<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://dme86.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://dme86.github.io/" rel="alternate" type="text/html" /><updated>2026-06-08T17:03:45+00:00</updated><id>https://dme86.github.io/feed.xml</id><title type="html">Daniel Meier</title><subtitle></subtitle><author><name>Dan &apos;dme&apos; Meier</name></author><entry><title type="html">AES‑256 Is Enough. Your Secrets Workflow Isn’t</title><link href="https://dme86.github.io/2026/06/08/AES-256-Is-Enough-Your-Secrets-Workflow-Isnt/" rel="alternate" type="text/html" title="AES‑256 Is Enough. Your Secrets Workflow Isn’t" /><published>2026-06-08T00:00:00+00:00</published><updated>2026-06-08T00:00:00+00:00</updated><id>https://dme86.github.io/2026/06/08/AES%E2%80%91256-Is-Enough-Your-Secrets-Workflow-Isnt</id><content type="html" xml:base="https://dme86.github.io/2026/06/08/AES-256-Is-Enough-Your-Secrets-Workflow-Isnt/"><![CDATA[<p>There is a strange little ritual in engineering teams.</p>

<p>Someone mentions encryption, someone else says “AES‑256,” and for a brief second the room relaxes. The magic number has been spoken. The vault door has appeared. The dragon is asleep.</p>

<p>Then the same team commits a decrypted <code class="language-plaintext highlighter-rouge">.env</code> file to Git.
Or stores an age private key in a shared password note.
Or lets CI print a production secret into a build log.
Or keeps the only decryption key on one developer laptop, guarded by vibes, hope, and an unpaid backup plan.</p>

<p>The uncomfortable truth is this:
AES‑256 is usually not the weak point.
Your workflow is.</p>

<!-- more -->

<h2 id="the-sops-and-age-use-case">The SOPS and age use case</h2>

<p>This becomes very real in modern DevOps and GitOps setups.</p>

<p>Tools like SOPS and age exist because teams want to keep configuration close to code without spraying plaintext secrets all over Git. SOPS is an editor for encrypted files and supports formats such as YAML, JSON, ENV, INI, and binary files. It can use backends such as age, PGP, AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, and OpenBao. SOPS keeps the structure of configuration files visible while encrypting values, and its own documentation says values are encrypted using AES‑256 in GCM mode. (<a href="https://getsops.io/">getsops.io</a>)</p>

<p>age is a modern file encryption tool and format with small explicit keys, UNIX-style composability, and support for recipient-based encryption. In other words: encrypt to one or more public recipients, decrypt with the corresponding private identity. (<a href="https://github.com/FiloSottile/age">github.com/FiloSottile/age</a>)</p>

<p>That is a very practical setup:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Git stores encrypted secrets.
Developers can review structure without seeing plaintext.
CI/CD decrypts only where needed.
Access is managed through explicit identities or KMS permissions.
</code></pre></div></div>

<p>That sounds sane.
And it can be sane.
But only if the surrounding workflow is sane too.</p>

<h2 id="aes256-itself-is-not-the-problem">AES‑256 itself is not the problem</h2>

<p>AES, the Advanced Encryption Standard, is a symmetric block cipher standardized by NIST. AES supports 128, 192, and 256-bit keys and encrypts data in 128-bit blocks. AES‑256 simply means AES with a 256-bit key. (<a href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf">NIST FIPS 197</a>)</p>

<p>A 256-bit key space contains:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2^256
</code></pre></div></div>

<p>possible keys.
That is about:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>116 quattuorvigintillion possible keys
</code></pre></div></div>

<p>A billion has 9 zeros.
A trillion has 12 zeros.
This number has 78 digits.</p>

<p>Written out, it is:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,936
</code></pre></div></div>

<p>At this scale, the exact name of the number almost stops helping. The point is simpler: there are so many possible AES‑256 keys that brute force is not an engineering plan. It is bedtime theatre for impatient supercomputers.</p>

<h2 id="a-classical-brute-force-attack-is-absurd">A classical brute-force attack is absurd</h2>

<p>Let’s pretend an attacker has a machine that can try:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>10^18 keys per second
</code></pre></div></div>

<p>That is one quintillion key attempts per second.
At that speed, searching the full AES‑256 key space would take roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>3.67 × 10^51 years
</code></pre></div></div>

<p>The universe is about:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1.38 × 10^10 years old
</code></pre></div></div>

<p>So this is not “a long time.”
This is “the heat death of your roadmap happened before the progress bar moved.”</p>

<h2 id="but-what-about-quantum-computers">But what about quantum computers?</h2>

<p>Quantum computers do change the discussion, but not in the way many headlines suggest.</p>

<p>For symmetric key search, <a href="https://en.wikipedia.org/wiki/Grover%27s_algorithm">Grover’s algorithm</a> can theoretically provide a quadratic speedup. Instead of searching through <code class="language-plaintext highlighter-rouge">N</code> possibilities, an idealized quantum search needs roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>√N
</code></pre></div></div>

<p>For a 256-bit key space:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>√(2^256) = 2^128
</code></pre></div></div>

<p>That is where the common statement comes from:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AES‑256 has roughly 128-bit security against idealized quantum brute force.
</code></pre></div></div>

<p>That sounds scary until you look at what <code class="language-plaintext highlighter-rouge">2^128</code> means:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>340,282,366,920,938,463,463,374,607,431,768,211,456
</code></pre></div></div>

<p>Still enormous.</p>

<p>NIST’s post-quantum FAQ is much calmer than the mythology. NIST says Grover’s algorithm gives a quadratic speedup <em>in theory</em>, but also notes that quantum hardware is likely to be expensive, that Grover is hard to parallelize efficiently, and that AES‑192 and AES‑256 are expected to remain safe for a very long time. (<a href="https://csrc.nist.gov/projects/post-quantum-cryptography/faqs">NIST Post-Quantum Cryptography FAQ</a>)</p>

<p>So no: a future quantum computer does not magically turn AES‑256 into wet cardboard.</p>

<h2 id="how-long-would-2128-attempts-take">How long would 2^128 attempts take?</h2>

<p>Assume an attacker somehow needs to perform <code class="language-plaintext highlighter-rouge">2^128</code> useful attempts.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">Attempts per second</th>
      <th style="text-align: right">Time needed for 2^128 attempts</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">10^9/s</code></td>
      <td style="text-align: right">about <code class="language-plaintext highlighter-rouge">1.08 × 10^22</code> years</td>
    </tr>
    <tr>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">10^12/s</code></td>
      <td style="text-align: right">about <code class="language-plaintext highlighter-rouge">1.08 × 10^19</code> years</td>
    </tr>
    <tr>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">10^18/s</code></td>
      <td style="text-align: right">about <code class="language-plaintext highlighter-rouge">1.08 × 10^13</code> years</td>
    </tr>
    <tr>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">10^24/s</code></td>
      <td style="text-align: right">about <code class="language-plaintext highlighter-rouge">10.8 million</code> years</td>
    </tr>
    <tr>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">10^30/s</code></td>
      <td style="text-align: right">about <code class="language-plaintext highlighter-rouge">10.8 years</code></td>
    </tr>
  </tbody>
</table>

<p>The last line looks scary.</p>

<p>But <code class="language-plaintext highlighter-rouge">10^30</code> useful cryptographic search steps per second is not “a large GPU cluster.”</p>

<p>It is not a few racks in a data center.
It is not even “someone at AWS got a very spicy invoice.”
It is <strong>fantasy</strong>-scale computing.</p>

<h2 id="compare-that-to-the-fastest-supercomputer">Compare that to the fastest supercomputer</h2>

<p>As a reality anchor, take El Capitan.</p>

<p>In the November 2025 TOP500 list, El Capitan was listed as the world’s fastest supercomputer, with an HPL benchmark result of <strong>1.809 exaflop/s</strong>, <strong>11.34 million cores</strong>, and a power draw of <strong>29,685 kW</strong>, roughly <strong>29.7 MW</strong>. (<a href="https://top500.org/lists/top500/2025/11/">TOP500 November 2025</a>)</p>

<p>Now let’s be outrageously generous.
Let’s pretend that:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1 floating-point operation = 1 useful AES key attempt
</code></pre></div></div>

<p>That is not how real AES brute force works, and it is especially not how quantum search works. But as a rough scale comparison, it is generous enough to help the intuition.</p>

<p>At El Capitan’s <code class="language-plaintext highlighter-rouge">1.809 × 10^18</code> operations per second, even the reduced quantum-style <code class="language-plaintext highlighter-rouge">2^128</code> search space would take roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>5.96 × 10^12 years
</code></pre></div></div>

<p>That is about:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>5.96 trillion years
</code></pre></div></div>

<p>So even after giving the attacker the quantum “128-bit effective” framing, and even after pretending the world’s fastest supercomputer is a perfect AES guessing machine, the answer is still trillions of years.</p>

<p>The machine is fast.
The number is ridiculous.</p>

<h2 id="what-would-1030-attempts-per-second-mean">What would 10^30 attempts per second mean?</h2>

<p>Now take the scary table entry:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>10^30 attempts per second
</code></pre></div></div>

<p>Compared to El Capitan:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>10^30 / 1.809 × 10^18 ≈ 552,800,000,000
</code></pre></div></div>

<p>So you would need roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>553 billion El Capitan-class systems
</code></pre></div></div>

<p>Again, this is a crude comparison. FLOPS are not AES attempts. Classical supercomputers are not quantum computers. But that actually makes the point stronger: even with a fantasy-friendly comparison, the scale is <em>deranged</em>.</p>

<p>Power consumption would be equally absurd.</p>

<p>One El Capitan-class system draws about:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>29.7 MW
</code></pre></div></div>

<p>Scale that to 553 billion systems:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>≈ 16,400,000 TW
</code></pre></div></div>

<p>That is:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>16.4 million terawatts
</code></pre></div></div>

<p>And if electricity cost only:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$0.10 per kWh
</code></pre></div></div>

<p>then running that fantasy machine would cost roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$1.64 quadrillion per hour
</code></pre></div></div>

<p>At:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$0.30 per kWh
</code></pre></div></div>

<p>it would be roughly:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$4.92 quadrillion per hour
</code></pre></div></div>

<p>That is not a data center.
That is not even an energy policy.
That is a planet trying to become a space heater.</p>

<h2 id="quantum-does-not-mean-free">Quantum does not mean free</h2>

<p>And the quantum version is not easier in practice.</p>

<p>You do not just replace 553 billion supercomputers with one glowing quantum cube and call it done.</p>

<p>A serious Grover-style attack against AES would require fault-tolerant quantum computing, logical qubits, quantum error correction, enormous gate depth, control hardware, cooling infrastructure, and a level of reliability that does not resemble today’s noisy quantum machines. Research on applying Grover’s algorithm to AES focuses exactly on these resource questions: qubits, circuit depth, gate counts, and the cost of implementing AES inside a quantum circuit. (<a href="https://arxiv.org/abs/1512.04965">arXiv:1512.04965</a>)</p>

<p>That is the gap between theory and practice.
Theory says:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Grover reduces exhaustive search from 2^256 to roughly 2^128.
</code></pre></div></div>

<p>Practice says:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Good luck building the machine, powering it, cooling it, error-correcting it, and running the full attack before civilization changes ticketing systems again.
</code></pre></div></div>

<h2 id="the-boring-attacks-are-the-real-attacks">The boring attacks are the real attacks</h2>

<p>If you use SOPS and age, the real risks are much less cinematic.
They look like this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A decrypted secrets file committed by accident.
An age private identity copied into Slack.
A CI job decrypting secrets for untrusted pull requests.
A debug command printing environment variables.
A KMS policy granting access too broadly.
A backup system storing plaintext copies.
An engineer leaving the company while still listed as a recipient.
A production secret living forever because nobody owns rotation.
</code></pre></div></div>

<p>None of these attacks break AES‑256.
They walk around it.
They steal the plaintext before encryption or after decryption.
That is the little goblin door in the castle wall.</p>

<h2 id="what-a-sane-sops--age-workflow-should-care-about">What a sane SOPS + age workflow should care about</h2>

<p>The important questions are operational:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Who can decrypt production secrets?
Where are private identities stored?
Are they backed up?
Are they encrypted at rest?
Can CI decrypt only on protected branches?
Can forked pull requests ever access plaintext secrets?
Are old recipients removed when people leave?
Are secrets rotated after exposure?
Do logs ever contain decrypted values?
Can you rebuild the system if one laptop dies?
Can you prove which key material protects which environment?
</code></pre></div></div>

<p>This is where the real engineering lives.</p>

<p>AES‑256 gives you a very strong locked box.</p>

<p>But someone still has to decide where the key goes, who can touch it, how it is rotated, how it is backed up, and how it is prevented from ending up in the worst possible chat thread at 17:48 on a Friday.</p>

<h2 id="the-quantum-panic-is-mostly-misplaced">The quantum panic is mostly misplaced</h2>

<p>Quantum computing is a serious field.</p>

<p>Post-quantum migration is serious too, especially for public-key cryptography such as RSA and elliptic-curve systems.
But symmetric encryption is not in the same panic category.</p>

<p>For AES, the practical message is much calmer:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AES‑256 is not the part you should be losing sleep over.
</code></pre></div></div>

<p>If your attacker can read your decrypted Kubernetes Secret from a build artifact, they do not need a quantum computer.</p>

<p>If your production <code class="language-plaintext highlighter-rouge">.env</code> file is sitting in someone’s Downloads folder, they do not need Grover’s algorithm.</p>

<p>If your age identity is copied into a wiki page, they do not need cryptanalysis.</p>

<p>They need search.</p>

<h2 id="the-real-takeaway">The real takeaway</h2>

<p>AES‑256 is enough.</p>

<p>The hard part is not making ciphertext strong.
The hard part is making plaintext rare.</p>

<p>A good secrets workflow should make decrypted secrets temporary, intentional, auditable, minimal, and boring.</p>

<p>SOPS and age can help with that. They are not magic. They are sharp tools. Used well, they let teams store encrypted secrets in Git without pretending Git is a vault. Used badly, they become one more ritual around a private key that everyone is too afraid to touch and nobody knows how to recover.</p>

<p>So yes:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AES‑256 is enough.
</code></pre></div></div>

<p>But that sentence is incomplete.</p>

<p>The better version is:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AES‑256 is enough.
Your secrets workflow has to be good enough too.
</code></pre></div></div>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Linux" /><category term="Security" /><summary type="html"><![CDATA[There is a strange little ritual in engineering teams. Someone mentions encryption, someone else says “AES‑256,” and for a brief second the room relaxes. The magic number has been spoken. The vault door has appeared. The dragon is asleep. Then the same team commits a decrypted .env file to Git. Or stores an age private key in a shared password note. Or lets CI print a production secret into a build log. Or keeps the only decryption key on one developer laptop, guarded by vibes, hope, and an unpaid backup plan. The uncomfortable truth is this: AES‑256 is usually not the weak point. Your workflow is.]]></summary></entry><entry><title type="html">Routing All macOS Traffic Through the Tor Network</title><link href="https://dme86.github.io/2024/11/22/Routing-All-macOS-Traffic-Through-the-Tor-Network/" rel="alternate" type="text/html" title="Routing All macOS Traffic Through the Tor Network" /><published>2024-11-22T00:00:00+00:00</published><updated>2024-11-22T00:00:00+00:00</updated><id>https://dme86.github.io/2024/11/22/Routing-All-macOS-Traffic-Through-the-Tor-Network</id><content type="html" xml:base="https://dme86.github.io/2024/11/22/Routing-All-macOS-Traffic-Through-the-Tor-Network/"><![CDATA[<p>For certain tasks, I need to use macOS and sometimes prefer to route all my traffic through the <a href="https://www.torproject.org/">Tor network</a>. In this tutorial, I will guide you through the process.</p>

<p>While you can download and use the Tor Browser for enhanced anonymity, I find that simply routing traffic through Tor’s network suffices for my needs while maintaining a civilized workflow.</p>

<!-- more -->

<h2 id="installation">Installation</h2>

<p>First, install Tor using Homebrew and start the Tor service:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>tor
brew services start tor
</code></pre></div></div>

<h2 id="configure-network-settings">Configure Network Settings</h2>

<p>Next, configure your network settings to use Tor as a SOCKS proxy:</p>

<ol>
  <li>Open <strong>System Preferences</strong>.</li>
  <li>Navigate to <strong>Network</strong>.</li>
  <li>Select your active network connection and click <strong>Advanced</strong>.</li>
  <li>Go to the <strong>Proxies</strong> tab.</li>
  <li>Check <strong>SOCKS Proxy</strong> and enter <code class="language-plaintext highlighter-rouge">localhost</code> as the server and <code class="language-plaintext highlighter-rouge">9050</code> as the port.</li>
</ol>

<h2 id="verify-tor-connection">Verify Tor Connection</h2>

<p>To ensure that your traffic is being routed through the Tor network, visit <a href="https://check.torproject.org/">Check Tor Project</a>.
You are able to use Onion-Links like: <a href="https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/">https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/</a></p>

<h2 id="managing-the-tor-service">Managing the Tor Service</h2>

<p>To restart Tor, use the following command:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew services restart tor
</code></pre></div></div>

<p>To stop Tor, use:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew services stop tor
</code></pre></div></div>

<p><strong>Note:</strong> After stopping Tor, remember to disable the SOCKS Proxy in your Network Settings to resume browsing without Tor.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[For certain tasks, I need to use macOS and sometimes prefer to route all my traffic through the Tor network. In this tutorial, I will guide you through the process. While you can download and use the Tor Browser for enhanced anonymity, I find that simply routing traffic through Tor’s network suffices for my needs while maintaining a civilized workflow.]]></summary></entry><entry><title type="html">The Philosophical Dichotomy Between macOS and Linux</title><link href="https://dme86.github.io/2024/10/27/The-Philosophical-Dichotomy-Between-macOS-and-Linux/" rel="alternate" type="text/html" title="The Philosophical Dichotomy Between macOS and Linux" /><published>2024-10-27T00:00:00+00:00</published><updated>2024-10-27T00:00:00+00:00</updated><id>https://dme86.github.io/2024/10/27/The-Philosophical-Dichotomy-Between-macOS-and-Linux</id><content type="html" xml:base="https://dme86.github.io/2024/10/27/The-Philosophical-Dichotomy-Between-macOS-and-Linux/"><![CDATA[<p>In the ongoing discourse surrounding operating systems, macOS and Linux occupy distinct philosophical and practical niches. Linux, with its open-source ethos, exemplifies adaptability and scalability. It operates seamlessly across commodity hardware, supports a diverse array of CPU architectures, and scales <em>up</em> to the formidable demands of supercomputing environments while also <em>scaling down</em> to function efficiently on cost-effective single-board computers (SBCs).</p>

<!-- more -->

<p>A cornerstone of Linux’s versatility lies in its sophisticated resource and security controls, which facilitate the implementation of containers. Containers have become indispensable in large-scale production networks, enabling efficient deployment and management of applications. In contrast, macOS lacks native container support. While solutions like Docker Desktop attempt to bridge this gap, they inherently rely on running a Linux virtual machine to emulate the necessary controls. This dependency underscores a fundamental divergence: Apple’s strategic focus does not prioritize macOS as a server platform, a domain increasingly embraced by competitors such as Windows, which now robustly supports containerization. Consequently, macOS remains the predominant mainstream operating system devoid of native container capabilities.</p>

<p>From a workstation perspective, macOS excels in delivering a polished and user-friendly environment, catering effectively to a broad spectrum of professional and creative tasks. However, the functionalities that Linux affords beyond the capabilities of macOS typically pertain to systems of considerable scale or minimalism - domains where flexibility and customization are paramount.</p>

<p>Personal usability further delineates these platforms. My experience with the macOS desktop environment often involved navigating a cluttered interface with multiple overlapping windows, making the retrieval of specific applications or settings cumbersome. In contrast, major Linux desktop environments such as <a href="https://www.gnome.org/">GNOME</a>, <a href="https://kde.org/">KDE</a>, and <a href="https://www.xfce.org/">XFCE</a>, though perhaps less refined in aesthetics, offer a more streamlined and unobtrusive user experience. Their design philosophy prioritizes functionality and user autonomy, allowing for greater customization and efficiency, albeit occasionally at the expense of visual smoothness.</p>

<h2 id="philosophical-underpinnings-open-source-vs-proprietary-paradigms">Philosophical Underpinnings: Open Source vs. Proprietary Paradigms</h2>

<p>The philosophical divergence between Linux and macOS extends beyond mere functionality to the very principles underpinning their development and distribution. Linux, as an open-source operating system, embodies the ideals of transparency, collaboration, and communal ownership. Its development model encourages a decentralized approach where contributions from a global community of developers drive continuous innovation and improvement. This openness fosters an environment where users are not merely consumers but active participants in the evolution of the software they utilize.</p>

<p>In stark contrast, macOS operates within a proprietary framework, controlled and curated by Apple Inc. This model emphasizes a tightly integrated ecosystem where hardware and software are meticulously designed to work in harmony, ensuring a consistent and optimized user experience. While this approach guarantees reliability and polish, it inherently limits user autonomy and restricts the ability to modify or extend the system beyond the parameters set by Apple.</p>

<p>This dichotomy raises profound questions about control, freedom, and the nature of technological progress. Linux’s open-source nature advocates for a democratized approach to computing, where knowledge and tools are freely accessible, promoting innovation through collective effort. Conversely, macOS’s proprietary stance underscores a vision of seamless integration and user-centric design, prioritizing quality and ease of use over customization and flexibility.</p>

<h2 id="the-role-of-community-and-ecosystem">The Role of Community and Ecosystem</h2>

<p>The communities surrounding Linux and macOS further illustrate their philosophical differences. The Linux ecosystem thrives on a diverse array of distributions, each tailored to specific needs and preferences, from the user-friendly Ubuntu and Fedora to the highly customizable Arch Linux and Gentoo. This plurality fosters a rich environment of experimentation and specialization, enabling users to select or even create a system that aligns precisely with their requirements.</p>

<p>macOS, while benefiting from a robust and dedicated user base, offers a more homogenized ecosystem. Apple’s stringent control over its software and hardware ensures a uniform experience but limits the breadth of customization and the proliferation of alternative configurations. This controlled environment can be advantageous for users who prioritize stability and support, yet it may be restrictive for those seeking to push the boundaries of their system’s capabilities.</p>

<h2 id="ethical-considerations-and-digital-sovereignty">Ethical Considerations and Digital Sovereignty</h2>

<p>Ethical considerations also play a role in the philosophical debate between macOS and Linux. The open-source movement, represented by Linux, champions digital sovereignty—the idea that individuals and communities should have control over their digital environments without reliance on proprietary entities. This perspective aligns with broader ethical principles of autonomy, privacy, and resistance to monopolistic practices.</p>

<p>On the other hand, macOS’s proprietary model places trust in a single entity to safeguard user data and system integrity. While Apple has built a reputation for strong security and privacy measures, this centralization also means that users must depend on Apple for updates, support, and the longevity of their systems. This reliance can be seen as a trade-off between the assurance of professional stewardship and the empowerment of individual or communal control.</p>

<h2 id="the-aesthetic-and-experiential-dimension">The Aesthetic and Experiential Dimension</h2>

<p>Beyond the technical and philosophical aspects, the aesthetic and experiential dimensions of macOS and Linux contribute to their distinct identities. macOS is renowned for its sleek design, intuitive interfaces, and cohesive visual language. This emphasis on aesthetics is not merely superficial; it reflects a deeper philosophical commitment to creating environments that inspire and facilitate creativity and productivity through beauty and simplicity.</p>

<p>Linux, while sometimes perceived as utilitarian in comparison, offers a canvas of customization that appeals to users who derive satisfaction from tailoring their environments to their exact specifications. The ability to modify everything from the window manager to the underlying system processes aligns with a philosophy that values individual expression and technical mastery.</p>

<h2 id="navigating-the-philosophical-landscape">Navigating the Philosophical Landscape</h2>

<p>Ultimately, the choice between macOS and Linux is not merely a technical decision but a philosophical alignment with different visions of computing. macOS represents a philosophy of curated excellence, where user experience and seamless integration are paramount. It appeals to those who seek a reliable, aesthetically pleasing, and user-friendly environment with minimal need for customization.</p>

<p>Linux, conversely, embodies a philosophy of openness, flexibility, and communal collaboration. It attracts users who value control, customization, and the ability to engage deeply with their operating system’s inner workings. For academics, researchers, and technologists who thrive on tinkering and optimizing their computational environments, Linux offers unparalleled advantages.</p>

<p>In the context of informatics and philosophy, this dichotomy also reflects broader themes of individualism versus collectivism, control versus freedom, and the balance between structure and flexibility. As technology continues to evolve, the philosophical discourse surrounding operating systems like macOS and Linux will remain a vital area of exploration, shedding light on how our digital tools shape and are shaped by our values and aspirations.</p>

<p>If the decision between these systems prompts contemplation, it is likely that Linux may not align with your current workflow demands. However, for those inclined towards tinkering and optimizing their computational environment, Linux remains a powerful and adaptable platform. Conversely, if macOS meets your needs without eliciting a desire for deeper system engagement, it stands as a testament to the success of proprietary, user-centric design. Embracing either system involves aligning with its underlying philosophy, thereby influencing not only how you interact with technology but also how you conceptualize and engage with the broader digital landscape.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Linux" /><category term="macOS" /><summary type="html"><![CDATA[In the ongoing discourse surrounding operating systems, macOS and Linux occupy distinct philosophical and practical niches. Linux, with its open-source ethos, exemplifies adaptability and scalability. It operates seamlessly across commodity hardware, supports a diverse array of CPU architectures, and scales up to the formidable demands of supercomputing environments while also scaling down to function efficiently on cost-effective single-board computers (SBCs).]]></summary></entry><entry><title type="html">Go as a Backend for AI Applications: A Performance Case Study</title><link href="https://dme86.github.io/2024/10/20/Go-vs-Python-for-AI-Model-Serving-A-Performance-Comparison/" rel="alternate" type="text/html" title="Go as a Backend for AI Applications: A Performance Case Study" /><published>2024-10-20T00:00:00+00:00</published><updated>2024-10-20T00:00:00+00:00</updated><id>https://dme86.github.io/2024/10/20/Go-vs-Python-for-AI-Model-Serving:-A-Performance-Comparison</id><content type="html" xml:base="https://dme86.github.io/2024/10/20/Go-vs-Python-for-AI-Model-Serving-A-Performance-Comparison/"><![CDATA[<p>When developing AI applications in Python, leveraging Go for model serving in the backend can offer significant performance advantages. While Python excels in machine learning model development with its vast ecosystem, Go’s efficiency makes it an ideal choice for serving those models in production.</p>

<!-- more -->

<p>We conducted a benchmark comparison using <strong><a href="https://formulae.brew.sh/formula/hey">hey</a></strong> to demonstrate Go’s superiority in high-performance backend operations. By deploying identical machine learning models using both Python and Go, we measured their response times and throughput.</p>

<h3 id="why-python-for-ai-development">Why Python for AI Development?</h3>

<p>Python is the dominant language for AI development due to its rich libraries, like TensorFlow and <a href="https://scikit-learn.org/">scikit-learn</a>, which simplify model training and experimentation. Its extensive ecosystem and simple syntax make rapid development easy, especially for data scientists who need flexibility and easy-to-read code.</p>

<p>However, Python’s interpreted nature results in slower execution and higher memory consumption compared to Go. This becomes especially noticeable when scaling an application to handle many requests, such as in a model-serving scenario.</p>

<h3 id="why-go-for-model-serving">Why Go for Model Serving?</h3>

<p>Go’s strengths lie in its speed, concurrency, and memory efficiency. It’s compiled and optimized for handling many requests at once, making it a powerful choice for production-level model serving. For applications that need to serve ML predictions to thousands of users, Go is an excellent fit due to its lower latency and better scalability.</p>

<h4 id="simple-example-serving-ai-models">Simple Example: Serving AI Models</h4>

<p>Let’s take a simple machine learning example where we train a model using Python and serve it using both Python and Go. We’ll then compare their performance.</p>

<h5 id="python-api-flask">Python API (Flask)</h5>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>

<span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">route</span><span class="p">(</span><span class="s">'/predict'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">():</span>
    <span class="c1"># Simple prediction simulation
</span>    <span class="k">return</span> <span class="s">"Prediction: Iris-Setosa"</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
    <span class="n">app</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">5000</span><span class="p">)</span>

</code></pre></div></div>

<h5 id="go-api">Go API</h5>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
    <span class="s">"fmt"</span>
    <span class="s">"log"</span>
    <span class="s">"net/http"</span>
<span class="p">)</span>

<span class="k">func</span> <span class="n">predictHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Prediction: Iris-Setosa"</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/predict"</span><span class="p">,</span> <span class="n">predictHandler</span><span class="p">)</span>
    <span class="n">log</span><span class="o">.</span><span class="n">Fatal</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">))</span>
<span class="p">}</span>

</code></pre></div></div>

<h4 id="benchmarking-with-hey">Benchmarking with <strong>Hey</strong></h4>

<p>To compare both APIs, use <strong><a href="https://formulae.brew.sh/formula/hey">hey</a></strong> for benchmarking. Here’s how you can run the tests:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For Python API</span>
hey <span class="nt">-n</span> 1000 <span class="nt">-c</span> 10 http://localhost:5000/predict
<span class="c"># For Go API</span>
hey <span class="nt">-n</span> 1000 <span class="nt">-c</span> 10 http://localhost:8080/predict
</code></pre></div></div>

<h3 id="benchmarking-go-vs-python-for-model-serving">Benchmarking: Go vs. Python for Model Serving</h3>

<p>In our tests, Go handled more requests per second (34,172 vs. Python’s 24,795) and had lower average response times. These results clearly show Go’s efficiency in handling concurrent requests, making it ideal for production model serving in AI applications.</p>

<ul>
  <li>
    <p><strong>Python</strong></p>

    <ul>
      <li>Requests per second: 24,795</li>
      <li>Average response time: 0.0004 secs</li>
      <li>Slowest response: 0.0107 secs</li>
    </ul>
  </li>
  <li>
    <p><strong>Go</strong></p>

    <ul>
      <li>Requests per second: 34,172</li>
      <li>Average response time: 0.0003 secs</li>
      <li>Slowest response: 0.0075 secs</li>
    </ul>
  </li>
</ul>

<p>As these numbers show, Go outperforms Python in terms of both requests per second and response times. In high-concurrency environments, the ability to handle thousands of requests with minimal latency is critical, and Go’s concurrent processing model makes it a clear winner for the backend. The improvement in throughput (<strong>over 30%</strong> more requests per second) highlights Go’s advantage when scaling applications.</p>

<h3 id="conclusion">Conclusion</h3>

<p>While Python remains the best language for AI development due to its powerful libraries, Go outperforms it in production environments for serving machine learning models. Using Go for model serving can lead to faster response times and higher scalability, making it a compelling choice for backend operations in AI-powered applications.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[When developing AI applications in Python, leveraging Go for model serving in the backend can offer significant performance advantages. While Python excels in machine learning model development with its vast ecosystem, Go’s efficiency makes it an ideal choice for serving those models in production.]]></summary></entry><entry><title type="html">Simple Load Balancer Tutorial with k3d</title><link href="https://dme86.github.io/2024/10/16/Simple-Load-Balancer-Tutorial-with-k3d/" rel="alternate" type="text/html" title="Simple Load Balancer Tutorial with k3d" /><published>2024-10-16T00:00:00+00:00</published><updated>2024-10-16T00:00:00+00:00</updated><id>https://dme86.github.io/2024/10/16/Simple-Load-Balancer-Tutorial-with-k3d</id><content type="html" xml:base="https://dme86.github.io/2024/10/16/Simple-Load-Balancer-Tutorial-with-k3d/"><![CDATA[<p>In this brief tutorial, we’ll walk through how to deploy a simple load-balanced application using k3d, a lightweight Kubernetes distribution. This guide will help you set up port mappings and create a basic deployment in just a few minutes.</p>

<!-- more -->

<p>Currently, I’m working at an AI startup, where we’re building our core infrastructure around Kubernetes. For local development, I’ve chosen k3d due to its lightweight setup, ease of use, and speed, making it ideal for rapid experimentation and testing.</p>

<h2 id="step-1-reset-k3d">Step 1: Reset k3d</h2>

<p>Before we start, let’s ensure that there are no existing k3d clusters running. This will help us start with a clean slate.</p>

<p>To reset k3d and remove all clusters, run the following command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>k3d cluster delete -a
</code></pre></div></div>

<p>This command deletes all active k3d clusters so you can proceed without any conflicts.</p>

<h2 id="step-2-start-the-cluster-with-port-mappings">Step 2: Start the Cluster with Port Mappings</h2>

<p>Now, let’s create a k3d cluster with one control plane and three worker nodes. We’ll map port <strong>8080</strong> on the <em>host</em> to port <strong>80</strong> <em>inside</em> the cluster. This allows us to expose our services externally:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>k3d cluster create mycluster -s 1 -a 3 --port "8080:80@loadbalancer"
</code></pre></div></div>
<p>This command creates a cluster with load balancing enabled, mapping traffic from port 8080 on your local machine to port 80 within the cluster.</p>

<h2 id="step-3-deployment-and-service">Step 3: Deployment and Service</h2>

<p>Next, we’ll deploy a simple Nginx service. First, create a deployment of three Nginx containers:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">apps/v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">nginx-deployment</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">replicas</span><span class="pi">:</span> <span class="m">3</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">matchLabels</span><span class="pi">:</span>
      <span class="na">app</span><span class="pi">:</span> <span class="s">nginx</span>
  <span class="na">template</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
      <span class="na">labels</span><span class="pi">:</span>
        <span class="na">app</span><span class="pi">:</span> <span class="s">nginx</span>
    <span class="na">spec</span><span class="pi">:</span>
      <span class="na">containers</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">nginx</span>
        <span class="na">image</span><span class="pi">:</span> <span class="s">nginx:latest</span>
        <span class="na">ports</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">containerPort</span><span class="pi">:</span> <span class="m">80</span>

</code></pre></div></div>
<p>Then, define a service to expose the deployment within the cluster:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">apiVersion</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">kind</span><span class="pi">:</span> <span class="s">Service</span>
<span class="na">metadata</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">nginx-service</span>
<span class="na">spec</span><span class="pi">:</span>
  <span class="na">selector</span><span class="pi">:</span>
    <span class="na">app</span><span class="pi">:</span> <span class="s">nginx</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">port</span><span class="pi">:</span> <span class="m">80</span>
      <span class="na">targetPort</span><span class="pi">:</span> <span class="m">80</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">LoadBalancer</span>
</code></pre></div></div>
<p>Apply these resources to the cluster:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kubectl apply <span class="nt">-f</span> nginx-deployment.yaml
kubectl apply <span class="nt">-f</span> nginx-service.yaml
</code></pre></div></div>

<h2 id="step-4-verifying-the-deployment">Step 4: Verifying the Deployment</h2>

<p>Once the deployment is created, you can use <code class="language-plaintext highlighter-rouge">k9s</code> to monitor the status of your pods and services.</p>

<p>Navigate to <code class="language-plaintext highlighter-rouge">:deployments</code> to see the live logs from the <code class="language-plaintext highlighter-rouge">nginx-deployment</code>. You can also switch to <code class="language-plaintext highlighter-rouge">:pods</code> to observe the individual Nginx pods. If you terminate one of the pods, Kubernetes will automatically respawn it, ensuring no downtime, thanks to the ReplicaSet.</p>

<p>you can also curl the service from your local machine:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl localhost:8080
</code></pre></div></div>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[In this brief tutorial, we’ll walk through how to deploy a simple load-balanced application using k3d, a lightweight Kubernetes distribution. This guide will help you set up port mappings and create a basic deployment in just a few minutes.]]></summary></entry><entry><title type="html">Why i switched from cd to zoxide</title><link href="https://dme86.github.io/2024/06/14/Why-I-switched-from-cd-to-zoxide/" rel="alternate" type="text/html" title="Why i switched from cd to zoxide" /><published>2024-06-14T00:00:00+00:00</published><updated>2024-06-14T00:00:00+00:00</updated><id>https://dme86.github.io/2024/06/14/Why-I-switched-from-cd-to-zoxide</id><content type="html" xml:base="https://dme86.github.io/2024/06/14/Why-I-switched-from-cd-to-zoxide/"><![CDATA[<p>This is a rather short article, but it highlights a small change with a big impact. I will briefly discuss why I switched from ‘cd’ to ‘zoxide’ and why you might want to consider it as well.</p>

<!-- more -->

<p>‘cd’ is a command you probably use every day hundreds of times. Maybe you also have some sort of autocompletion for your shell because it’s faster and more convenient.</p>

<p>Well, I installed zoxide, along with a <a href="https://github.com/kidonng/zoxide.fish">plugin for the fish shell</a>, and after setting the alias “<strong>alias cd=z</strong>”, I basically replaced every “<strong>cd</strong>” with “<strong>z</strong>”.</p>

<p>This enables me, for example, to type “<strong>cd -</strong>” and navigate to the previous directory every time.
Also, after a while, zoxide will learn your frequently used paths, so you don’t have to type “<strong>cd ~/.config/nvim</strong>” anymore — a simple “<strong>cd nvim</strong>” is enough, and the same goes for your project folders.</p>

<p>So just check out <a href="https://github.com/ajeetdsouza/zoxide">zoxide on GitHub</a> to learn how to install and configure your shell with this great tool, improving your speed and convenience even further.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[This is a rather short article, but it highlights a small change with a big impact. I will briefly discuss why I switched from ‘cd’ to ‘zoxide’ and why you might want to consider it as well.]]></summary></entry><entry><title type="html">Why I Continue To Advocate For Centos Stream In Production Environments</title><link href="https://dme86.github.io/2024/03/05/Why-I-Continue-to-Advocate-for-CentOS-Stream-in-Production-Environments/" rel="alternate" type="text/html" title="Why I Continue To Advocate For Centos Stream In Production Environments" /><published>2024-03-05T00:00:00+00:00</published><updated>2024-03-05T00:00:00+00:00</updated><id>https://dme86.github.io/2024/03/05/Why-I-Continue-to-Advocate-for-CentOS-Stream-in-Production-Environments</id><content type="html" xml:base="https://dme86.github.io/2024/03/05/Why-I-Continue-to-Advocate-for-CentOS-Stream-in-Production-Environments/"><![CDATA[<p>A few years ago, there was considerable discussion surrounding Red Hat’s transition of CentOS, which, according to insights shared by “industry experts” on platforms such as Reddit, was perceived as a shift towards an unstable development-oriented rolling-release model.
It is possible that you encountered similar information and, perhaps, acted upon the advice of professionals who expressed their opinions online.</p>

<p>This narrative reflects the state of CentOS prior to the aforementioned transformation:</p>

<!-- more -->

<div class="mermaid">
graph LR
classDef sub opacity:0
classDef note fill:#7bf, stroke:#ccb
A{Fedora}
A --&gt;|Enterprise Stabilization| C{RHEL}
C --&gt; D{CentOS}
    subgraph subC [" "]
        C
        noteC[Stable]
    end
class subA,subB,subC sub
class noteA,noteB,noteC note
</div>

<p>Previously, CentOS operated as a community-driven initiative that involved retrieving all the source RPMs from Red Hat Enterprise Linux (RHEL) and crafting a functional distribution from them. The sole alterations were the removal of Red Hat’s branding, adhering to legal stipulations.
Essentially, CentOS Linux closely mirrored RHEL, differing only in the absence of proprietary branding, and it did not incorporate its own fixes, modifications, or patches.</p>

<p>What has transformed, aside from the nomenclature shift to “Stream,” is this:</p>

<div class="mermaid">
graph LR
classDef sub opacity:0
classDef note fill:#7bf, stroke:#ccb
A{Fedora}
A --&gt;|Enterprise Stabilization| C{CentOS}
C --&gt; D{RHEL}
    subgraph subC [" "]
        C
        noteC[Stable]
    end
class subA,subB,subC sub
class noteA,noteB,noteC note
</div>

<blockquote>
  <p>CentOS Stream now occupies the position formerly held by RHEL.
Therefore, unless one perceived RHEL as unstable, there is no basis to
assume that CentOS Stream will exhibit instability.</p>
</blockquote>

<p>The designation of CentOS Stream as a rolling release prompted some discontent among users. It is important to note that a traditional rolling release does not inherently imply instability; rather, it involves meticulous testing of packages by maintainers.
The distinguishing feature is the potential for significant version jumps in installed packages, leading to notable changes in program behavior.</p>

<p>In the case of CentOS Stream, the alteration primarily involves the elimination of point releases. Instead of transitioning from, for instance, CentOS 7 to 7.1, users receive regular updates.
As these updates remain within the same major release, they do not introduce disruptive changes. This framework contrasts with classic rolling releases such as Arch or Gentoo, which lack version numbers.</p>

<p>For those familiar with Debian Stable and the -updates repository, the concept is analogous.</p>

<h1 id="conclusion">Conclusion</h1>

<p>RHEL, characterized as a stable LTS distribution, follows a <a href="https://access.redhat.com/support/policy/updates/errata">release schedule</a> spanning 3 years, complemented by a support period lasting a decade.
Beyond this, minor releases concurrent with a major RHEL release persist for up to 2 years, providing a consistent <a href="https://en.wikipedia.org/wiki/Application_binary_interface">ABI</a> guarantee that outlines supported interfaces.
This assurance equips developers with precise knowledge about interface stability throughout the 10-year duration.</p>

<p>In comparison, CentOS Stream <em>maintains its status</em> as a stable LTS distribution, featuring a release cadence occurring every 3 years and a support lifespan of 5 years.
Aligning with RHEL, CentOS Stream offers an equivalent ABI guarantee.</p>

<p>Traditionally, CentOS adhered to the same cadence and lifespan as the corresponding RHEL release, <em>excluding</em> the extended minor release duration.
This distinction is crucial, as CentOS’s stability lagged behind RHEL due to users lacking the option to remain on a minor release for 2 years while still receiving security updates.</p>

<blockquote>
  <p>This nuance might not be fully grasped by individuals unfamiliar with
RHEL, including many Reddit users, encompassing a significant portion
of the CentOS community on the platform.</p>
</blockquote>

<p>CentOS Stream, while sharing a stability level with CentOS, does not fall short of CentOS’s stability; it is <em>equally</em> robust.
Both CentOS and CentOS Stream provide the <em>same</em> ABI guarantee and function as a unified major release channel.</p>

<p>For example CentOS Stream 9 was released September 15, 2021 and will have <em>active Support</em> until May 31 2027.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Linux" /><category term="CentOS" /><summary type="html"><![CDATA[A few years ago, there was considerable discussion surrounding Red Hat’s transition of CentOS, which, according to insights shared by “industry experts” on platforms such as Reddit, was perceived as a shift towards an unstable development-oriented rolling-release model. It is possible that you encountered similar information and, perhaps, acted upon the advice of professionals who expressed their opinions online. This narrative reflects the state of CentOS prior to the aforementioned transformation:]]></summary></entry><entry><title type="html">Gentoo goes Binary</title><link href="https://dme86.github.io/2024/01/18/Gentoo-Goes-Binary/" rel="alternate" type="text/html" title="Gentoo goes Binary" /><published>2024-01-18T00:00:00+00:00</published><updated>2024-01-18T00:00:00+00:00</updated><id>https://dme86.github.io/2024/01/18/Gentoo-Goes-Binary</id><content type="html" xml:base="https://dme86.github.io/2024/01/18/Gentoo-Goes-Binary/"><![CDATA[<p>I was genuinely excited as I read the latest Gentoo news regarding their commitment to <a href="https://www.gentoo.org/news/2023/12/29/Gentoo-binary.html">providing more binary packages</a> for Gentoo stable.</p>

<p>Gentoo is often referred to as <strong>the</strong> non-binary distribution, where everything must be compiled from source code. For me, this aspect has always been Gentoo’s greatest strength and, simultaneously, its most significant weakness. Despite being a fervent Gentoo fan, I find myself resorting to <a href="https://archlinux.org/">Arch</a> in certain environments because, I must admit, compile times on Gentoo, especially on older hardware, can be quite painful.</p>

<p>This is precisely why Gentoo is now expanding its offering of binary packages on their (mirror) servers. While, for most architectures, this is limited to the core system and weekly updates, it’s a different story for <strong>amd64 and arm64</strong>. There, they boast an impressive <strong>&gt;20 GByte of packages</strong> on their mirrors, ranging from LibreOffice to KDE Plasma and from Gnome to Docker. Gentoo stable is updated daily!</p>

<!-- more -->

<p>Despite the newfound convenience, you still retain the flexibility of Gentoo’s USE flags. However, if you find yourself running Gentoo on older hardware or simply wish to avoid lengthy builds, such as with qtwebengine, you have the option to expedite the installation process using binaries on a base system. Later, you can switch back to a non-binary installation, although the installation process with binaries is considerably faster, as illustrated in the screenshot I captured during a fresh installation using <a href="https://wiki.gentoo.org/wiki/Emerge">emerge</a>, which predominantly utilized binary packages:
<img src="https://i.imgur.com/QtjKALZ.png" alt="enter image description here" /></p>

<blockquote>
  <p>I’m using a <a href="https://github.com/dme86/dwm">modded version of dwm</a> as my windowmanager and <a href="https://github.com/dme86/st">st</a> as my terminal emulator.</p>
</blockquote>

<p>The only modifications I made in this fresh installation were to edit the contents of this new file here:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/portage/binrepos.conf/gentoobinhost.conf
</code></pre></div></div>

<p>So that the priority is <strong>9999</strong> and to ensure I’m utilizing the nearest mirror:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[gentoobinhost]
priority = 9999
sync-uri = https://mirror.netcologne.de/gentoo/releases/amd64/binpackages/17.1/x86-64/
</code></pre></div></div>

<p>Also, <strong>make.conf</strong> should have the following entry to enforce verification of GPG signatures:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FEATURES="${FEATURES} binpkg-request-signature"
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">emerge -avuDUg @world</code> will now handle the rest.</p>

<p>If you wish to install a package like <a href="https://github.com/dme86/neovim">neovim</a> using emerge, you can do so by employing the “-g” parameter alongside the emerge command to install neovim from the binaries:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>emerge -g --ask neovim
</code></pre></div></div>

<p>If you desire to set the “-g” parameter as the default for your system, modify your make.conf file to ensure that <a href="https://wiki.gentoo.org/wiki/EMERGE_DEFAULT_OPTS/en">EMERGE_DEFAULT_OPTS</a> reflects your preferred default settings:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EMERGE_DEFAULT_OPTS="-g"
</code></pre></div></div>

<h1 id="installation-in-an-virtual-environment">Installation in an virtual environment</h1>

<p>If I have to set up a virtual machine, I typically do so using <a href="https://www.qemu.org/">qemu</a>. For me, this is the most versatile and lightweight way to spin up virtual machines.</p>

<p>First, I created a qemu image of 15GB:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-img create -f qcow2 gentoo.qcow2 15g
</code></pre></div></div>

<p>For this machine, I created this simple shell startup file:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    qemu-system-x86_64 <span class="se">\</span>
      <span class="nt">-m</span> 2G <span class="se">\</span>
      <span class="nt">-vga</span> virtio <span class="se">\</span>
      <span class="nt">-display</span> default,show-cursor<span class="o">=</span>on <span class="se">\</span>
      <span class="nt">-usb</span> <span class="se">\</span>
      <span class="nt">-device</span> usb-tablet <span class="se">\</span>
      <span class="nt">-smp</span> 2 <span class="se">\</span>
      <span class="nt">-cdrom</span> install.iso <span class="nt">-boot</span> <span class="nv">menu</span><span class="o">=</span>on <span class="se">\</span>
      <span class="nt">-drive</span> <span class="nv">file</span><span class="o">=</span>gentoo.qcow2,if<span class="o">=</span>virtio <span class="se">\</span>
      <span class="nt">-device</span> e1000,netdev<span class="o">=</span>net0 <span class="se">\</span>
      <span class="nt">-netdev</span> user,id<span class="o">=</span>net0,hostfwd<span class="o">=</span>tcp::2222-:22  <span class="se">\</span>
      <span class="nt">-cpu</span> Nehalem
</code></pre></div></div>

<p>and made it executable via <code class="language-plaintext highlighter-rouge">chmod +x start.sh</code>.</p>

<p>Now, I downloaded the latest <a href="https://www.gentoo.org/downloads/">minimal install image from Gentoo</a> and started the VM via <code class="language-plaintext highlighter-rouge">./start.sh</code>.</p>

<p>After the machine was booted up, I started the SSH daemon, assigned a password to root, and was able to SSH into it from a proper <a href="https://github.com/dme86/st">terminal emulator</a>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/init.d/sshd start
passwd root
</code></pre></div></div>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh <span class="nt">-p</span> 2222 root@localhost
</code></pre></div></div>

<h1 id="gentoo">Gentoo</h1>

<p>I did the usual steps for installing Gentoo without any frills. If you don’t have any idea of what you are doing, please <a href="https://wiki.gentoo.org/wiki/Handbook:AMD64/en">read the Gentoo Handbook</a>. It’s awesome.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>livecd /etc/portage/binrepos.conf <span class="c"># lsblk</span>
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
fd0     2:0    1     4K  0 disk
loop0   7:0    0 424.5M  1 loop /mnt/livecd
sr0    11:0    1 466.7M  0 rom  /mnt/cdrom
vda   252:0    0    15G  0 disk
zram0 253:0    0     0B  0 disk
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>livecd /etc/portage/binrepos.conf <span class="c"># parted /dev/vda</span>
GNU Parted 3.6
Using /dev/vda
Welcome to GNU Parted! Type <span class="s1">'help'</span> to view a list of commands.
<span class="o">(</span>parted<span class="o">)</span> mklabel gpt
<span class="o">(</span>parted<span class="o">)</span> mkpart primary ext4 1MiB 100%
<span class="o">(</span>parted<span class="o">)</span> <span class="nb">set </span>1 boot on
<span class="o">(</span>parted<span class="o">)</span> quit
Information: You may need to update /etc/fstab.
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>livecd /etc/portage/binrepos.conf <span class="c"># blkid /dev/vda1</span>
/dev/vda1: <span class="nv">UUID</span><span class="o">=</span><span class="s2">"2e7bc77b-40ff-46c2-8d13-3f34cf03742a"</span> <span class="nv">BLOCK_SIZE</span><span class="o">=</span><span class="s2">"4096"</span> <span class="nv">TYPE</span><span class="o">=</span><span class="s2">"ext4"</span> <span class="nv">PARTLABEL</span><span class="o">=</span><span class="s2">"primary"</span> <span class="nv">PARTUUID</span><span class="o">=</span><span class="s2">"e28d6e8d-bb87-427e-818b-198d60e23ddb"</span>
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>livecd /etc/portage/binrepos.conf <span class="c"># mount /dev/vda1 /mnt/gentoo/</span>
livecd /etc/portage/binrepos.conf <span class="c"># cd /mnt/gentoo/</span>
livecd /mnt/gentoo <span class="c"># ls</span>
lost+found
livecd /mnt/gentoo <span class="c"># wget https://distfiles.gentoo.org/releases/amd64/autobuilds/20240114T164819Z/stage3-amd64-systemd-mergedusr-20240114T164819Z.tar.xz</span>
<span class="nt">--2024-01-18</span> 13:45:33--  https://distfiles.gentoo.org/releases/amd64/autobuilds/20240114T164819Z/stage3-amd64-systemd-mergedusr-20240114T164819Z.tar.xz
Resolving distfiles.gentoo.org... 195.181.170.18, 212.102.56.182, 195.181.175.15, ...
Connecting to distfiles.gentoo.org|195.181.170.18|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 309232792 <span class="o">(</span>295M<span class="o">)</span> <span class="o">[</span>application/x-xz]
Saving to: ‘stage3-amd64-systemd-mergedusr-20240114T164819Z.tar.xz’

stage3-amd64-systemd-mergedusr-20240114T164819Z 100%[<span class="o">======================================================================================================&gt;]</span> 294.91M  11.1MB/s    <span class="k">in </span>29s

2024-01-18 13:46:03 <span class="o">(</span>10.3 MB/s<span class="o">)</span> - ‘stage3-amd64-systemd-mergedusr-20240114T164819Z.tar.xz’ saved <span class="o">[</span>309232792/309232792]

livecd /mnt/gentoo <span class="c"># tar xpvf stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner</span>
</code></pre></div></div>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Linux" /><category term="Gentoo" /><summary type="html"><![CDATA[I was genuinely excited as I read the latest Gentoo news regarding their commitment to providing more binary packages for Gentoo stable. Gentoo is often referred to as the non-binary distribution, where everything must be compiled from source code. For me, this aspect has always been Gentoo’s greatest strength and, simultaneously, its most significant weakness. Despite being a fervent Gentoo fan, I find myself resorting to Arch in certain environments because, I must admit, compile times on Gentoo, especially on older hardware, can be quite painful. This is precisely why Gentoo is now expanding its offering of binary packages on their (mirror) servers. While, for most architectures, this is limited to the core system and weekly updates, it’s a different story for amd64 and arm64. There, they boast an impressive &gt;20 GByte of packages on their mirrors, ranging from LibreOffice to KDE Plasma and from Gnome to Docker. Gentoo stable is updated daily!]]></summary></entry><entry><title type="html">Gitea - A Small and Scaleable DevOps Platform - From Your Homelab to Enterprise</title><link href="https://dme86.github.io/2024/01/17/gitea-a-small-and-scaleable-DevOps-Platform-from-your-Homelab-to-Enterprise/" rel="alternate" type="text/html" title="Gitea - A Small and Scaleable DevOps Platform - From Your Homelab to Enterprise" /><published>2024-01-17T00:00:00+00:00</published><updated>2024-01-17T00:00:00+00:00</updated><id>https://dme86.github.io/2024/01/17/gitea-a-small-and-scaleable-DevOps-Platform-from-your-Homelab-to-Enterprise</id><content type="html" xml:base="https://dme86.github.io/2024/01/17/gitea-a-small-and-scaleable-DevOps-Platform-from-your-Homelab-to-Enterprise/"><![CDATA[<p>What I appreciate in software is when it scales efficiently. I dislike overstretched goals and under-delivering on value.</p>

<p>In recent years, GitLab, for example, made numerous promises about features but struggled to deliver on many occasions. Notably, they still lack support for ARM64 (See <a href="https://gitlab.com/groups/gitlab-org/-/epics/2370">Epic</a>).</p>

<p>Moreover, in most cases, I’ve observed that companies don’t necessarily need an exhaustive feature set like GitLab’s. What they often require is CI/CD, <a href="https://docs.gitea.com/usage/automatically-linked-references">Issues</a>, package management, <a href="https://docs.renovatebot.com/modules/platform/gitea/">Renovate</a> or Webhooks, in addition to User Management.</p>

<p>With Gitea, I get all of this - and more. I can also run it on a Raspberry Pi or configure it for replication on larger machines.</p>

<p>In this article, I’ll show you how I installed a simple Gitea test instance on a small server (1 CPU, 1GB RAM) and hosted a runner for CI/CD actions. All of this was set up in <strong>~1h</strong>. For demonstration purposes, I did not dive into TLS or backup topics, and OAuth2 is not included.</p>

<!-- more -->

<h1 id="installation">Installation</h1>

<p>I followed the <a href="https://docs.gitea.com/installation/install-from-binary">official documentation</a> from Gitea and was able to access it on port 3000 within a few minutes. (You can also choose to run it in Kubernetes, install it via Docker, etc.)
<img src="https://i.imgur.com/LF2RupW.png" alt="enter image description here" /></p>

<p>For simplicity and a lightweight installation, I chose an <a href="https://www.sqlite.org/">SQLite3</a> Database.</p>

<p>The first user will be granted admin rights. The installation only took a few seconds, and the dashboard was displayed:
<img src="https://i.imgur.com/Nx3hZiB.png" alt="enter image description here" /></p>

<p>I added my public SSH key to my user profile and made sure my <code class="language-plaintext highlighter-rouge">~/.ssh/config</code> was configured to represent the new server, like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Host IP/HOST
    User git
    Hostname IP/HOST
    PreferredAuthentications publickey
IdentityFile ~/.ssh/me.daniel.meier
</code></pre></div></div>

<p>I then added a new organization, and within it, a new repository. As you can see, there are numerous options available, including the ability to use a template for our repository, for example:
<img src="https://i.imgur.com/HzQVzqW.png" alt="enter image description here" />
<img src="https://i.imgur.com/9of0imS.png" alt="enter image description here" />
<img src="https://i.imgur.com/sxjjrgg.png" alt="enter image description here" /></p>

<p>With the repository in place, my public key added, and my <code class="language-plaintext highlighter-rouge">~/.ssh/config</code> configured, I was now able to follow the steps to make the first commit:
<img src="https://i.imgur.com/UyxGe9p.png" alt="enter image description here" /></p>

<p>And in the dashboard, everything was displayed as well—perfect!
<img src="https://i.imgur.com/t8PVicv.png" alt="enter image description here" /></p>

<h1 id="runner-cicd">Runner (CI/CD)</h1>

<p>Starting a runner for CI/CD processes is extremely simple. For demonstration purposes, just follow the steps outlined in the <a href="https://docs.gitea.com/usage/actions/act-runner">documentation</a>.
After enabling the actions in the repo settings, I registered my demo runner as a global runner:
<img src="https://i.imgur.com/lBdDXeZ.png" alt="enter image description here" />
<img src="https://i.imgur.com/R36xWOd.png" alt="enter image description here" /></p>

<p>Inside my repository, I created the following file:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.gitea/workflows/demo.yaml
</code></pre></div></div>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s">Gitea Actions Demo</span>
<span class="na">run-name</span><span class="pi">:</span> <span class="s">$ is testing out Gitea Actions 🚀</span>
<span class="na">on</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">push</span><span class="pi">]</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">Explore-Gitea-Actions</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "🎉 The job was automatically triggered by a $ event."</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "🐧 This job is now running on a $ server hosted by Gitea!"</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "🔎 The name of your branch is $ and your repository is $."</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Check out repository code</span>
        <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v3</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "💡 The $ repository has been cloned to the runner."</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "🖥️ The workflow is now ready to test your code on the runner."</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">List files in the repository</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">ls $</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">echo "🍏 This job's status is $."</span>
</code></pre></div></div>

<p>As my code was pushed to the repository, I checked the runner’s output in my terminal:
<img src="https://i.imgur.com/d77wmzE.png" alt="enter image description here" /></p>

<p>And the process was visible from the repository as well:
<img src="https://i.imgur.com/ZaEZltF.png" alt="enter image description here" />
<img src="https://i.imgur.com/lNoW8rb.png" alt="enter image description here" />
<img src="https://i.imgur.com/U1UR78C.png" alt="enter image description here" />
<img src="https://i.imgur.com/nJlvsAw.png" alt="enter image description here" /></p>

<h1 id="enterprise">Enterprise</h1>

<p>To run such a setup in an enterprise scenario, I would recommend ensuring a robust backup strategy (testing regularly is crucial) and staying vigilant about version updates. Additionally, always implement TLS, for instance, with an Nginx reverse proxy, and maintain control over user management through <a href="https://docs.gitea.com/development/oauth2-provider">OAuth2</a>. Keep a close eye on right-sizing your server to optimize costs.</p>

<h1 id="conclusion">Conclusion</h1>

<p>I’ve only scratched the surface here, but it should give you a glimpse of what is possible with Gitea.
It offers many more features needed on a daily basis, such as <a href="https://docs.gitea.com/usage/automatically-linked-references">linking references or closing an issue via commit or PR</a>. Please <a href="https://docs.gitea.com/">refer to their documentation</a> for more information.</p>

<p>IT is changing permanently, but one thing has stayed the same over all the years working in this field, and that is the emphasis on reducing costs. If you have commitments to licenses, such as with GitLab or Slack, it can be challenging to reduce them, and often, you end up paying (a lot!) for features you don’t need.</p>

<p>For me, Gitea is a simple yet powerful and highly scalable solution. Easy to maintain and with no licensing costs, it provides a cost-efficient way to grow with it.</p>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[What I appreciate in software is when it scales efficiently. I dislike overstretched goals and under-delivering on value. In recent years, GitLab, for example, made numerous promises about features but struggled to deliver on many occasions. Notably, they still lack support for ARM64 (See Epic). Moreover, in most cases, I’ve observed that companies don’t necessarily need an exhaustive feature set like GitLab’s. What they often require is CI/CD, Issues, package management, Renovate or Webhooks, in addition to User Management. With Gitea, I get all of this - and more. I can also run it on a Raspberry Pi or configure it for replication on larger machines. In this article, I’ll show you how I installed a simple Gitea test instance on a small server (1 CPU, 1GB RAM) and hosted a runner for CI/CD actions. All of this was set up in ~1h. For demonstration purposes, I did not dive into TLS or backup topics, and OAuth2 is not included.]]></summary></entry><entry><title type="html">k9s Tutorial</title><link href="https://dme86.github.io/2024/01/16/k9s-tutorial/" rel="alternate" type="text/html" title="k9s Tutorial" /><published>2024-01-16T00:00:00+00:00</published><updated>2024-01-16T00:00:00+00:00</updated><id>https://dme86.github.io/2024/01/16/k9s-tutorial</id><content type="html" xml:base="https://dme86.github.io/2024/01/16/k9s-tutorial/"><![CDATA[<p>I am excited to introduce an article about k9s, a powerful tool designed for efficient management of kubernetes clusters, whether it be on platforms like EKS or k3s. This tool has significantly enhanced my productivity, allowing me to navigate kubernetes environments, manage pods, and swiftly identify issues with remarkable speed.</p>

<!-- more -->

<p>The speed and efficiency derived from not relying on your mouse for interactions with k9s is remarkable. By solely utilizing your keyboard, you develop muscle memory, resulting in a faster workflow compared to other programs.</p>

<p>I have been using k9s for several years, and I firmly believe it is the most efficient solution for managing and maintaining Kubernetes clusters. I trust it so much that I regularly use it for version upgrades, and it has never let me down.</p>

<p>Upon opening k9s for the first time, you should expect to receive an overview like this:
<img src="https://i.imgur.com/x5irRPq.png" alt="enter image description here" /></p>

<p>As you might be familiar with from vim commands, navigation in k9s allows you to move up and down using <code class="language-plaintext highlighter-rouge">j</code> and <code class="language-plaintext highlighter-rouge">k</code>. Press <code class="language-plaintext highlighter-rouge">Enter</code> to select your kubernetes context.</p>

<p>Upon doing so, it will display a comprehensive list of all your pods:
<img src="https://i.imgur.com/0mKgBN3.png" alt="enter image description here" /></p>

<p>In the top right corner, you’ll consistently find a list of available commands, extending beyond the fundamental ones. In the pod-view, for instance, you can open a shell with <code class="language-plaintext highlighter-rouge">s</code>, view the pod logs using <code class="language-plaintext highlighter-rouge">l</code>, or edit the YAML file associated with the pod through <code class="language-plaintext highlighter-rouge">e</code>.</p>

<p>Here’s a glimpse into the log-view of my demo-pod:
<img src="https://i.imgur.com/rucaWyP.png" alt="enter image description here" /></p>

<p>You might have observed that the menu in the top right has been altered; it now provides options for toggling features such as Autoscroll, FullScreen, etc. while inside the log-view:
<img src="https://i.imgur.com/Jicq8Tu.png" alt="enter image description here" /></p>

<p>No matter where you are in the menu, you can always return to the previous screen by pressing <code class="language-plaintext highlighter-rouge">ESC</code>.</p>

<p>I recommend getting acquainted with the search command, which follows the same pattern as vim: <code class="language-plaintext highlighter-rouge">/</code>. Pressing <code class="language-plaintext highlighter-rouge">/</code> will bring up a search box, facilitating quick searches for namespaces, pods, and more.</p>

<p>Switching between Kubernetes services is straightforward. First, obtain an overview by pressing <code class="language-plaintext highlighter-rouge">Ctrl+a</code>:
<img src="https://i.imgur.com/86BXNra.png" alt="enter image description here" /></p>

<p>As demonstrated, I entered <code class="language-plaintext highlighter-rouge">/</code> in the aliases overview and typed <code class="language-plaintext highlighter-rouge">con</code>, displaying all search results for <code class="language-plaintext highlighter-rouge">con</code> in all aliases.</p>

<p>After a few hours, you’ll likely identify the most essential services, enabling you to switch between them rapidly. Simply press the vim-command <code class="language-plaintext highlighter-rouge">:</code> and enter the name or shortcut you wish to switch to, like <code class="language-plaintext highlighter-rouge">pod</code> (shortcut <code class="language-plaintext highlighter-rouge">po</code>) or <code class="language-plaintext highlighter-rouge">namespace</code> (shortcut <code class="language-plaintext highlighter-rouge">ns</code>).</p>

<p>Remember, you can always look up all aliases via <code class="language-plaintext highlighter-rouge">Ctrl+a</code>, and if ever in doubt, press <code class="language-plaintext highlighter-rouge">?</code> to access the general help page.</p>

<p>With this knowledge, while entering command mode and typing a resource name or alias, navigating through frequently used resources could become cumbersome.
Allow me to introduce: HotKeys!</p>

<p>You can customize your own HotKeys on a global scale:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$XDG_CONFIG_HOME/k9s/hotkeys.yaml
</code></pre></div></div>

<p>You have the flexibility to define HotKeys on both a global <strong>and</strong> context-specific or cluster-specific level:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$XDG_DATA_HOME/k9s/clusters/clusterX/contextY/hotkeys.yaml
</code></pre></div></div>

<p>Your HotKeys will also be visible on the help page <code class="language-plaintext highlighter-rouge">?</code>.</p>

<p>Example hotkeys.yaml:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">hotKeys</span><span class="pi">:</span>
  <span class="c1"># Hitting Shift-0 navigates to your pod view</span>
  <span class="na">shift-0</span><span class="pi">:</span>
    <span class="na">shortCut</span><span class="pi">:</span>    <span class="s">Shift-0</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Viewing pods</span>
    <span class="na">command</span><span class="pi">:</span>     <span class="s">pods</span>
  <span class="c1"># Hitting Shift-1 navigates to your deployments</span>
  <span class="na">shift-1</span><span class="pi">:</span>
    <span class="na">shortCut</span><span class="pi">:</span>    <span class="s">Shift-1</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">View deployments</span>
    <span class="na">command</span><span class="pi">:</span>     <span class="s">dp</span>
  <span class="c1"># Hitting Shift-2 navigates to your xray deployments</span>
  <span class="na">shift-2</span><span class="pi">:</span>
    <span class="na">shortCut</span><span class="pi">:</span>    <span class="s">Shift-2</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Xray Deployments</span>
    <span class="na">command</span><span class="pi">:</span>     <span class="s">xray deploy</span>
  <span class="c1"># Hitting Ctrl-U view the resources in the namespace of your current selection</span>
  <span class="na">ctrl-u</span><span class="pi">:</span>
    <span class="na">shortCut</span><span class="pi">:</span>    <span class="s">Ctrl-U</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Namespaced resources</span>
    <span class="na">command</span><span class="pi">:</span>     <span class="s2">"</span><span class="s">$RESOURCE_NAME</span><span class="nv"> </span><span class="s">$NAMESPACE"</span>
    <span class="na">keepHistory</span><span class="pi">:</span> <span class="no">true</span> <span class="c1"># whether you can return to the previous view</span>
</code></pre></div></div>]]></content><author><name>Dan &apos;dme&apos; Meier</name></author><category term="Tutorials" /><summary type="html"><![CDATA[I am excited to introduce an article about k9s, a powerful tool designed for efficient management of kubernetes clusters, whether it be on platforms like EKS or k3s. This tool has significantly enhanced my productivity, allowing me to navigate kubernetes environments, manage pods, and swiftly identify issues with remarkable speed.]]></summary></entry></feed>