<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DevOps Archives - Linuxcent</title>
	<atom:link href="https://linuxcent.com/tag/devops/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxcent.com/tag/devops/</link>
	<description>Infrastructure security, from the kernel up.</description>
	<lastBuildDate>Fri, 10 Jul 2026 15:36:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxcent.com/wp-content/uploads/2026/04/favicon-512x512-1-150x150.png</url>
	<title>DevOps Archives - Linuxcent</title>
	<link>https://linuxcent.com/tag/devops/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">211632295</site>	<item>
		<title>Minikube: Local Kubernetes Done Right — and Where It Breaks Down</title>
		<link>https://linuxcent.com/minikube-local-kubernetes/</link>
					<comments>https://linuxcent.com/minikube-local-kubernetes/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 02:00:00 +0000</pubDate>
				<category><![CDATA[Kubernetes Ecosystem]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Local Development]]></category>
		<category><![CDATA[Minikube]]></category>
		<guid isPermaLink="false">https://linuxcent.com/?p=2240</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>See what Minikube actually virtualizes for local Kubernetes — and the exact resource and networking limits that push teams toward something else.</p>
<p>The post <a href="https://linuxcent.com/minikube-local-kubernetes/">Minikube: Local Kubernetes Done Right — and Where It Breaks Down</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><em>Kubernetes Ecosystem: From User to Contributor, Episode 2</em><br />
<a href="/microk8s-edge-kubernetes/">← EP01: MicroK8s Explained</a> · <strong>EP02: Minikube</strong> · <a href="/k3s-vs-microk8s-vs-minikube/">EP03: k3s vs MicroK8s vs Minikube →</a></p>
<p><strong>11 min read</strong></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>What is Minikube? A tool that runs a single-node Kubernetes cluster inside a VM or a container on your local machine — the oldest and most widely adopted &#8220;local Kubernetes&#8221; tool in the ecosystem</li>
<li>Unlike MicroK8s&#8217;s bare-metal snap install, Minikube&#8217;s default drivers isolate the cluster inside a VM (VirtualBox, HyperKit, Hyper-V, KVM2) or a Docker container — a deliberate isolation trade-off, not an accident</li>
<li><code class="" data-line="">minikube addons</code>, <code class="" data-line="">minikube profile</code>, and multi-node support let you run several named clusters side by side, each with its own driver and Kubernetes version</li>
<li><code class="" data-line="">LoadBalancer</code> services don&#8217;t resolve to anything real on their own — <code class="" data-line="">minikube tunnel</code> or <code class="" data-line="">minikube service</code> are required, and this trips up almost everyone the first time</li>
<li>The VM overhead that makes Minikube heavier than MicroK8s is also what makes it a more faithful stand-in for a real cloud node, particularly for testing kernel-adjacent behavior</li>
<li>Contribution opportunity: feature parity across Minikube&#8217;s own driver list is uneven, and closing specific gaps there is a well-scoped, achievable contribution</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">MICROK8S: BARE-METAL SNAP                   MINIKUBE: ISOLATED VM/CONTAINER
──────────────────────────                   ──────────────────────────────
Host OS
  └── microk8s snap                         Host OS
        ├── kubelet                           └── Driver (VirtualBox / KVM2 /
        ├── kube-apiserver                        HyperKit / Docker / Podman)
        ├── containerd                              └── VM or container
        └── Dqlite                                        ├── kubelet
                                                            ├── kube-apiserver
No VM boundary — cluster                                   ├── etcd
runs directly on the host                                  └── containerd
kernel and network stack
                                              Full isolation boundary between
                                              cluster and host — closer to how
                                              a real cloud node actually looks
</code></pre>
<p>What is Minikube? It&#8217;s the tool that popularized &#8220;just run a Kubernetes cluster on your laptop&#8221; — a single command that provisions a VM or container, installs a full Kubernetes control plane and node inside it, and hands you a working <code class="" data-line="">kubectl</code> context. The isolation boundary that VM makes MicroK8s&#8217;s bare-metal install avoid is the entire point: Minikube trades startup speed and resource overhead for a cluster that behaves more like a real, separate node — the same control-plane/node split covered in detail in <a href="https://linuxcent.com/kubernetes-history-borg-legacy/">this site&#8217;s Kubernetes history series</a>, just shrunk down to fit on a laptop.</p>
<hr />
<h2 id="the-driver-model-how-minikube-actually-runs-your-cluster">The Driver Model: How Minikube Actually Runs Your Cluster</h2>
<p>Minikube doesn&#8217;t run Kubernetes directly on your host. It provisions a driver-specific environment first, then runs Kubernetes inside that:</p>
<pre><code class="" data-line="">$ minikube start --driver=docker
&#x1f604;  minikube v1.32.0 on Darwin 14.2
&#x2728;  Using the docker driver based on user configuration
&#x1f44d;  Starting control plane node minikube in cluster minikube
&#x1f69c;  Pulling base image ...
&#x1f525;  Creating docker container (CPUs=2, Memory=4000MB) ...
&#x1f433;  Preparing Kubernetes v1.28.3 on Docker 24.0.7 ...
&#x1f50e;  Verifying Kubernetes components...
&#x1f31f;  Enabled addons: default-storageclass, storage-provisioner
&#x1f3c4;  Done! kubectl is now configured to use &quot;minikube&quot; cluster

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
</code></pre>
<p>The <code class="" data-line="">--driver</code> flag is the real decision point. <code class="" data-line="">docker</code>/<code class="" data-line="">podman</code> drivers run the cluster as a container, which is fast to start but shares the host kernel — you don&#8217;t get true kernel-level isolation. <code class="" data-line="">virtualbox</code>/<code class="" data-line="">hyperkit</code>/<code class="" data-line="">kvm2</code>/<code class="" data-line="">hyperv</code> drivers run a full VM, which is slower to start (30–90 seconds, versus 10–20 for the container driver) but gives the cluster its own kernel, its own network namespace, and behavior much closer to an actual cloud instance.</p>
<hr />
<h2 id="addons-and-profiles-minikubes-answer-to-multi-environment-testing">Addons and Profiles: Minikube&#8217;s Answer to Multi-Environment Testing</h2>
<pre><code class="" data-line="">$ minikube addons list
|-----------------------------|----------|--------------|
| ADDON NAME                  | PROFILE  | STATUS       |
|-----------------------------|----------|--------------|
| ingress                     | minikube | disabled     |
| metrics-server              | minikube | disabled     |
| dashboard                   | minikube | disabled     |
| registry                    | minikube | disabled     |

$ minikube addons enable ingress
&#x1f50e;  Verifying ingress addon...
&#x1f31f;  The &#039;ingress&#039; addon is enabled

# Run a second, independent cluster on a different Kubernetes version
$ minikube start -p old-version --kubernetes-version=v1.26.0
$ minikube profile list
|----------|-----------|---------|--------------|------|
| Profile  | VM Driver | Runtime | IP           | Ver  |
|----------|-----------|---------|--------------|------|
| minikube | docker    | docker  | 192.168.49.2 | v1.28.3 |
| old-version | docker | docker  | 192.168.58.2 | v1.26.0 |
</code></pre>
<p>Profiles are Minikube&#8217;s way of running multiple, fully independent clusters side by side — useful for testing an upgrade path or comparing behavior across Kubernetes versions without tearing anything down. MicroK8s has no equivalent to this; it&#8217;s a genuine Minikube differentiator, not just a different flavor of the same feature.</p>
<hr />
<h2 id="where-the-vm-overhead-actually-shows-up">Where the VM Overhead Actually Shows Up</h2>
<p>The isolation Minikube provides isn&#8217;t free, and it shows up in three concrete places: startup time (a VM driver cold-start is measured in tens of seconds, not the few seconds a bare-metal snap install takes), memory floor (a VM needs to reserve memory for its own kernel and init system before Kubernetes gets any of it), and CI runners specifically — many hosted CI environments (GitHub Actions&#8217; standard runners, for example) don&#8217;t support nested virtualization, which rules out VM drivers entirely and forces the <code class="" data-line="">docker</code> driver, quietly giving up the isolation benefit that was the reason to pick Minikube over MicroK8s in the first place.</p>
<hr />
<h2 id="networking-quirks-loadbalancer-services-and-minikube-tunnel">Networking Quirks: LoadBalancer Services and <code class="" data-line="">minikube tunnel</code></h2>
<p>This is the single most common point of confusion for anyone coming from a real cloud cluster:</p>
<pre><code class="" data-line="">$ kubectl expose deployment web --type=LoadBalancer --port=80
service/web exposed

$ kubectl get svc web
NAME   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)
web    LoadBalancer   10.96.34.201   &lt;pending&gt;     80:31234/TCP
#                                    ^^^^^^^^^ stays pending forever —
#                                    there&#039;s no cloud load balancer to provision one
</code></pre>
<p>Minikube has no cloud provider to actually satisfy a <code class="" data-line="">LoadBalancer</code> request. Two ways to actually reach the service:</p>
<pre><code class="" data-line=""># Option 1: minikube tunnel — creates a real route to LoadBalancer services,
# must stay running in a foreground terminal the whole time
$ minikube tunnel
&#x2705;  Tunnel successfully started

# Option 2: minikube service — opens the service in a browser via NodePort,
# no LoadBalancer semantics, but doesn&#039;t require a background process
$ minikube service web --url
http://192.168.49.2:31234
</code></pre>
<p><code class="" data-line="">minikube tunnel</code> is the closer match to real <code class="" data-line="">LoadBalancer</code> behavior, but it&#8217;s a foreground process that silently stops working if the terminal closes or the machine sleeps — a frequent source of &#8220;it worked five minutes ago&#8221; confusion.</p>
<hr />
<h2 id="production-gotchas"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Production Gotchas</h2>
<p><strong>Nested virtualization isn&#8217;t available everywhere.</strong> Many hosted CI runners and some cloud dev environments don&#8217;t expose the CPU virtualization extensions Minikube&#8217;s VM drivers need — you&#8217;ll get a driver failure that looks like a Minikube bug but is actually a host capability gap. Falling back to <code class="" data-line="">--driver=docker</code> works, but changes the isolation guarantees you were relying on.</p>
<p><strong>The docker driver shares your host&#8217;s Docker daemon resource limits.</strong> If your host Docker Desktop is capped at 4GB, that&#8217;s a hard ceiling for everything running inside the Minikube container too — VM drivers get their own explicit memory allocation instead.</p>
<p><strong><code class="" data-line="">minikube tunnel</code> dying silently is the most common &#8220;why can&#8217;t I reach my LoadBalancer&#8221; support question.</strong> It doesn&#8217;t reliably surface a clear error when it stops — check <code class="" data-line="">minikube tunnel</code>&#8216;s own terminal output before assuming the Kubernetes side is broken.</p>
<p><strong>Addon behavior differs meaningfully by driver.</strong> The <code class="" data-line="">ingress</code> addon&#8217;s interaction with host networking is different between a VM driver (which gets its own IP on a virtual network) and the docker driver (which shares the host&#8217;s Docker network) — a setup that works on one driver doesn&#8217;t automatically work identically on another.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<pre><code class="" data-line="">minikube start --driver=&lt;docker|virtualbox|hyperkit|kvm2|hyperv&gt;
minikube status                    # cluster health
minikube addons list                # available and enabled add-ons
minikube addons enable &lt;name&gt;       # enable one
minikube profile list               # all named clusters
minikube start -p &lt;name&gt;            # start/create a named profile
minikube tunnel                     # real LoadBalancer routing (foreground)
minikube service &lt;name&gt; --url       # NodePort-based access, no LB semantics
minikube delete -p &lt;name&gt;           # tear down a specific profile
minikube ssh                        # shell into the cluster&#039;s VM/container
</code></pre>
<hr />
<h2 id="contribution-opportunity-closing-minikubes-driver-feature-parity-gaps">Contribution Opportunity: Closing Minikube&#8217;s Driver Feature-Parity Gaps</h2>
<p><strong>The limitation:</strong> Minikube supports over a dozen drivers (docker, podman, virtualbox, hyperkit, kvm2, hyperv, vfkit, qemu, and more), and features don&#8217;t land on all of them at the same time or with the same fidelity. GPU passthrough, specific CNI plugin support, and certain addon behaviors work reliably on some drivers and only partially — or not at all — on others. A user picking a driver based on their OS often has no easy way to know upfront which features they&#8217;re implicitly giving up.</p>
<p><strong>Why it&#8217;s hard to fix:</strong> Each driver wraps a fundamentally different underlying technology (a type-2 hypervisor, a container runtime, a different hypervisor API per OS), so a feature that&#8217;s straightforward on one driver can require an entirely separate implementation path on another — this isn&#8217;t a matter of one team finishing a checklist, it&#8217;s N different integration surfaces that each need their own maintainer attention, and Minikube&#8217;s driver maintainers are a much smaller, more fragmented group than the core Kubernetes maintainers.</p>
<p><strong>What a contribution-shaped fix looks like:</strong> The achievable starting point isn&#8217;t &#8220;add GPU support to every driver&#8221; — it&#8217;s picking one specific, well-documented gap (say, a particular addon&#8217;s known behavior difference on <code class="" data-line="">hyperv</code> versus <code class="" data-line="">kvm2</code>), reproducing it precisely, and either fixing the driver-specific code path in <code class="" data-line="">kubernetes/minikube</code> or, just as valuably, contributing a clear compatibility matrix to the project&#8217;s docs so the next person doesn&#8217;t discover the gap by trial and error. Minikube&#8217;s own GitHub issues are full of exactly these driver-specific reports sitting unresolved for lack of someone who reproduces and narrows them down.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Minikube isolates the cluster inside a VM or container, trading startup speed and resource overhead for isolation closer to a real cloud node</li>
<li>Profiles let you run multiple independent, differently-versioned clusters side by side — a genuine capability MicroK8s doesn&#8217;t have</li>
<li><code class="" data-line="">LoadBalancer</code> services need <code class="" data-line="">minikube tunnel</code> or <code class="" data-line="">minikube service</code> — there&#8217;s no cloud provider underneath to satisfy the request automatically</li>
<li>Driver choice has real consequences: VM drivers need nested virtualization support that not every host or CI runner provides, and feature parity across drivers is uneven</li>
<li>The clearest contribution opportunity is narrowing and documenting (or fixing) specific driver feature-parity gaps — achievable without deep hypervisor expertise</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>EP01 and EP02 covered MicroK8s and Minikube individually. EP03 puts them head-to-head against k3s — the third major lightweight Kubernetes option — on the criteria that actually matter when picking one: resource footprint, HA story, and how much you&#8217;re willing to trade control for convenience.</p>
<p><em>Next: <a href="/k3s-vs-microk8s-vs-minikube/">EP03 — k3s vs MicroK8s vs Minikube: Which Lightweight Kubernetes Fits Your Use Case</a></em></p>
<p>Get EP03 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&amp;linkname=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fminikube-local-kubernetes%2F&#038;title=Minikube%3A%20Local%20Kubernetes%20Done%20Right%20%E2%80%94%20and%20Where%20It%20Breaks%20Down" data-a2a-url="https://linuxcent.com/minikube-local-kubernetes/" data-a2a-title="Minikube: Local Kubernetes Done Right — and Where It Breaks Down"></a></p><p>The post <a href="https://linuxcent.com/minikube-local-kubernetes/">Minikube: Local Kubernetes Done Right — and Where It Breaks Down</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/minikube-local-kubernetes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2240</post-id>	</item>
		<item>
		<title>MicroK8s Explained: The Single-Binary Kubernetes for Edge and IoT</title>
		<link>https://linuxcent.com/microk8s-edge-kubernetes/</link>
					<comments>https://linuxcent.com/microk8s-edge-kubernetes/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Sat, 11 Jul 2026 02:00:00 +0000</pubDate>
				<category><![CDATA[Kubernetes Ecosystem]]></category>
		<category><![CDATA[Canonical]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Edge Computing]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[MicroK8s]]></category>
		<category><![CDATA[Snap]]></category>
		<guid isPermaLink="false">https://linuxcent.com/?p=2237</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>See how MicroK8s packages a full Kubernetes cluster into one snap-installed binary — and exactly which production controls that simplicity trades away.</p>
<p>The post <a href="https://linuxcent.com/microk8s-edge-kubernetes/">MicroK8s Explained: The Single-Binary Kubernetes for Edge and IoT</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<p><em>Kubernetes Ecosystem: From User to Contributor, Episode 1</em><br />
<a href="/kubernetes-history-borg-legacy/">← Kubernetes: From Borg to Platform Engineering</a> · <strong>EP01: MicroK8s Explained</strong> · <a href="/kubernetes-ecosystem-series/">All Kubernetes Ecosystem Episodes →</a></p>
<p><strong>11 min read</strong></p>
<hr />
<h2 id="tldr">TL;DR</h2>
<ul>
<li>What is MicroK8s? A full, CNCF-conformant Kubernetes cluster packaged into a single snap package — install and have a running cluster in under 60 seconds, no separate container runtime or CNI install required</li>
<li>Built by Canonical for edge, IoT, and ephemeral CI clusters, where minimal footprint and single-command lifecycle matter more than fine-grained tuning</li>
<li>Add-ons (<code class="" data-line="">dns</code>, <code class="" data-line="">storage</code>, <code class="" data-line="">ingress</code>, <code class="" data-line="">metallb</code>, <code class="" data-line="">cilium</code>, <code class="" data-line="">gpu</code>) replace what you&#8217;d otherwise hand-install and wire together yourself</li>
<li>High-availability mode uses <strong>Dqlite</strong> (a distributed, Raft-backed SQLite) instead of etcd — a deliberate design choice with a real operational trade-off</li>
<li>The same &#8220;just works&#8221; install model that makes MicroK8s fast to stand up also hides some of the control-plane tuning knobs production operators expect from etcd</li>
<li>Contribution opportunity: Dqlite&#8217;s operational tooling is years behind etcd&#8217;s — a real, specific, achievable gap, covered in depth below</li>
</ul>
<hr />
<h2 id="the-big-picture">The Big Picture</h2>
<pre><code class="" data-line="">TRADITIONAL KUBERNETES INSTALL              MICROK8S INSTALL
─────────────────────────────               ──────────────────
Install a container runtime                 $ sudo snap install microk8s --classic
Install kubelet, kubeadm, kubectl            $ microk8s status --wait-ready
Stand up and configure etcd
kubeadm init, join workers                          │
Install a CNI plugin                                ▼
Install an ingress controller                One snap install =
Install a storage provisioner                kubelet + kube-apiserver + kube-scheduler
Wire it all together, hope                   + kube-controller-manager + containerd
the versions are compatible                  + Dqlite + CNI (via add-on)
                                              — one running cluster, one command
</code></pre>
<p>What is MicroK8s? It&#8217;s Canonical&#8217;s single-binary distribution that packages an entire Kubernetes control plane and node into one snap package, so <code class="" data-line="">snap install microk8s</code> produces a running, CNCF-conformant cluster without a separate container runtime, etcd install, or CNI setup step. The trade for that speed is control: the same bundling that removes a dozen manual steps also removes a dozen places you&#8217;d normally tune something.</p>
<hr />
<h2 id="how-microk8s-fits-an-entire-cluster-into-one-snap">How MicroK8s Fits an Entire Cluster Into One Snap</h2>
<p>A snap package is a self-contained, confined Linux application bundle — MicroK8s ships its own containerd, its own CNI defaults, and its own datastore inside that bundle, rather than expecting the host to provide them.</p>
<pre><code class="" data-line="">$ sudo snap install microk8s --classic
microk8s (1.29/stable) v1.29.1 from Canonical✓ installed

$ microk8s status --wait-ready
microk8s is running
high-availability: no
  datastore master nodes: 127.0.0.1:19001
  datastore standby nodes: none
addons:
  enabled:
    ha-cluster            # always on — this is the Dqlite HA layer, even for a single node
  disabled:
    dns                   # ← you enable what you need, nothing runs by default beyond core
    ingress
    storage
    ...
</code></pre>
<p><code class="" data-line="">--classic</code> confinement is required because MicroK8s needs broader host access than a strictly-confined snap allows — it manages network interfaces, iptables/nftables rules, and mounts. This is the first place production operators coming from a bare-metal <code class="" data-line="">kubeadm</code> install get surprised: MicroK8s&#8217;s snap confinement model means some host interactions happen through paths a traditional install never touches, and debugging network issues sometimes means understanding snap&#8217;s confinement boundaries, not just Kubernetes networking.</p>
<hr />
<h2 id="the-add-on-model-how-microk8s-replaces-a-day-of-cluster-bootstrapping">The Add-on Model: How MicroK8s Replaces a Day of Cluster Bootstrapping</h2>
<p>Everything beyond the bare control plane is an add-on, enabled with one command:</p>
<pre><code class="" data-line="">$ microk8s enable dns storage ingress
Infer repository core for addon dns
Enabling DNS
...
DNS is enabled
Infer repository core for addon storage
Enabling default storage class
...
Storage is enabled
Infer repository core for addon ingress
Ingress controller is enabled

$ microk8s kubectl get pods -A
NAMESPACE     NAME                                      READY   STATUS    RESTARTS
kube-system   coredns-864597b5fd-x7k2p                  1/1     Running   0
kube-system   hostpath-provisioner-5c65c9c74f-j9qmz      1/1     Running   0
ingress       nginx-ingress-microk8s-controller-abcde    1/1     Running   0
</code></pre>
<p>Each add-on is a maintained, version-pinned bundle — enabling <code class="" data-line="">ingress</code> doesn&#8217;t pull the latest ingress-nginx release, it pulls whatever version that MicroK8s release channel has validated. That&#8217;s the same trade seen everywhere else in this tool: predictability and speed, at the cost of being slightly behind upstream and unable to mix-and-match component versions the way a hand-built cluster can.</p>
<p>The <code class="" data-line="">cilium</code> add-on is worth calling out specifically for platform teams already standardizing on eBPF-based networking elsewhere — it replaces MicroK8s&#8217;s default CNI with Cilium, giving you the same <a href="https://linuxcent.com/tc-ebpf-kubernetes-network-policy/">eBPF-enforced network policy model covered in the TC eBPF episode of the eBPF series</a>, without a separate Cilium install process.</p>
<hr />
<h2 id="dqlite-instead-of-etcd-microk8ss-most-debated-design-choice">Dqlite Instead of etcd: MicroK8s&#8217;s Most Debated Design Choice</h2>
<p>For high availability, upstream Kubernetes distributions almost universally reach for etcd — a mature, Raft-based key-value store with over a decade of production hardening. MicroK8s uses <strong>Dqlite</strong> instead: a distributed SQLite built by Canonical, also Raft-based, but SQL-native rather than a plain key-value store.</p>
<pre><code class="" data-line=""># Convert a single node into a 3-node HA cluster
$ microk8s add-node
From the target node, run:
microk8s join 10.0.1.15:25000/abc123... --worker

$ microk8s status
microk8s is running
high-availability: yes
  datastore master nodes: 10.0.1.10:19001 10.0.1.12:19001 10.0.1.15:19001
  datastore standby nodes: none
</code></pre>
<p>The reasoning behind Dqlite is architectural: Canonical wanted a datastore that could also serve their other projects (LXD, for instance) with a SQL interface, not just Kubernetes&#8217; key-value needs, and one they could tightly control the release cadence of rather than depending on the etcd project&#8217;s own timeline. That&#8217;s a legitimate engineering decision — but it means MicroK8s&#8217;s HA story runs on a datastore with a small fraction of etcd&#8217;s operational track record.</p>
<hr />
<h2 id="where-microk8s-actually-runs-in-production">Where MicroK8s Actually Runs in Production</h2>
<p>MicroK8s&#8217;s real fit is narrower than &#8220;any Kubernetes workload&#8221;: edge and IoT deployments where a device needs a full, conformant cluster with no external dependencies (a factory sensor gateway, a retail point-of-sale cluster); CI/CD pipelines that need a disposable, fast-booting cluster per test run; and single-node developer or demo environments where Minikube&#8217;s VM overhead isn&#8217;t wanted.</p>
<p>It&#8217;s a weaker fit for large multi-tenant production clusters where teams already have deep etcd operational expertise, need fine-grained control-plane component versioning, or run at a scale where Dqlite&#8217;s newer, less-battle-tested Raft implementation is a harder sell to a risk-averse platform team.</p>
<hr />
<h2 id="production-gotchas"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Production Gotchas</h2>
<p><strong>Dqlite HA needs an odd number of nodes, same as etcd — but the community knowledge base is much thinner.</strong> A 2-node or 4-node Dqlite cluster has the identical split-brain risk etcd has at even node counts. The difference is that when something goes wrong, etcd has ten years of Stack Overflow answers and postmortems; Dqlite has a fraction of that.</p>
<p><strong><code class="" data-line="">microk8s kubectl</code> and a separately-installed <code class="" data-line="">kubectl</code> are not automatically the same context.</strong> Running both on one host is a common source of &#8220;why isn&#8217;t my change showing up&#8221; confusion — always check which kubeconfig each one is actually pointed at.</p>
<p><strong>Add-on versions lag upstream by design.</strong> If a CVE fix or a new feature lands in upstream ingress-nginx or Cilium, MicroK8s&#8217;s bundled add-on version won&#8217;t have it until the next MicroK8s release validates it. Don&#8217;t assume <code class="" data-line="">microk8s enable X</code> gets you the latest X.</p>
<p><strong>Classic confinement means MicroK8s can conflict with other host-level network tooling.</strong> Firewalls, VPN clients, or other snap-confined networking tools on the same host can produce iptables/nftables rule conflicts that look like a Kubernetes networking bug but are actually a confinement-boundary interaction.</p>
<hr />
<h2 id="quick-reference">Quick Reference</h2>
<pre><code class="" data-line="">microk8s status --wait-ready       # cluster health, HA state, enabled add-ons
microk8s enable &lt;addon&gt;            # dns, storage, ingress, metallb, cilium, gpu, ...
microk8s disable &lt;addon&gt;           # remove an add-on
microk8s kubectl &lt;args&gt;            # bundled kubectl, uses MicroK8s&#039;s own kubeconfig
microk8s add-node                  # generate a join token for HA/worker expansion
microk8s join &lt;token&gt;               # join a node using that token
microk8s inspect                   # generate a full diagnostic tarball for support/debugging
microk8s remove-node &lt;node&gt;         # remove a node from an HA cluster
</code></pre>
<hr />
<h2 id="contribution-opportunity-dqlites-missing-decade-of-tooling">Contribution Opportunity: Dqlite&#8217;s Missing Decade of Tooling</h2>
<p><strong>The limitation:</strong> etcd operators have <code class="" data-line="">etcdctl endpoint status</code>, <code class="" data-line="">etcdctl endpoint health</code>, mature snapshot/restore tooling, and a decade of documented failure-mode runbooks. Dqlite&#8217;s CLI surface for diagnosing a struggling Raft cluster — checking leader state, log index lag between nodes, or safely restoring from a snapshot after a prolonged partition — is meaningfully thinner. When a MicroK8s HA node fails to rejoin cleanly, there&#8217;s far less prior art to lean on than for the etcd equivalent.</p>
<p><strong>Why it&#8217;s hard to fix:</strong> This isn&#8217;t a bug sitting in an issue tracker waiting for a quick patch. It&#8217;s a maturity gap that comes from Dqlite being a newer, narrower-scope project (built primarily to serve Canonical&#8217;s own products) maintained by a much smaller team than the decade of enterprise-scale usage that produced etcd&#8217;s tooling. Closing that gap is a sustained, multi-quarter documentation-and-tooling effort, not a single PR — and it competes for the Dqlite maintainers&#8217; time against Canonical&#8217;s own product roadmap, which doesn&#8217;t automatically prioritize the broader Kubernetes community&#8217;s operational wishlist.</p>
<p><strong>What a contribution-shaped fix looks like:</strong> Two concrete, achievable starting points that don&#8217;t require deep Raft-internals expertise: (1) a <code class="" data-line="">dqlite</code>-side diagnostic command mirroring <code class="" data-line="">etcdctl endpoint status</code> — human-readable leader/term/log-index output — contributed to <code class="" data-line="">canonical/go-dqlite</code>; or (2) reproducing and documenting specific HA failure scenarios (node rejoin after a prolonged network partition, recovery from a minority-node failure) as runbooks in <code class="" data-line="">canonical/microk8s</code>&#8216;s own documentation repo, with the exact recovery commands verified against a real reproduction. The second option in particular is the kind of contribution an engineer who&#8217;s actually operated MicroK8s in production is uniquely positioned to make — it needs careful reproduction and clear writing, not kernel-level systems expertise.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>MicroK8s packages a full, CNCF-conformant Kubernetes cluster into a single snap install — no separate runtime, etcd, or CNI setup required</li>
<li>The add-on model trades version flexibility for predictability: what you enable is validated and bundled, not necessarily the latest upstream release</li>
<li>Dqlite replaces etcd for HA — a legitimate architectural choice, but one with far less operational tooling and community track record behind it</li>
<li>MicroK8s&#8217;s real fit is edge/IoT, ephemeral CI clusters, and single-node dev environments — not large multi-tenant production clusters with deep etcd expertise already in place</li>
<li>The clearest contribution opportunity here doesn&#8217;t require Raft internals — it requires operating MicroK8s in production long enough to hit a real failure mode and documenting it precisely</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p>MicroK8s trades control for a near-instant single-command cluster. EP02 looks at Minikube — the other dominant &#8220;local Kubernetes&#8221; tool, built on a different trade-off entirely: a full VM (or container-based driver) per cluster instead of a bare-metal snap install, and where that heavier model actually earns its overhead.</p>
<p><em>Next: EP02 — Minikube: Local Kubernetes Done Right — and Where It Breaks Down</em></p>
<p>Get EP02 in your inbox when it publishes → <a href="https://linuxcent.com/subscribe">linuxcent.com/subscribe</a></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&amp;linkname=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fmicrok8s-edge-kubernetes%2F&#038;title=MicroK8s%20Explained%3A%20The%20Single-Binary%20Kubernetes%20for%20Edge%20and%20IoT" data-a2a-url="https://linuxcent.com/microk8s-edge-kubernetes/" data-a2a-title="MicroK8s Explained: The Single-Binary Kubernetes for Edge and IoT"></a></p><p>The post <a href="https://linuxcent.com/microk8s-edge-kubernetes/">MicroK8s Explained: The Single-Binary Kubernetes for Edge and IoT</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/microk8s-edge-kubernetes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2237</post-id>	</item>
		<item>
		<title>Kubernetes Today: v1.33 to v1.35, In-Place Resize GA, and What Comes Next</title>
		<link>https://linuxcent.com/kubernetes-v1-33-whats-new/</link>
					<comments>https://linuxcent.com/kubernetes-v1-33-whats-new/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Fri, 24 Apr 2026 19:31:44 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Kubernetes Security]]></category>
		<category><![CDATA[Kubernetes v1.33]]></category>
		<category><![CDATA[Kubernetes v1.35]]></category>
		<category><![CDATA[Platform Engineering]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-v1-33-whats-new/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>In-place pod resize GA, sidecar containers stable, structured logging mature. Trace what v1.33–v1.35 shipped and where Kubernetes is heading in 2025 and beyond.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-v1-33-whats-new/">Kubernetes Today: v1.33 to v1.35, In-Place Resize GA, and What Comes Next</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;
    font-size:.88em;line-height:1.6;border-left:4px solid #555}
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}
pre code{background:transparent;padding:0;color:inherit}
pre[data-lang="bash"],pre[data-lang="sh"],
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}
pre[data-lang="yaml"],pre[data-lang="json"],
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}
pre[data-lang="text"],pre[data-lang="output"],
pre[data-lang="console"]{border-left-color:#888}
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;
    transition:opacity .15s,background .15s;line-height:1.6}
pre:hover .lc-copy-btn{opacity:1}
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}
pre:hover .lc-lang-badge{opacity:1}
table{border-collapse:collapse;width:100%;margin:16px 0}
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}
th{background:#f0f0f0;font-weight:600}
tr:nth-child(even){background:#fafafa}
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>Ten years after the first commit, Kubernetes is not exciting in the way it was in 2015. That&#8217;s a compliment. The system is stable. The APIs are mature. The migrations — dockershim, PSP, cloud provider code — are behind us.</p>
<p>What the 1.33–1.35 cycle shows is a project focused on precision: removing edge cases, promoting long-running alpha features to stable, and making the scheduler, storage, and security model more correct rather than more powerful. That&#8217;s what a mature infrastructure platform looks like.</p>
<p>Here&#8217;s what happened and where the project is headed.</p>
<hr />
<h2 id="kubernetes-133-sidecar-resize-in-place-resize-beta-april-2025">Kubernetes 1.33 — Sidecar Resize, In-Place Resize Beta (April 2025)</h2>
<p>Code name: <strong>Octarine</strong></p>
<h3 id="in-place-pod-vertical-scaling-reaches-beta">In-Place Pod Vertical Scaling reaches Beta</h3>
<p>After landing as alpha in 1.27, in-place pod resource resizing became beta in 1.33 — enabled by default via the <code class="" data-line="">InPlacePodVerticalScaling</code> feature gate.</p>
<p>The capability: change CPU and memory requests/limits on a running container without terminating and restarting the pod.</p>
<pre><code class="" data-line=""># Resize a running container&#039;s CPU limit without restart
kubectl patch pod api-pod-xyz --type=&#039;json&#039; -p=&#039;[
  {
    &quot;op&quot;: &quot;replace&quot;,
    &quot;path&quot;: &quot;/spec/containers/0/resources/requests/cpu&quot;,
    &quot;value&quot;: &quot;2&quot;
  },
  {
    &quot;op&quot;: &quot;replace&quot;,
    &quot;path&quot;: &quot;/spec/containers/0/resources/limits/cpu&quot;,
    &quot;value&quot;: &quot;4&quot;
  }
]&#039;

# Verify the resize was applied
kubectl get pod api-pod-xyz -o jsonpath=&#039;{.status.containerStatuses[0].resources}&#039;
</code></pre>
<p><strong>Why this matters operationally</strong>: Before in-place resize, vertical scaling meant terminating the pod, losing in-memory state, waiting for a new pod to become ready. For databases with warm buffer pools, JVM applications with loaded heap caches, or any workload where startup cost is significant, this was a serious limitation. Vertical Pod Autoscaler (VPA) worked around it by restarting pods — acceptable for stateless workloads, problematic for stateful ones.</p>
<p>In 1.33, resizing also works for sidecar containers, combining two 1.32-stable features.</p>
<h3 id="sidecar-containers-full-maturity">Sidecar Containers — Full Maturity</h3>
<p>The first feature to formally combine sidecar and in-place resize: you can now vertically scale a service mesh proxy (Envoy sidecar) without restarting the application pod. For high-traffic services where the proxy itself becomes the CPU bottleneck, this is directly actionable.</p>
<hr />
<h2 id="gateway-api-v14-october-2025">Gateway API v1.4 (October 2025)</h2>
<p>Gateway API continued its rapid iteration with v1.4:</p>
<p><strong>BackendTLSPolicy</strong> (Standard channel): Configure TLS between the gateway and the backend service — not just TLS termination at the gateway, but end-to-end encryption:</p>
<pre><code class="" data-line="">apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
  name: api-backend-tls
spec:
  targetRefs:
  - group: &quot;&quot;
    kind: Service
    name: api-service
  validation:
    caCertificateRefs:
    - name: internal-ca
      group: &quot;&quot;
      kind: ConfigMap
    hostname: api.internal.corp
</code></pre>
<p><strong>Gateway Client Certificate Validation</strong>: The gateway can now validate client certificates — mutual TLS for ingress traffic, not just between services.</p>
<p><strong>TLSRoute to Standard</strong>: TLS routing (based on SNI, not HTTP host headers) graduated to the standard channel — enabling TCP workloads with TLS passthrough through the Gateway API model.</p>
<p><strong>ListenerSet</strong>: Group multiple Gateway listeners — useful for shared infrastructure where multiple teams need to attach routes to the same gateway without managing separate Gateway resources.</p>
<hr />
<h2 id="kubernetes-134-scheduler-improvements-dra-continues-august-2025">Kubernetes 1.34 — Scheduler Improvements, DRA Continues (August 2025)</h2>
<p>The 1.34 release focused on the scheduler and Dynamic Resource Allocation:</p>
<p><strong>DRA structured parameters</strong> stabilization: The Dynamic Resource Allocation API matured its parameter model — resource drivers can expose structured claims that the scheduler understands, enabling topology-aware placement of GPU workloads:</p>
<pre><code class="" data-line="">apiVersion: resource.k8s.io/v1alpha3
kind: ResourceClaim
metadata:
  name: gpu-claim
spec:
  devices:
    requests:
    - name: gpu
      deviceClassName: gpu.nvidia.com
      selectors:
      - cel:
          expression: device.attributes[&quot;nvidia.com/gpu-product&quot;].string() == &quot;A100-SXM4-80GB&quot;
      count: 2
</code></pre>
<p><strong>Scheduler QueueingHint</strong> stable: Plugins can now tell the scheduler when to re-queue a pod for scheduling — instead of the scheduler periodically retrying all unschedulable pods, plugins signal when relevant cluster state has changed. This significantly reduces scheduler CPU consumption in large clusters with many unschedulable pods.</p>
<p><strong>Fine-grained node authorization improvements</strong>: Kubelets can now be restricted from accessing Service resources they don&#8217;t need — further reducing the blast radius of a compromised kubelet.</p>
<hr />
<h2 id="kubernetes-135-in-place-resize-ga-memory-limits-unlocked-december-2025">Kubernetes 1.35 — In-Place Resize GA, Memory Limits Unlocked (December 2025)</h2>
<h3 id="in-place-pod-vertical-scaling-graduates-to-stable">In-Place Pod Vertical Scaling Graduates to Stable</h3>
<p>After landing in alpha (1.27), beta (1.33), in-place resize graduated to GA in 1.35. Two significant improvements accompanied GA:</p>
<p><strong>Memory limit decreases now permitted</strong>: Previously, you could increase memory limits in-place but not decrease them. The restriction existed because the kernel doesn&#8217;t immediately reclaim memory when the limit is lowered — the OOM killer would need to run. 1.35 lifts this restriction with proper handling: the kernel is instructed to reclaim, and the pod status reflects the resize progress.</p>
<p><strong>Pod-Level Resources</strong> (alpha in 1.35): Specify resource requests and limits at the pod level rather than per-container — with in-place resize support. Useful for init containers and sidecar patterns where total pod resources matter more than per-container allocation.</p>
<pre><code class="" data-line="">spec:
  # Pod-level resources (alpha) — total budget for all containers
  resources:
    requests:
      cpu: &quot;4&quot;
      memory: &quot;8Gi&quot;
  containers:
  - name: application
    image: myapp:latest
    # No per-container resources; pod-level applies
  - name: log-collector
    image: fluentbit:latest
    restartPolicy: Always  # sidecar
</code></pre>
<h3 id="other-135-highlights">Other 1.35 Highlights</h3>
<p><strong>Topology Spread Constraints improvements</strong>: Better handling of unschedulable scenarios — <code class="" data-line="">whenUnsatisfiable: ScheduleAnyway</code> now has smarter fallback behavior.</p>
<p><strong>VolumeAttributesClass</strong> stable: Change storage performance characteristics (IOPS, throughput) of a PersistentVolume without re-provisioning — the storage equivalent of in-place pod resize.</p>
<pre><code class="" data-line=""># Change volume IOPS without re-provisioning
kubectl patch pvc database-pvc --type=&#039;merge&#039; -p=&#039;
  {&quot;spec&quot;: {&quot;volumeAttributesClassName&quot;: &quot;high-performance&quot;}}&#039;
</code></pre>
<p><strong>Job success policy improvements</strong>: Declare a Job successful when a subset of pods complete successfully — for distributed training jobs where not all workers need to finish.</p>
<hr />
<h2 id="whats-in-kubernetes-136-april-22-2026">What&#8217;s in Kubernetes 1.36 (April 22, 2026)</h2>
<p>Kubernetes 1.36 is on track for April 22, 2026 release. Based on the enhancement tracking and KEP (Kubernetes Enhancement Proposal) pipeline, expected highlights include:</p>
<ul>
<li><strong>DRA</strong> continuing toward stable</li>
<li><strong>Pod-level resources</strong> moving to beta</li>
<li><strong>Scheduler improvements</strong> for AI/ML workload placement</li>
<li><strong>Further Gateway API integration</strong> as core networking model</li>
</ul>
<p>The project has reached a rhythm: four releases per year, each focused on advancing a predictable set of features through alpha → beta → stable. The drama of the 2019–2022 period (PSP, dockershim, API removals) is behind it.</p>
<hr />
<h2 id="the-state-of-the-ecosystem-in-2026">The State of the Ecosystem in 2026</h2>
<h3 id="control-plane-deployment-models">Control Plane Deployment Models</h3>
<table>
<thead>
<tr>
<th>Model</th>
<th>Examples</th>
<th>Best For</th>
</tr>
</thead>
<tbody>
<tr>
<td>Managed (cloud provider)</td>
<td>GKE, EKS, AKS</td>
<td>Most organizations; no control plane ops</td>
</tr>
<tr>
<td>Self-managed</td>
<td>kubeadm, k3s, Talos</td>
<td>Air-gapped, on-prem, specific compliance requirements</td>
</tr>
<tr>
<td>Managed (platform)</td>
<td>Rancher, OpenShift</td>
<td>Enterprises that need multi-cluster management + vendor support</td>
</tr>
</tbody>
</table>
<h3 id="cni-landscape">CNI Landscape</h3>
<table>
<thead>
<tr>
<th>CNI</th>
<th>Model</th>
<th>Notable Feature</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cilium</td>
<td>eBPF</td>
<td>kube-proxy replacement, network policy at kernel, Hubble observability</td>
</tr>
<tr>
<td>Calico</td>
<td>eBPF or iptables</td>
<td>BGP-based networking, hybrid cloud routing</td>
</tr>
<tr>
<td>Flannel</td>
<td>VXLAN/host-gw</td>
<td>Simple, low overhead, no network policy</td>
</tr>
<tr>
<td>Weave</td>
<td>Mesh overlay</td>
<td>Easy multi-host setup</td>
</tr>
</tbody>
</table>
<p>eBPF-based CNIs (Cilium, Calico in eBPF mode) are now the default recommendation for production clusters. The iptables era of Kubernetes networking is ending.</p>
<h3 id="security-stack-in-2026">Security Stack in 2026</h3>
<p>A hardened Kubernetes cluster in 2026 runs:</p>
<pre><code class="" data-line="">Cluster provisioning:    Cluster API + GitOps (Flux/ArgoCD)
Admission control:       Pod Security Admission (restricted) + Kyverno or OPA/Gatekeeper
Runtime security:        Falco (eBPF-based syscall monitoring)
Network security:        Cilium NetworkPolicy + Cilium Cluster Mesh for multi-cluster
Image security:          Cosign signing in CI + admission webhook for signature verification
Secret management:       External Secrets Operator → HashiCorp Vault or cloud KMS
Observability:           Prometheus + Grafana + Hubble (network flows) + OpenTelemetry
</code></pre>
<hr />
<h2 id="the-permanent-principles-that-havent-changed">The Permanent Principles That Haven&#8217;t Changed</h2>
<p>Looking across twelve years and 35 minor versions, some things have not changed:</p>
<p><strong>The API as the universal interface</strong>: Everything in Kubernetes is a resource. This remains the most important architectural decision — it makes every tool, every controller, every GitOps system work with the same model.</p>
<p><strong>Reconciliation loops</strong>: Every Kubernetes controller watches actual state and drives it toward desired state. The controller pattern from 2014 is unchanged. CRDs and Operators are just more instances of it.</p>
<p><strong>Labels and selectors</strong>: The flexible grouping mechanism from 1.0 is still the primary way Kubernetes components find each other. Services find pods. HPA finds Deployments. Operators find their managed resources.</p>
<p><strong>Declarative, not imperative</strong>: You describe what you want. Kubernetes figures out how to achieve and maintain it. This principle, inherited from Borg&#8217;s BCL configuration, underlies everything from Deployments to Crossplane&#8217;s cloud resource management.</p>
<hr />
<h2 id="whats-coming-the-next-five-years">What&#8217;s Coming: The Next Five Years</h2>
<p><strong>WebAssembly on Kubernetes</strong>: The Wasm ecosystem (wasmCloud, SpinKube) is building toward running WebAssembly workloads as first-class Kubernetes pods — near-native performance, smaller images, stronger isolation than containers. Still early, but gaining real adoption.</p>
<p><strong>AI inference as infrastructure</strong>: LLM serving is becoming a cluster primitive. Tools like KServe and vLLM on Kubernetes are moving from research to production. The scheduler, resource model, and networking will continue adapting to inference workload patterns.</p>
<p><strong>Confidential computing</strong>: AMD SEV, Intel TDX, and ARM CCA provide hardware-level memory encryption for pods. The RuntimeClass mechanism and ongoing kernel work are making confidential Kubernetes workloads operational rather than experimental.</p>
<p><strong>Leaner distributions</strong>: k3s, k0s, Talos, and Flatcar-based minimal Kubernetes distributions are growing in adoption for edge, IoT, and resource-constrained environments. The pressure is toward smaller, more auditable control planes.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>In-place pod vertical scaling went from alpha (1.27) to stable (1.35) — live CPU and memory resize without pod restart changes the economics of stateful workload management</li>
<li>Gateway API v1.4 completes the ingress replacement story: BackendTLSPolicy, client certificate validation, and TLSRoute in standard channel</li>
<li>VolumeAttributesClass stable (1.35): Change storage performance in-place — the storage parallel to pod resource resize</li>
<li>The eBPF era of Kubernetes networking is established: Cilium as default CNI in GKE, growing in EKS/AKS, replacing iptables-based kube-proxy</li>
<li>The Kubernetes project in 2026 is focused on precision — promoting mature features to stable, reducing edge cases, improving scheduler efficiency — not adding new abstractions</li>
<li>WebAssembly, confidential computing, and AI inference scheduling are the frontiers to watch</li>
</ul>
<hr />
<h2 id="series-wrap-up">Series Wrap-Up</h2>
<table>
<thead>
<tr>
<th>Era</th>
<th>Defining Change</th>
</tr>
</thead>
<tbody>
<tr>
<td>2003–2014</td>
<td>Borg and Omega build the playbook internally at Google</td>
</tr>
<tr>
<td>2014–2016</td>
<td>Kubernetes 1.0, CNCF, and winning the container orchestration wars</td>
</tr>
<tr>
<td>2016–2018</td>
<td>RBAC stable, CRDs, cloud providers all-in on managed K8s</td>
</tr>
<tr>
<td>2018–2020</td>
<td>Operators, service mesh, OPA/Gatekeeper — the extensibility era</td>
</tr>
<tr>
<td>2020–2022</td>
<td>Supply chain crisis, PSP deprecated, API removals, dockershim exit</td>
</tr>
<tr>
<td>2022–2023</td>
<td>Dockershim and PSP removed, eBPF networking takes over</td>
</tr>
<tr>
<td>2023–2025</td>
<td>GitOps standard, sidecar stable, DRA, AI/ML workloads</td>
</tr>
<tr>
<td>2025–2026</td>
<td>In-place resize GA, VolumeAttributesClass, Gateway API complete</td>
</tr>
</tbody>
</table>
<p>From 47,501 lines of Go in a 250-file GitHub commit to the operating system of the cloud — and still reconciling.</p>
<hr />
<p><a href="ep07-platform-engineering.md">← EP07: Platform Engineering Era</a></p>
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&amp;linkname=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-v1-33-whats-new%2F&#038;title=Kubernetes%20Today%3A%20v1.33%20to%20v1.35%2C%20In-Place%20Resize%20GA%2C%20and%20What%20Comes%20Next" data-a2a-url="https://linuxcent.com/kubernetes-v1-33-whats-new/" data-a2a-title="Kubernetes Today: v1.33 to v1.35, In-Place Resize GA, and What Comes Next"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-v1-33-whats-new/">Kubernetes Today: v1.33 to v1.35, In-Place Resize GA, and What Comes Next</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-v1-33-whats-new/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1662</post-id>	</item>
		<item>
		<title>The Platform Engineering Era: GitOps, AI Workloads, and Leaner Kubernetes (2023–2025)</title>
		<link>https://linuxcent.com/kubernetes-platform-engineering-gitops/</link>
					<comments>https://linuxcent.com/kubernetes-platform-engineering-gitops/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 15 Apr 2026 19:31:32 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[AI Infrastructure]]></category>
		<category><![CDATA[ArgoCD]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[GitOps]]></category>
		<category><![CDATA[Platform Engineering]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-platform-engineering-gitops/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>GitOps became the default deployment model. AI workloads hit production clusters. Cluster API matured. Trace how v1.28–v1.32 made Kubernetes the substrate for platform engineering.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-platform-engineering-gitops/">The Platform Engineering Era: GitOps, AI Workloads, and Leaner Kubernetes (2023–2025)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;<br />
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;<br />
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;<br />
    font-size:.88em;line-height:1.6;border-left:4px solid #555}<br />
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}<br />
pre code{background:transparent;padding:0;color:inherit}<br />
pre[data-lang="bash"],pre[data-lang="sh"],<br />
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}<br />
pre[data-lang="yaml"],pre[data-lang="json"],<br />
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}<br />
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],<br />
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}<br />
pre[data-lang="text"],pre[data-lang="output"],<br />
pre[data-lang="console"]{border-left-color:#888}<br />
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;<br />
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;<br />
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;<br />
    transition:opacity .15s,background .15s;line-height:1.6}<br />
pre:hover .lc-copy-btn{opacity:1}<br />
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}<br />
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}<br />
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;<br />
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;<br />
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}<br />
pre:hover .lc-lang-badge{opacity:1}<br />
table{border-collapse:collapse;width:100%;margin:16px 0}<br />
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}<br />
th{background:#f0f0f0;font-weight:600}<br />
tr:nth-child(even){background:#fafafa}<br />
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>By 2023, the question had shifted from &#8220;how do we run Kubernetes?&#8221; to &#8220;how do we let other engineers run their workloads on Kubernetes without becoming a bottleneck?&#8221;</p>
<p>This is the platform engineering problem. And it drove the tooling that defined 2023–2025: GitOps as the deployment standard, Cluster API for Kubernetes-on-Kubernetes provisioning, AI/ML workloads forcing new scheduling capabilities, and the Kubernetes project itself shedding more weight to become faster to release and operate.</p>
<hr />
<h2 id="gitops-principle-becomes-practice">GitOps: Principle Becomes Practice</h2>
<p>GitOps as a term was coined by Weaveworks in 2017. By 2023, it was no longer a debate — it was the default deployment model for organizations running Kubernetes at scale.</p>
<p>The principle: the desired state of your cluster lives in Git. A controller watches the repository and reconciles the cluster state to match. Every deployment is a PR merge. The audit trail is the Git history.</p>
<p><strong>Flux v2</strong> (CNCF graduated) and <strong>ArgoCD</strong> (CNCF incubating) became the two dominant implementations:</p>
<pre><code class="" data-line=""># Flux: GitRepository + Kustomization
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: production-config
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/org/k8s-config
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: production-apps
  namespace: flux-system
spec:
  interval: 10m
  path: ./clusters/production
  prune: true          # Remove resources deleted from Git
  sourceRef:
    kind: GitRepository
    name: production-config
  healthChecks:
  - apiVersion: apps/v1
    kind: Deployment
    name: api
    namespace: production
</code></pre>
<p>The <code class="" data-line="">prune: true</code> behavior is critical: resources deleted from Git are deleted from the cluster. This is what makes GitOps a security control — unknown resources that aren&#8217;t in Git get removed. No more accumulation of forgotten test deployments, rogue debug pods, or unauthorized configuration changes that outlive the engineer who made them.</p>
<p><strong>ArgoCD&#8217;s Application model</strong> added a UI, synchronization policies, and multi-cluster management:</p>
<pre><code class="" data-line="">apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: production-api
  namespace: argocd
spec:
  project: production
  source:
    repoURL: https://github.com/org/apps
    targetRevision: HEAD
    path: api/production
  destination:
    server: https://kubernetes.default.svc
    namespace: api
  syncPolicy:
    automated:
      prune: true
      selfHeal: true    # Revert manual kubectl changes
    syncOptions:
    - CreateNamespace=true
</code></pre>
<p>The <code class="" data-line="">selfHeal: true</code> option is where GitOps becomes enforceable: any manual change made with kubectl is automatically reverted within the sync interval. For compliance-sensitive environments, this is a configuration drift prevention control.</p>
<hr />
<h2 id="cluster-api-kubernetes-managing-kubernetes">Cluster API: Kubernetes Managing Kubernetes</h2>
<p><strong>Cluster API</strong> (cluster-sigs/cluster-api) flipped the usual model: instead of using tools like Terraform or Ansible to provision Kubernetes clusters, Cluster API lets you manage Kubernetes clusters as Kubernetes resources — using a management cluster to provision and manage workload clusters.</p>
<pre><code class="" data-line=""># Create a new Kubernetes cluster as a Kubernetes resource
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: workload-cluster-prod
spec:
  clusterNetwork:
    pods:
      cidrBlocks: [&quot;192.168.0.0/16&quot;]
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
    kind: AWSCluster
    name: workload-cluster-prod
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
    kind: KubeadmControlPlane
    name: workload-cluster-prod-control-plane
</code></pre>
<p>Cluster API reconciliation handles cluster provisioning, scaling, upgrades, and deletion — all through the Kubernetes API, with all the tooling (RBAC, audit logging, GitOps integration) that entails. Multi-cluster platform teams could now manage hundreds of workload clusters from a single management cluster.</p>
<hr />
<h2 id="kubernetes-128-sidecar-containers-alpha-august-2023">Kubernetes 1.28 — Sidecar Containers Alpha (August 2023)</h2>
<p>Sidecar containers had been a Kubernetes pattern since 2015 — a helper container in the same pod as the main application. But there was no native sidecar lifecycle management. Sidecars were just regular init containers or additional containers, which meant:<br />
&#8211; Init container sidecars ran before the application and had to block until they succeeded<br />
&#8211; Regular container sidecars had no ordering guarantees at startup<br />
&#8211; At pod termination, sidecars could die before the application finished draining</p>
<p>1.28 introduced native sidecar support: <strong>a new restartPolicy field for init containers</strong>:</p>
<pre><code class="" data-line="">spec:
  initContainers:
  - name: log-collector
    image: fluentbit:latest
    restartPolicy: Always    # This makes it a sidecar
    # Starts before main containers, stays running, stops after main containers exit
  containers:
  - name: application
    image: myapp:latest
</code></pre>
<p>A sidecar container (init container with <code class="" data-line="">restartPolicy: Always</code>):<br />
&#8211; Starts before application containers<br />
&#8211; Stays running throughout the pod lifecycle<br />
&#8211; Terminates automatically after all main containers exit<br />
&#8211; Restarts if it crashes (unlike regular init containers)</p>
<p>This solved the service mesh sidecar problem: Istio and Linkerd injected Envoy proxies as regular containers, leading to race conditions where the proxy hadn&#8217;t started when the application tried to make outbound connections. Native sidecar lifecycle guarantees the proxy is ready before the application starts.</p>
<p>Also in 1.28:<br />
&#8211; <strong>Retroactive default StorageClass assignment</strong>: Existing PVCs without a StorageClass assignment get the default applied retroactively — useful for migrations<br />
&#8211; <strong>Non-graceful node shutdown</strong> stable: Handle node power failures without manual pod cleanup<br />
&#8211; <strong>Recovery from volume expansion failure</strong>: Previously, a failed volume expansion left the PVC in a broken state; 1.28 introduced a mechanism to recover</p>
<hr />
<h2 id="aiml-workloads-force-new-kubernetes-capabilities">AI/ML Workloads Force New Kubernetes Capabilities</h2>
<p>The LLM wave of 2023 drove GPU workloads onto Kubernetes at a scale and urgency the project hadn&#8217;t anticipated. Running LLM inference on Kubernetes required solving problems that CPU-centric cluster scheduling hadn&#8217;t encountered:</p>
<p><strong>GPU topology awareness</strong>: Inference across multiple GPUs requires GPUs connected by NVLink or on the same PCIe switch, not arbitrary GPUs from different nodes or different PCIe buses. The Dynamic Resource Allocation API (1.26 alpha) was designed exactly for this.</p>
<p><strong>Fractional GPU allocation</strong>: NVIDIA&#8217;s time-slicing and MIG (Multi-Instance GPU) allow multiple pods to share a single GPU. The GPU operator (NVIDIA) manages this at the node level:</p>
<pre><code class="" data-line=""># Check GPU resources visible to Kubernetes
kubectl get nodes -o custom-columns=\
  &quot;NODE:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu&quot;
# NODE       GPU
# gpu-node-1   8
# gpu-node-2   8
</code></pre>
<p><strong>Batch scheduling for training jobs</strong>: Training runs require all workers to start simultaneously — a single missing GPU makes the entire job stall. The Kubernetes Job API doesn&#8217;t guarantee this. Projects like <strong>Volcano</strong> (CNCF incubating) and <strong>Kueue</strong> (Kubernetes SIG Scheduling) added gang scheduling: a job only starts when all requested resources are available.</p>
<pre><code class="" data-line=""># Kueue: queue AI training jobs with resource quotas
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: gpu-queue
spec:
  namespaceSelector: {}
  resourceGroups:
  - coveredResources: [&quot;nvidia.com/gpu&quot;, &quot;cpu&quot;, &quot;memory&quot;]
    flavors:
    - name: a100-80gb
      resources:
      - name: nvidia.com/gpu
        nominalQuota: 16
</code></pre>
<hr />
<h2 id="kubernetes-129-sidecar-to-beta-load-balancer-ip-mode-december-2023">Kubernetes 1.29 — Sidecar to Beta, Load Balancer IP Mode (December 2023)</h2>
<ul>
<li><strong>Sidecar containers</strong> beta: The lifecycle semantics were refined based on 1.28 alpha feedback</li>
<li><strong>Load balancer IP mode</strong> alpha: Distinguish between load balancers that use virtual IPs (kube-proxy handles the traffic) vs. those that handle traffic directly (no need for kube-proxy rules) — important for eBPF-based load balancers</li>
<li><strong>ReadWriteOncePod volume access</strong> stable</li>
</ul>
<hr />
<h2 id="kubernetes-130-structured-authorization-config-april-2024">Kubernetes 1.30 — Structured Authorization Config (April 2024)</h2>
<ul>
<li><strong>Structured authorization configuration</strong> beta: Define multiple authorization webhooks with explicit ordering, failure modes, and connection settings — replacing the flat <code class="" data-line="">--authorization-mode</code> flag</li>
<li><strong>Sidecar containers</strong> beta continues</li>
<li><strong>Node memory swap support</strong> beta: Allow pods to use swap memory — controversial but necessary for workloads with bursty memory patterns that prefer using swap over OOM kill</li>
</ul>
<pre><code class="" data-line=""># Node with swap enabled — kubelet config
kind: KubeletConfiguration
memorySwap:
  swapBehavior: LimitedSwap
</code></pre>
<p>The swap support feature reversed a long-standing Kubernetes hard stance: swap was disabled since 1.0 because its interaction with Kubernetes memory accounting was unpredictable. The 1.30 approach adds proper accounting and policies.</p>
<hr />
<h2 id="kubernetes-131-cloud-provider-code-removal-complete-august-2024">Kubernetes 1.31 — Cloud Provider Code Removal Complete (August 2024)</h2>
<p>1.31 marked the completion of the cloud provider code removal — the 1.5 million line migration that had been running since 1.26. Core binaries are 40% smaller. The API server, controller manager, and scheduler no longer contain vendor-specific code.</p>
<p>Also in 1.31:<br />
&#8211; <strong>Persistent Volume health monitor</strong> stable<br />
&#8211; <strong>AppArmor support</strong> stable: AppArmor profiles for pods using the native Kubernetes field (not annotations)<br />
&#8211; <strong>Traffic distribution for Services</strong> beta: Express topology preferences for Service routing (prefer local node, prefer same zone)</p>
<pre><code class="" data-line=""># Traffic distribution: prefer endpoints in the same zone
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  trafficDistribution: PreferClose
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 8080
</code></pre>
<hr />
<h2 id="kubernetes-132-sidecar-stable-dra-beta-december-2024">Kubernetes 1.32 — Sidecar Stable, DRA Beta (December 2024)</h2>
<ul>
<li><strong>Sidecar containers</strong> stable: After nearly a decade of workarounds, the sidecar pattern is a first-class Kubernetes primitive</li>
<li><strong>Dynamic Resource Allocation</strong> beta: GPU and specialized hardware scheduling ready for production evaluation</li>
<li><strong>Job API improvements</strong>: Success and failure policies for indexed jobs — granular control over batch workload behavior</li>
<li><strong>Custom Resource field selectors</strong>: Filter CRDs on arbitrary fields — making large CRD-based systems more efficient to query</li>
</ul>
<hr />
<h2 id="crossplane-kubernetes-as-the-control-plane-for-everything">Crossplane: Kubernetes as the Control Plane for Everything</h2>
<p>Crossplane (CNCF graduated) extended the Kubernetes API model beyond the cluster itself. Using CRDs and controllers, Crossplane lets you manage cloud resources (RDS databases, S3 buckets, VPCs, IAM roles) as Kubernetes resources — provisioned, updated, and deleted through the Kubernetes API.</p>
<pre><code class="" data-line=""># Crossplane: provision an RDS PostgreSQL instance as a Kubernetes resource
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
  name: production-db
spec:
  forProvider:
    region: us-east-1
    dbInstanceClass: db.r6g.xlarge
    masterUsername: admin
    engine: postgres
    engineVersion: &quot;15&quot;
    allocatedStorage: 100
    multiAZ: true
  writeConnectionSecretsToRef:
    name: production-db-credentials
    namespace: production
</code></pre>
<p>For platform teams, Crossplane means a single control plane — the Kubernetes API — for both compute workloads and cloud infrastructure. GitOps tools (Flux, ArgoCD) manage both.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>GitOps (Flux, ArgoCD) became the production deployment standard — not for ideological reasons, but because the audit trail, drift detection, and self-healing properties solve real operational and compliance problems</li>
<li>Cluster API made Kubernetes cluster lifecycle (provisioning, upgrades, deletion) a Kubernetes-native operation — the same API, tooling, and audit trail</li>
<li>Native sidecar containers (1.28 alpha → 1.32 stable) finally resolved the lifecycle ordering problem that service meshes and log collectors had worked around for years</li>
<li>AI/ML workloads drove new scheduling capabilities (DRA, gang scheduling via Kueue/Volcano) and made GPU topology awareness a first-class concern</li>
<li>Crossplane generalized the Kubernetes API model to cloud infrastructure — the cluster is now a control plane for everything, not just containers</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="ep06-runtime-reckoning.md">← EP06: The Runtime Reckoning</a> | <a href="ep08-kubernetes-today.md">EP08: Kubernetes Today →</a></p>
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&amp;linkname=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-platform-engineering-gitops%2F&#038;title=The%20Platform%20Engineering%20Era%3A%20GitOps%2C%20AI%20Workloads%2C%20and%20Leaner%20Kubernetes%20%282023%E2%80%932025%29" data-a2a-url="https://linuxcent.com/kubernetes-platform-engineering-gitops/" data-a2a-title="The Platform Engineering Era: GitOps, AI Workloads, and Leaner Kubernetes (2023–2025)"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-platform-engineering-gitops/">The Platform Engineering Era: GitOps, AI Workloads, and Leaner Kubernetes (2023–2025)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-platform-engineering-gitops/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1659</post-id>	</item>
		<item>
		<title>The Operator Era: Stateful Workloads, Service Mesh, and the Cloud-Native Stack (2018–2020)</title>
		<link>https://linuxcent.com/kubernetes-operator-pattern-service-mesh/</link>
					<comments>https://linuxcent.com/kubernetes-operator-pattern-service-mesh/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 19:30:49 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Istio]]></category>
		<category><![CDATA[Kubernetes Operators]]></category>
		<category><![CDATA[Kubernetes Security]]></category>
		<category><![CDATA[Service Mesh]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-operator-pattern-service-mesh/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>Operators extended Kubernetes beyond stateless apps. Service mesh layered mTLS on top. Trace how v1.11–v1.18 added Istio, StatefulSets, and OPA to the cloud-native stack.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-operator-pattern-service-mesh/">The Operator Era: Stateful Workloads, Service Mesh, and the Cloud-Native Stack (2018–2020)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;<br />
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;<br />
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;<br />
    font-size:.88em;line-height:1.6;border-left:4px solid #555}<br />
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}<br />
pre code{background:transparent;padding:0;color:inherit}<br />
pre[data-lang="bash"],pre[data-lang="sh"],<br />
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}<br />
pre[data-lang="yaml"],pre[data-lang="json"],<br />
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}<br />
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],<br />
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}<br />
pre[data-lang="text"],pre[data-lang="output"],<br />
pre[data-lang="console"]{border-left-color:#888}<br />
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;<br />
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;<br />
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;<br />
    transition:opacity .15s,background .15s;line-height:1.6}<br />
pre:hover .lc-copy-btn{opacity:1}<br />
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}<br />
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}<br />
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;<br />
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;<br />
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}<br />
pre:hover .lc-lang-badge{opacity:1}<br />
table{border-collapse:collapse;width:100%;margin:16px 0}<br />
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}<br />
th{background:#f0f0f0;font-weight:600}<br />
tr:nth-child(even){background:#fafafa}<br />
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>By 2018, Kubernetes had won the orchestration market. The question was no longer &#8220;which orchestrator?&#8221; — it was &#8220;how do we run complex workloads on it, and how do we do it safely?&#8221;</p>
<p>The 2018–2020 period is defined by three parallel tracks: the Operator pattern maturing into a serious engineering discipline, the service mesh debate consuming enormous community energy, and the security model evolving from &#8220;trust everything in the cluster&#8221; toward something resembling defense-in-depth.</p>
<hr />
<h2 id="the-operatorhub-era">The OperatorHub Era</h2>
<p>The Operator pattern, introduced by CoreOS engineers in 2016, reached critical mass in 2018–2019. In November 2018, Red Hat launched <strong>OperatorHub.io</strong> — a registry for Kubernetes Operators covering databases (PostgreSQL, MongoDB, CockroachDB), messaging (Kafka, RabbitMQ), monitoring (Prometheus), and more.</p>
<p>The Operator SDK (Red Hat, 2018) gave teams a framework for building Operators in Go, Ansible, or Helm — lowering the barrier from &#8220;you need to write a Kubernetes controller from scratch&#8221; to &#8220;fill in the reconciliation logic.&#8221;</p>
<p>The maturity model for Operators was codified into five levels:</p>
<table>
<thead>
<tr>
<th>Level</th>
<th>Capability</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Basic Install — automated deployment</td>
</tr>
<tr>
<td>2</td>
<td>Seamless Upgrades — patch and minor version upgrades</td>
</tr>
<tr>
<td>3</td>
<td>Full Lifecycle — backup, failure recovery</td>
</tr>
<tr>
<td>4</td>
<td>Deep Insights — metrics, alerts, log processing</td>
</tr>
<tr>
<td>5</td>
<td>Auto Pilot — horizontal/vertical scaling, auto-config tuning</td>
</tr>
</tbody>
</table>
<p>Most production Operators in 2019 were at Level 1–2. Getting to Level 3+ required encoding significant domain knowledge — the kind that previously lived in a senior database administrator&#8217;s head.</p>
<hr />
<h2 id="kubernetes-111-coredns-default-load-balancing-stable-june-2018">Kubernetes 1.11 — CoreDNS Default, Load Balancing Stable (June 2018)</h2>
<ul>
<li><strong>CoreDNS</strong> replaced kube-dns as the default DNS provider. CoreDNS is plugin-based — you can extend it for custom DNS resolution logic (split DNS, external name resolution, DNS-based service discovery for non-Kubernetes services)</li>
<li><strong>IPVS-based kube-proxy</strong> stable: The load balancing mode for Services switched from iptables to IPVS (IP Virtual Server), enabling O(1) service routing instead of O(n) iptables rule traversal — critical at scale</li>
<li><strong>TLS bootstrapping</strong> stable: Kubelet automatic certificate rotation — kubelets no longer needed manual certificate management</li>
</ul>
<p>The IPVS kube-proxy mode is a good example of a performance improvement that also has security implications. iptables rules degrade linearly with rule count; at 10,000+ services, iptables becomes a performance and debuggability problem. IPVS uses a hash table — O(1) lookups regardless of service count.</p>
<hr />
<h2 id="kubernetes-112-113-amazon-eks-runtime-security-septemberdecember-2018">Kubernetes 1.12 — 1.13: Amazon EKS, Runtime Security (September–December 2018)</h2>
<h3 id="amazon-eks-goes-ga-june-2018">Amazon EKS Goes GA (June 2018)</h3>
<p>Amazon EKS became generally available in June 2018. This was significant not just for AWS customers but for the entire ecosystem: EKS&#8217;s launch meant every major cloud provider now had a production-grade managed Kubernetes offering.</p>
<p>EKS&#8217;s initial release was deliberately limited — managed control plane, self-managed worker nodes. This contrasted with GKE&#8217;s more automated approach, and the community noticed. GKE had been running managed Kubernetes longer, and it showed in feature completeness.</p>
<h3 id="112-september-2018">1.12 (September 2018)</h3>
<ul>
<li><strong>RuntimeClass</strong> alpha: A mechanism to specify which container runtime to use for a pod — containerd, gVisor, Kata Containers. The foundation for confidential computing workloads where you want hardware-isolated containers</li>
<li><strong>RBAC delegation</strong>: Service accounts could now grant RBAC permissions they themselves held — enabling Operators to manage RBAC for the applications they deploy</li>
<li><strong>Volume snapshot</strong> alpha: Create point-in-time snapshots of PersistentVolumes — the beginning of Kubernetes-native backup primitives</li>
</ul>
<h3 id="113-december-2018">1.13 (December 2018)</h3>
<ul>
<li><strong>kubeadm</strong> graduates to GA: The cluster bootstrapping tool was now stable and recommended for production</li>
<li><strong>CoreDNS</strong> stable</li>
<li><strong>CSI</strong> stable: Storage drivers could be shipped entirely out of tree</li>
</ul>
<hr />
<h2 id="kubernetes-114-windows-containers-go-stable-march-2019">Kubernetes 1.14 — Windows Containers Go Stable (March 2019)</h2>
<p>Windows Server container support graduated to stable in 1.14. For the first time, Kubernetes clusters could run Windows workloads as first-class citizens — .NET Framework applications, IIS, SQL Server containers alongside Linux-based microservices.</p>
<p>The implementation required significant work: Windows containers have different networking models, different filesystem semantics, and different process models than Linux containers. Making them a first-class Kubernetes citizen meant handling all of those differences in the node components.</p>
<p>Also in 1.14:<br />
&#8211; <strong>PersistentVolume and StorageClass</strong> improvements<br />
&#8211; <strong>kubectl improvements</strong>: <code class="" data-line="">kubectl diff</code> — show what would change before applying a manifest</p>
<hr />
<h2 id="the-podsecuritypolicy-problem">The PodSecurityPolicy Problem</h2>
<p><strong>PodSecurityPolicy (PSP)</strong> was alpha in Kubernetes 1.3, beta in 1.8, and would remain in beta until it was deprecated in 1.21. It was simultaneously the most important security primitive in Kubernetes and the most broken.</p>
<p>PSP let administrators define what a pod was allowed to do:</p>
<pre><code class="" data-line="">apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - &#039;configMap&#039;
    - &#039;emptyDir&#039;
    - &#039;projected&#039;
    - &#039;secret&#039;
    - &#039;downwardAPI&#039;
    - &#039;persistentVolumeClaim&#039;
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: MustRunAsNonRoot
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: MustRunAs
    ranges:
      - min: 1
        max: 65535
  fsGroup:
    rule: MustRunAs
    ranges:
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false
</code></pre>
<p>The problem: the admission mechanism was confusing, the UX was hostile, and the authorization model (who could use which PSP) led to privilege escalation paths that were non-obvious. Many teams either disabled PSP entirely or created a permissive policy that made it functionally useless.</p>
<p>The community would spend years working toward a replacement. In 2021 it was deprecated; in 1.25 (2022) it was removed. The replacement — Pod Security Admission — is discussed in EP05.</p>
<hr />
<h2 id="kubernetes-115-117-custom-resource-maturity-2019">Kubernetes 1.15 — 1.17: Custom Resource Maturity (2019)</h2>
<h3 id="115-june-2019">1.15 (June 2019)</h3>
<ul>
<li><strong>CRDs</strong> continue maturing: Structural schemas, pruning of unknown fields — making CRDs behave more like first-class API types</li>
<li><strong>Kustomize</strong> integrated into kubectl: Template-free Kubernetes configuration customization. Where Helm uses Go templates, Kustomize uses overlays — a base configuration plus environment-specific patches</li>
</ul>
<pre><code class="" data-line=""># kustomization.yaml — base + production overlay
bases:
  - ../../base
patches:
  - deployment-replicas.yaml
  - resource-limits.yaml
configMapGenerator:
  - name: app-config
    literals:
      - ENV=production
</code></pre>
<h3 id="116-september-2019">1.16 (September 2019)</h3>
<ul>
<li><strong>CRDs</strong> graduate to GA (apps/v1, not extensions/v1beta1)</li>
<li><strong>Admission webhooks</strong> stable: Validating and mutating webhooks that intercept every API request. This is the foundation for OPA/Gatekeeper, Kyverno, and all policy-as-code enforcement in Kubernetes</li>
</ul>
<p>The admission webhook framework&#8217;s graduation to stable in 1.16 was more significant than it appeared. It meant that any security policy engine — OPA/Gatekeeper, Kyverno, Styra, etc. — could now enforce policies on any Kubernetes resource creation or modification, using a stable, documented API.</p>
<ul>
<li><strong>Removal of several deprecated beta APIs</strong>: extensions/v1beta1 Deployments, DaemonSets, ReplicaSets — a preview of the more aggressive API cleanup that would come in 1.22</li>
</ul>
<h3 id="117-december-2019">1.17 (December 2019)</h3>
<ul>
<li><strong>Volume snapshots</strong> beta</li>
<li><strong>Cloud Provider labels</strong> stable</li>
</ul>
<hr />
<h2 id="opagatekeeper-policy-as-code-enters-the-mainstream">OPA/Gatekeeper: Policy as Code Enters the Mainstream</h2>
<p>Open Policy Agent (OPA) + Gatekeeper emerged as the policy engine of choice for Kubernetes in 2019. Gatekeeper uses the admission webhook framework to intercept API requests and evaluate them against Rego policies:</p>
<pre><code class="" data-line=""># Deny containers running as root
package kubernetes.admission

deny[msg] {
  input.request.kind.kind == &quot;Pod&quot;
  container := input.request.object.spec.containers[_]
  container.securityContext.runAsUser == 0
  msg := sprintf(&quot;Container %v must not run as root&quot;, [container.name])
}
</code></pre>
<p>The OPA/Gatekeeper model represented a shift in security thinking: instead of configuring security at the cluster level, you codify security policy in a language (Rego) and enforce it uniformly across all admission requests. Policies can be tested, versioned, and reviewed like code.</p>
<hr />
<h2 id="kubernetes-118-topology-aware-routing-immutability-march-2020">Kubernetes 1.18 — Topology-Aware Routing, Immutability (March 2020)</h2>
<ul>
<li><strong>Topology-aware service routing</strong> alpha: Route service traffic to endpoints in the same zone/node as the caller — reducing cross-zone data transfer costs and latency</li>
<li><strong>Immutable ConfigMaps and Secrets</strong> alpha: Mark a ConfigMap or Secret as immutable — the API server rejects updates, preventing accidental mutation of configuration that applications have already loaded</li>
<li><strong>IngressClass</strong>: A mechanism to specify which Ingress controller should handle an Ingress resource — enabling multiple ingress controllers in the same cluster</li>
</ul>
<pre><code class="" data-line=""># Immutable secret — once set, cannot be changed
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
immutable: true
data:
  password: dGhpcyBpcyBhIHRlc3Q=
</code></pre>
<hr />
<h2 id="the-falco-adoption-wave">The Falco Adoption Wave</h2>
<p>CNCF-donated Falco (originated by Sysdig) became the standard tool for Kubernetes runtime security in this period. Falco uses eBPF probes or kernel modules to monitor syscalls and generate alerts based on rules:</p>
<pre><code class="" data-line=""># Falco rule: detect shell spawned in a container
- rule: Terminal shell in container
  desc: A shell was spawned in a container
  condition: &gt;
    spawned_process and container and
    shell_procs and proc.tty != 0
  output: &gt;
    A shell was spawned in a container
    (user=%user.name container=%container.name
     shell=%proc.name parent=%proc.pname)
  priority: WARNING
</code></pre>
<p>Falco addressed the gap that PodSecurityPolicy couldn&#8217;t: admission-time policy prevents known-bad configurations from running, but it can&#8217;t detect a compromise that happens at runtime — a shell spawned by an exploited web application, for example.</p>
<hr />
<h2 id="the-service-mesh-exhaustion">The Service Mesh Exhaustion</h2>
<p>By 2019, the service mesh landscape was producing more overhead than value for many teams. Istio&#8217;s operational complexity — its control plane components, its sidecar injection model, its frequent breaking changes between versions — burned teams that adopted it early.</p>
<p>The community questions were real: do you actually need mTLS between every service in your cluster? Is the operational cost of a service mesh worth the security benefit for every organization?</p>
<p>Linkerd 2.x (Buoyant) positioned itself as the lightweight alternative — simpler to operate, less configuration surface, Rust-based proxy instead of Envoy. For teams that wanted the security benefit (mTLS) without the complexity cost, Linkerd 2.x was often the better choice.</p>
<p>The honest answer in 2019-2020: service meshes were the right architecture for organizations with hundreds of services and dedicated platform teams. For most organizations, they were complexity that outpaced the threat model.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>The Operator pattern matured from a pattern into an engineering discipline with tooling (Operator SDK), a registry (OperatorHub), and a capability maturity model</li>
<li>EKS going GA completed the managed Kubernetes trifecta — every major cloud provider was now committed</li>
<li>CRDs graduating to stable in 1.16 was the foundation for everything built on Kubernetes extensibility — Operators, policy engines, GitOps tools</li>
<li>Admission webhooks graduating to stable enabled the policy-as-code ecosystem (OPA/Gatekeeper, Kyverno) — the only viable alternative to PSP&#8217;s broken model</li>
<li>Falco established runtime security as a distinct discipline from admission-time policy enforcement</li>
<li>Service mesh adoption was real but the complexity cost was frequently underestimated; many teams that adopted Istio in 2018-2019 spent 2019-2020 managing it</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="ep03-enterprise-awakening.md">← EP03: Enterprise Awakening</a> | <a href="ep05-security-hardens.md">EP05: Security Hardens →</a></p>
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&amp;linkname=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-operator-pattern-service-mesh%2F&#038;title=The%20Operator%20Era%3A%20Stateful%20Workloads%2C%20Service%20Mesh%2C%20and%20the%20Cloud-Native%20Stack%20%282018%E2%80%932020%29" data-a2a-url="https://linuxcent.com/kubernetes-operator-pattern-service-mesh/" data-a2a-title="The Operator Era: Stateful Workloads, Service Mesh, and the Cloud-Native Stack (2018–2020)"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-operator-pattern-service-mesh/">The Operator Era: Stateful Workloads, Service Mesh, and the Cloud-Native Stack (2018–2020)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-operator-pattern-service-mesh/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1650</post-id>	</item>
		<item>
		<title>Enterprise Awakening: RBAC, CRDs, Cloud Providers, and Helm Goes Mainstream (2016–2018)</title>
		<link>https://linuxcent.com/kubernetes-enterprise-rbac-helm/</link>
					<comments>https://linuxcent.com/kubernetes-enterprise-rbac-helm/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 18 Mar 2026 19:30:35 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[CRD]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Helm]]></category>
		<category><![CDATA[Kubernetes RBAC]]></category>
		<category><![CDATA[Kubernetes Security]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-enterprise-rbac-helm/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>RBAC, CRDs, and Helm — the three features that made Kubernetes safe for enterprise. Trace how v1.6–v1.10 transformed a Google-born system into the platform teams actually adopted.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-enterprise-rbac-helm/">Enterprise Awakening: RBAC, CRDs, Cloud Providers, and Helm Goes Mainstream (2016–2018)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;<br />
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;<br />
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;<br />
    font-size:.88em;line-height:1.6;border-left:4px solid #555}<br />
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}<br />
pre code{background:transparent;padding:0;color:inherit}<br />
pre[data-lang="bash"],pre[data-lang="sh"],<br />
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}<br />
pre[data-lang="yaml"],pre[data-lang="json"],<br />
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}<br />
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],<br />
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}<br />
pre[data-lang="text"],pre[data-lang="output"],<br />
pre[data-lang="console"]{border-left-color:#888}<br />
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;<br />
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;<br />
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;<br />
    transition:opacity .15s,background .15s;line-height:1.6}<br />
pre:hover .lc-copy-btn{opacity:1}<br />
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}<br />
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}<br />
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;<br />
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;<br />
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}<br />
pre:hover .lc-lang-badge{opacity:1}<br />
table{border-collapse:collapse;width:100%;margin:16px 0}<br />
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}<br />
th{background:#f0f0f0;font-weight:600}<br />
tr:nth-child(even){background:#fafafa}<br />
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>By the end of 2016, engineers were running Kubernetes in production. Not as an experiment — in production, handling real traffic. And that&#8217;s where the real gaps became visible.</p>
<p>The 2016–2018 period is the era when Kubernetes grew up. RBAC went stable. CRDs replaced the fragile ThirdPartyResource hack. The major cloud providers launched managed services. Helm became the standard for packaging. And the security posture, which had been an afterthought in the Borg-derived model, started getting serious attention.</p>
<hr />
<h2 id="kubernetes-16-the-rbac-milestone-march-2017">Kubernetes 1.6 — The RBAC Milestone (March 2017)</h2>
<p>Kubernetes 1.6 is the release that made enterprise Kubernetes possible. The headline feature: <strong>RBAC (Role-Based Access Control) promoted to beta</strong>, enabled by default.</p>
<p>Before RBAC, Kubernetes had attribute-based access control (ABAC) — a flat policy file on the API server that required a restart to change. It worked, but it was operationally painful and offered no granularity at the namespace level.</p>
<p>RBAC introduced four objects:<br />
&#8211; <strong>Role</strong>: A set of permissions scoped to a namespace<br />
&#8211; <strong>ClusterRole</strong>: A set of permissions cluster-wide or reusable across namespaces<br />
&#8211; <strong>RoleBinding</strong>: Assigns a Role to a user/group/service account in a namespace<br />
&#8211; <strong>ClusterRoleBinding</strong>: Assigns a ClusterRole cluster-wide</p>
<pre><code class="" data-line=""># Example: read-only access to pods in the dev namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev
  name: pod-reader
rules:
- apiGroups: [&quot;&quot;]
  resources: [&quot;pods&quot;]
  verbs: [&quot;get&quot;, &quot;watch&quot;, &quot;list&quot;]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev
subjects:
- kind: User
  name: alice
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
</code></pre>
<p>Also in 1.6:<br />
&#8211; <strong>etcd v3 as default</strong>: Better performance, watch semantics, and transaction support<br />
&#8211; <strong>Node Authorization mode</strong>: Kubelets can now only access secrets and pods bound to their own node — a critical lateral movement restriction<br />
&#8211; <strong>Audit logging</strong> (alpha): API server logs every request — who did what, to which resource, at what time<br />
&#8211; Scale: Tested to 5,000 nodes per cluster</p>
<p>The node authorization mode deserves more attention than it typically gets. Before 1.6, a compromised kubelet could read all secrets in the cluster. Node authorization restricted the kubelet to only the secrets it needed for pods scheduled on that node. This single change dramatically reduced the blast radius of a node compromise.</p>
<hr />
<h2 id="kubernetes-17-custom-resource-definitions-june-2017">Kubernetes 1.7 — Custom Resource Definitions (June 2017)</h2>
<p>The most significant architectural decision in Kubernetes history after the initial design: <strong>ThirdPartyResources (TPRs) were replaced with CustomResourceDefinitions (CRDs)</strong>.</p>
<p>TPRs were a fragile mechanism introduced in 1.2 that let users define custom API types. They had serious limitations: no schema validation, no versioning, data loss bugs, and poor upgrade behavior. In 1.7, they were replaced with CRDs.</p>
<p>CRDs are what make the Kubernetes API extension model work. They let you define new resource types that the API server stores and serves, with optional schema validation via OpenAPI v3 schemas, version conversion, and admission webhook integration.</p>
<pre><code class="" data-line="">apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.stable.example.com
spec:
  group: stable.example.com
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              size:
                type: string
              version:
                type: string
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
</code></pre>
<p>CRDs enabled the entire Operator ecosystem that would define the next phase of Kubernetes. Without stable, schema-validated custom resources, you can&#8217;t build reliable controllers on top of them.</p>
<p>Also in 1.7:<br />
&#8211; <strong>Secrets encryption at rest</strong> (alpha): Finally, secrets stored in etcd could be encrypted with AES-CBC or AES-GCM<br />
&#8211; <strong>Network Policy</strong> promoted to stable: CNI plugins implementing NetworkPolicy could now enforce pod-level ingress/egress rules<br />
&#8211; <strong>API aggregation layer</strong>: Extend the Kubernetes API with custom API servers — the foundation for metrics-server and other API extensions</p>
<hr />
<h2 id="kubernetes-18-rbac-goes-stable-september-2017">Kubernetes 1.8 — RBAC Goes Stable (September 2017)</h2>
<p>RBAC graduated to stable in 1.8. This was the point of no return for enterprise adoption. Security teams could now enforce least-privilege on Kubernetes API access with a documented, stable API.</p>
<p>Key additions:<br />
&#8211; <strong>Storage Classes</strong> stable: Dynamic volume provisioning — request a PersistentVolume and have the underlying storage (EBS, GCE PD, NFS) automatically provisioned<br />
&#8211; <strong>Workloads API</strong> (apps/v1beta2): Deployments, ReplicaSets, DaemonSets, and StatefulSets all moved under a unified API group, signaling they were heading toward stable</p>
<p>The admission webhook framework — which would become the foundation for policy enforcement tools like OPA/Gatekeeper — was also being refined in this period.</p>
<hr />
<h2 id="the-cloud-provider-moment-20172018">The Cloud Provider Moment (2017–2018)</h2>
<h3 id="october-2017-docker-surrenders">October 2017: Docker Surrenders</h3>
<p>At DockerCon Europe in October 2017, Docker Inc. announced that Docker Enterprise Edition would ship with Kubernetes support alongside Docker Swarm. This was, effectively, Docker Inc. conceding the orchestration market to Kubernetes. Swarm remained available, but the message was clear: Kubernetes was the production standard.</p>
<h3 id="october-2017-microsoft-previews-aks">October 2017: Microsoft Previews AKS</h3>
<p>Microsoft previewed Azure Kubernetes Service at DockerCon Europe. The managed Kubernetes race was on.</p>
<h3 id="november-2017-amazon-announces-eks">November 2017: Amazon Announces EKS</h3>
<p>At AWS re:Invent 2017, Amazon announced Elastic Kubernetes Service. The three major cloud providers — Google (GKE, running since 2014), Microsoft (AKS), and Amazon (EKS) — were all committed to managed Kubernetes.</p>
<p>For enterprise buyers, this was the signal they needed. Kubernetes was no longer a bet on an experimental technology — it was the supported, managed offering from every major cloud provider.</p>
<hr />
<h2 id="kubernetes-19-workloads-api-stable-december-2017">Kubernetes 1.9 — Workloads API Stable (December 2017)</h2>
<p>The Workloads API (apps/v1) went stable in 1.9. This matters because it locked in the API contract for Deployments, ReplicaSets, DaemonSets, and StatefulSets. Infrastructure built on these APIs would not break on upgrades.</p>
<pre><code class="" data-line=""># apps/v1 Deployment — the stable form that operators rely on
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: &quot;64Mi&quot;
            cpu: &quot;250m&quot;
          limits:
            memory: &quot;128Mi&quot;
            cpu: &quot;500m&quot;
</code></pre>
<p>Also in 1.9:<br />
&#8211; <strong>Windows container support</strong> moved to beta — actual Windows Server 2016 nodes in a cluster<br />
&#8211; <strong>CoreDNS</strong> available as an alternative to kube-dns: A more extensible, plugin-based DNS server that would replace kube-dns as the default in 1.11</p>
<hr />
<h2 id="kubernetes-110-storage-auth-and-scale-march-2018">Kubernetes 1.10 — Storage, Auth, and Scale (March 2018)</h2>
<p>1.10 continued the enterprise hardening:<br />
&#8211; <strong>CSI (Container Storage Interface)</strong> beta: A standardized interface between Kubernetes and storage providers. Before CSI, storage drivers were compiled into the kubelet binary. CSI moved them out-of-tree, allowing storage vendors to ship their own drivers without waiting for a Kubernetes release<br />
&#8211; <strong>External credential providers</strong> (alpha): Authenticate against external systems (cloud IAM, HashiCorp Vault) for kubeconfig credentials<br />
&#8211; <strong>Node problem detector</strong> stable: Detect and report node-level problems (kernel deadlocks, corrupted file systems) as Kubernetes events and node conditions</p>
<p>The CSI transition was one of the most important infrastructure decisions of this period. It decoupled storage driver development from the Kubernetes release cycle — a necessary step for cloud providers to ship storage integrations rapidly and independently.</p>
<hr />
<h2 id="the-istio-announcement-and-service-mesh-wars-may-2017">The Istio Announcement and Service Mesh Wars (May 2017)</h2>
<p>Google and IBM announced Istio in May 2017 — a service mesh that layered mTLS, traffic management, and observability on top of existing Kubernetes deployments without changing application code.</p>
<p>Istio&#8217;s architecture: sidecar proxies (Envoy) injected into every pod, managed by a control plane. Every service-to-service call passes through the sidecar, enabling:<br />
&#8211; Mutual TLS between services (zero-trust networking at the service layer)<br />
&#8211; Fine-grained traffic control (canary releases, circuit breaking, retries)<br />
&#8211; Distributed tracing and metrics</p>
<p>Linkerd (from Buoyant) had been working on the same problem since 2016. The two projects would compete for the &#8220;service mesh standard&#8221; throughout 2017–2019.</p>
<p>The service mesh conversation was fundamentally a security architecture conversation: how do you enforce mutual authentication and encryption between services in a Kubernetes cluster without requiring application developers to implement it?</p>
<hr />
<h2 id="coreos-acquisition-and-the-operator-pattern-2018">CoreOS Acquisition and the Operator Pattern (2018)</h2>
<p>In January 2018, Red Hat acquired CoreOS for $250 million. CoreOS had contributed two things that would permanently shape Kubernetes:</p>
<p><strong>1. The Operator Pattern</strong> (introduced by CoreOS engineers Brandon Philips and Josh Wood in 2016): An Operator is a custom controller that uses CRDs to manage the lifecycle of complex, stateful applications. The etcd Operator (CoreOS&#8217;s own) was the first — it automated etcd cluster creation, scaling, backup, and failure recovery. The pattern generalized: a Prometheus Operator, a PostgreSQL Operator, a Kafka Operator.</p>
<p>The Operator pattern is the answer to the question &#8220;how do you encode operational knowledge into software?&#8221; A human operator knows how to deploy, scale, backup, and recover a database. An Operator codifies that knowledge into a controller loop.</p>
<pre><code class="" data-line=""># Operator pattern: watch CRD → reconcile → manage application
CRD (EtcdCluster) → Operator Controller watches → creates/updates Pods, Services, Snapshots
</code></pre>
<p><strong>2. etcd</strong>: The distributed key-value store that backs the Kubernetes control plane. CoreOS built and maintained etcd. Red Hat acquiring CoreOS meant that the company maintaining Kubernetes&#8217;s most critical dependency (after the kernel) was now inside the Red Hat/IBM orbit.</p>
<hr />
<h2 id="helm-2-and-the-charts-ecosystem">Helm 2 and the Charts Ecosystem</h2>
<p>By 2017–2018, Helm had become the de facto package manager for Kubernetes. The public Helm chart repository hosted hundreds of charts — databases (PostgreSQL, MySQL, Redis), monitoring (Prometheus, Grafana), ingress controllers (nginx), CI/CD tools (Jenkins, GitLab Runner).</p>
<p>Helm 2 introduced Tiller — a server-side component that managed release state in the cluster. Tiller became the most criticized security decision in the Kubernetes ecosystem: Tiller ran with cluster-admin privileges by default, meaning any user who could reach Tiller&#8217;s gRPC endpoint could do anything in the cluster.</p>
<p>Security teams hated Tiller. The Helm team addressed it in Helm 3 (2019) by removing Tiller entirely and storing release state as Kubernetes Secrets instead.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>RBAC going stable in 1.8 was the single most important security event in early Kubernetes history — it gave enterprises the access control model they needed for production</li>
<li>CRDs replacing TPRs in 1.7 enabled the entire Operator ecosystem that would define the next phase of Kubernetes</li>
<li>Docker Inc.&#8217;s October 2017 announcement that it would support Kubernetes in Docker EE effectively ended the container orchestration wars</li>
<li>The three major cloud providers (GKE, AKS, EKS) all standardizing on managed Kubernetes drove enterprise adoption faster than any feature announcement could</li>
<li>The Operator pattern — Kubernetes controllers that encode operational knowledge — emerged from CoreOS and became the standard model for managing complex stateful applications</li>
<li>Helm filled a real gap but Tiller&#8217;s cluster-admin model was a security debt the community had to repay in Helm 3</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="ep02-container-wars.md">← EP02: The Container Wars</a> | <a href="ep04-operator-era.md">EP04: The Operator Era →</a></p>
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&amp;linkname=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-enterprise-rbac-helm%2F&#038;title=Enterprise%20Awakening%3A%20RBAC%2C%20CRDs%2C%20Cloud%20Providers%2C%20and%20Helm%20Goes%20Mainstream%20%282016%E2%80%932018%29" data-a2a-url="https://linuxcent.com/kubernetes-enterprise-rbac-helm/" data-a2a-title="Enterprise Awakening: RBAC, CRDs, Cloud Providers, and Helm Goes Mainstream (2016–2018)"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-enterprise-rbac-helm/">Enterprise Awakening: RBAC, CRDs, Cloud Providers, and Helm Goes Mainstream (2016–2018)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-enterprise-rbac-helm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1647</post-id>	</item>
		<item>
		<title>The Container Wars: Kubernetes 1.0, CNCF, and the Fight for Orchestration (2014–2016)</title>
		<link>https://linuxcent.com/kubernetes-container-wars-cncf/</link>
					<comments>https://linuxcent.com/kubernetes-container-wars-cncf/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 11 Mar 2026 19:30:22 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[CNCF]]></category>
		<category><![CDATA[Container Orchestration]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Kubernetes History]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-container-wars-cncf/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span>Three orchestrators entered in 2015 — Docker Swarm, Mesos, and Kubernetes. Only one won. Trace how Kubernetes 1.0 and the CNCF's formation decided the container wars.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-container-wars-cncf/">The Container Wars: Kubernetes 1.0, CNCF, and the Fight for Orchestration (2014–2016)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 6</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;<br />
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;<br />
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;<br />
    font-size:.88em;line-height:1.6;border-left:4px solid #555}<br />
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}<br />
pre code{background:transparent;padding:0;color:inherit}<br />
pre[data-lang="bash"],pre[data-lang="sh"],<br />
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}<br />
pre[data-lang="yaml"],pre[data-lang="json"],<br />
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}<br />
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],<br />
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}<br />
pre[data-lang="text"],pre[data-lang="output"],<br />
pre[data-lang="console"]{border-left-color:#888}<br />
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;<br />
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;<br />
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;<br />
    transition:opacity .15s,background .15s;line-height:1.6}<br />
pre:hover .lc-copy-btn{opacity:1}<br />
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}<br />
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}<br />
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;<br />
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;<br />
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}<br />
pre:hover .lc-lang-badge{opacity:1}<br />
table{border-collapse:collapse;width:100%;margin:16px 0}<br />
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}<br />
th{background:#f0f0f0;font-weight:600}<br />
tr:nth-child(even){background:#fafafa}<br />
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>Three orchestration systems entered the arena in 2015. Only one would still matter three years later.</p>
<p>Docker had created the container revolution. Now everyone needed to run containers at scale, and three camps formed around three very different philosophies. Understanding why Kubernetes won — and how close it came to not winning — explains most of the design choices that still shape Kubernetes today.</p>
<hr />
<h2 id="the-state-of-container-orchestration-in-2014">The State of Container Orchestration in 2014</h2>
<p>When Kubernetes made its public debut at DockerCon 2014, it entered a space that didn&#8217;t yet have a name. &#8220;Container orchestration&#8221; wasn&#8217;t a category. It was a problem people had started to feel but not yet articulate.</p>
<p>Three approaches emerged nearly simultaneously:</p>
<p><strong>Docker Swarm</strong> (announced December 2014): Docker&#8217;s answer to orchestration, built on the premise that the tool you use to run containers should also be the tool you use to cluster them. Swarm used the same Docker CLI and Docker API — zero new concepts for developers already using Docker.</p>
<p><strong>Apache Mesos</strong> (Mesosphere Marathon): Mesos predated Docker. It was a distributed systems kernel originally developed at Berkeley, used in production at Twitter, Airbnb, and Apple. Marathon was the framework for running long-running services on top of Mesos. Mesos could run Docker containers, Hadoop jobs, and Spark workloads on the same cluster. Serious infrastructure engineers took it seriously.</p>
<p><strong>Kubernetes</strong>: The newcomer with Google&#8217;s name behind it, but no track record outside Google, and early versions that required significant operational expertise to run.</p>
<hr />
<h2 id="kubernetes-v10-july-21-2015">Kubernetes v1.0: July 21, 2015</h2>
<p>The 1.0 release landed at the first CloudNativeCon/KubeCon in San Francisco on July 21, 2015. The timing was deliberate — it coincided with the announcement of the Cloud Native Computing Foundation.</p>
<p>What shipped in 1.0:</p>
<ul>
<li><strong>Pods</strong>: The core scheduling unit — one or more containers sharing a network namespace and storage</li>
<li><strong>Replication Controllers</strong>: Keep N copies of a pod running (later replaced by ReplicaSets and Deployments)</li>
<li><strong>Services</strong>: A stable virtual IP and DNS name in front of a set of pods</li>
<li><strong>Namespaces</strong>: Soft multi-tenancy boundaries within a cluster</li>
<li><strong>Labels and Selectors</strong>: The flexible grouping mechanism that makes everything composable</li>
<li><strong>Persistent Volumes</strong> (basic): Pods could mount persistent storage</li>
<li><strong>kubectl</strong>: The command-line interface</li>
</ul>
<p>What was not in 1.0:<br />
&#8211; No RBAC (Role-Based Access Control)<br />
&#8211; No network policy<br />
&#8211; No autoscaling<br />
&#8211; No Ingress resources<br />
&#8211; No StatefulSets<br />
&#8211; No DaemonSets (added in 1.1)<br />
&#8211; Secrets were stored in plaintext in etcd</p>
<p>The security posture of a fresh Kubernetes 1.0 cluster was essentially: &#8220;trust everything inside the cluster.&#8221; That was the inherited assumption from Borg.</p>
<hr />
<h2 id="the-cncf-formation">The CNCF Formation</h2>
<p>Alongside the 1.0 release, Google donated Kubernetes to the newly formed <strong>Cloud Native Computing Foundation</strong> — a Linux Foundation project. This was a critical strategic move.</p>
<p>By donating Kubernetes to a neutral foundation, Google:<br />
1. Removed the perception of a single vendor controlling the project<br />
2. Created a governance model that made enterprise adoption politically safe<br />
3. Invited competitors (Red Hat, CoreOS, Docker, Microsoft) to contribute without ceding control to them</p>
<p>The CNCF&#8217;s initial Technical Oversight Committee included engineers from Google, Red Hat, Twitter, Cisco, and others. This governance model would later become the template for every CNCF project that followed.</p>
<hr />
<h2 id="v11-v15-building-the-foundation-late-20152016">v1.1 — v1.5: Building the Foundation (Late 2015–2016)</h2>
<h3 id="kubernetes-11-november-2015">Kubernetes 1.1 (November 2015)</h3>
<ul>
<li><strong>Horizontal Pod Autoscaler (HPA)</strong>: Automatically scale pod count based on CPU utilization</li>
<li><strong>HTTP load balancing</strong>: Ingress API added as alpha — pods could now be exposed via HTTP routing rules</li>
<li><strong>Job objects</strong>: Run a task to completion, not just keep it running</li>
<li>Performance: 30% throughput improvement, pods per minute scheduling rate improved significantly</li>
</ul>
<h3 id="kubernetes-12-march-2016">Kubernetes 1.2 (March 2016)</h3>
<ul>
<li><strong>Deployments</strong> promoted to beta: Rolling updates, rollback, pause/resume — the deployment primitive that engineers actually use for application deployments</li>
<li><strong>ConfigMaps</strong>: Decouple configuration from container images (no more baking config into images)</li>
<li><strong>Daemon Sets</strong> stable: Run exactly one pod per node — the pattern for node agents (log shippers, monitoring agents, network plugins)</li>
<li>Scale: Tested to 1,000 nodes and 30,000 pods per cluster</li>
</ul>
<h3 id="kubernetes-13-july-2016">Kubernetes 1.3 (July 2016)</h3>
<ul>
<li><strong>StatefulSets</strong> (then called PetSets, alpha): Ordered, persistent-identity pods — the first serious attempt to run databases and stateful applications</li>
<li><strong>Cross-cluster federation</strong> (alpha): Run workloads across multiple clusters</li>
<li><strong>PodDisruptionBudgets</strong> (alpha): Control how many pods can be unavailable during voluntary disruptions — critical for safe rolling updates</li>
<li><strong>rkt integration</strong> (Rktnetes): First Container Runtime Interface experiment — the kubelet talking to something other than Docker</li>
</ul>
<h3 id="kubernetes-14-september-2016">Kubernetes 1.4 (September 2016)</h3>
<ul>
<li><strong>kubeadm</strong>: A tool to bootstrap a Kubernetes cluster in two commands. Before kubeadm, setting up a cluster required following Kelsey Hightower&#8217;s &#8220;Kubernetes the Hard Way&#8221; — valuable for learning, painful for production</li>
<li><strong>ScheduledJobs</strong> (CronJobs): Run a job on a schedule</li>
<li><strong>PodPresets</strong>: Inject common configuration into pods at admission time</li>
<li><strong>Init Containers</strong> beta: Containers that run to completion before the main application containers start — the clean solution for initialization sequencing</li>
</ul>
<h3 id="kubernetes-15-december-2016">Kubernetes 1.5 (December 2016)</h3>
<ul>
<li><strong>StatefulSets</strong> promoted to beta</li>
<li><strong>PodDisruptionBudgets</strong> to beta</li>
<li><strong>Windows Server container support</strong> (alpha): First step toward a non-Linux node</li>
<li><strong>CRI (Container Runtime Interface)</strong> alpha: The abstraction layer that would eventually allow Kubernetes to run containerd, CRI-O, and others instead of depending on Docker</li>
<li><strong>OpenAPI</strong> spec: Machine-readable API documentation, enabling client code generation</li>
</ul>
<hr />
<h2 id="helm-the-missing-package-manager-february-2016">Helm: The Missing Package Manager (February 2016)</h2>
<p>Kubernetes gave you primitives. It did not give you a way to install applications composed of those primitives. In February 2016, Deis (later acquired by Microsoft) released <strong>Helm</strong> — a package manager for Kubernetes.</p>
<p>Helm introduced two concepts that stuck:<br />
&#8211; <strong>Charts</strong>: A collection of Kubernetes manifests bundled with templating and default values<br />
&#8211; <strong>Releases</strong>: An installed instance of a chart, with its own lifecycle (install, upgrade, rollback, delete)</p>
<p>Helm&#8217;s immediate adoption signaled something important: the community was already thinking in terms of applications, not just raw primitives. Infrastructure engineers needed a layer of abstraction above YAML.</p>
<hr />
<h2 id="the-battle-lines-harden">The Battle Lines Harden</h2>
<p>By mid-2016, the three-way contest was becoming clearer:</p>
<p><strong>Docker Swarm&#8217;s advantage</strong>: Zero friction for existing Docker users. <code class="" data-line="">docker swarm init</code> + <code class="" data-line="">docker stack deploy</code>. No new CLI, no new API, no new mental model. For small teams running straightforward applications, it was compelling.</p>
<p><strong>Mesos&#8217;s advantage</strong>: Proven at Google-scale before Kubernetes existed. Twitter ran Mesos in production. It could run heterogeneous workloads (Docker containers, Hadoop, Spark) on the same cluster. Enterprise data teams already had Mesos expertise.</p>
<p><strong>Kubernetes&#8217;s advantage</strong>: The Google name, rapidly growing community, and a design that was clearly winning the feature race. But operational complexity was real — running Kubernetes well in 2016 required significant investment.</p>
<hr />
<h2 id="the-turning-point-nobody-talks-about">The Turning Point Nobody Talks About</h2>
<p>The real moment that decided the container wars wasn&#8217;t a feature announcement. It was cloud provider behavior.</p>
<p>Google Kubernetes Engine (GKE) — then called Google Container Engine — had been running since 2014. It was the first managed Kubernetes service, and it worked. In 2016, both Microsoft and Amazon were working on managed Kubernetes offerings. Neither chose Docker Swarm. Neither chose Mesos.</p>
<p>When cloud providers converge on a technology, the market follows. By the time Amazon announced EKS and Microsoft announced AKS in late 2017, the decision was already made.</p>
<hr />
<h2 id="the-security-debt-accumulates">The Security Debt Accumulates</h2>
<p>Running through the 1.0–1.5 feature list reveals a security architecture that was being designed in flight:</p>
<ul>
<li><strong>etcd stored secrets as base64-encoded strings</strong> — not encrypted. Kubernetes 1.7 (2017) would add encryption at rest, but it required explicit configuration</li>
<li><strong>The API server was unauthenticated by default</strong> in early versions — you needed to configure authentication</li>
<li><strong>Network traffic between pods was unrestricted</strong> — all pods could reach all other pods on all ports, across all namespaces. NetworkPolicy existed as alpha in 1.3 but required a CNI plugin that supported it</li>
<li><strong>The kubelet&#8217;s API was open</strong> — in early Kubernetes, the kubelet&#8217;s HTTP API was accessible without authentication from within the cluster</li>
</ul>
<p>These weren&#8217;t oversights — they were reasonable defaults for an internal cluster managed by a single team. They became liabilities as Kubernetes moved into multi-tenant enterprise environments.</p>
<hr />
<h2 id="kubecon-a-community-forms">KubeCon: A Community Forms</h2>
<p>The first KubeCon conference ran November 9-11, 2015, in San Francisco — a small gathering of a few hundred engineers. By November 2016, KubeCon North America in Seattle drew thousands. The growth was not marketing-driven; it was practitioners solving real problems and sharing what they learned.</p>
<p>This community dynamic was qualitatively different from the Docker Swarm and Mesos ecosystems. Kubernetes had a contributor culture — pull requests, SIG (Special Interest Group) meetings, public design docs. The project was being built in the open, and engineers could see it happening.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Kubernetes 1.0 shipped in July 2015 with the basics functional but security model immature — no RBAC, no network policy, secrets stored in plaintext</li>
<li>The CNCF governance model was the strategic move that made enterprise adoption politically safe — no single vendor controls the project</li>
<li>Helm filled the missing application packaging layer that raw Kubernetes couldn&#8217;t provide</li>
<li>The container wars were decided not by technical superiority alone, but by cloud provider alignment — when Google, Microsoft, and Amazon all built managed Kubernetes, the market followed</li>
<li>v1.1–v1.5 established the core workload primitives: Deployments, StatefulSets, DaemonSets, Jobs, ConfigMaps, HPA — most of these remain the daily vocabulary of Kubernetes operations</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="ep01-borg-legacy.md">← EP01: The Borg Legacy</a> | <a href="ep03-enterprise-awakening.md">EP03: Enterprise Awakening →</a></p>
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&amp;linkname=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-container-wars-cncf%2F&#038;title=The%20Container%20Wars%3A%20Kubernetes%201.0%2C%20CNCF%2C%20and%20the%20Fight%20for%20Orchestration%20%282014%E2%80%932016%29" data-a2a-url="https://linuxcent.com/kubernetes-container-wars-cncf/" data-a2a-title="The Container Wars: Kubernetes 1.0, CNCF, and the Fight for Orchestration (2014–2016)"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-container-wars-cncf/">The Container Wars: Kubernetes 1.0, CNCF, and the Fight for Orchestration (2014–2016)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-container-wars-cncf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1644</post-id>	</item>
		<item>
		<title>The Borg Legacy: How Google Built the Blueprint for Kubernetes (2003–2014)</title>
		<link>https://linuxcent.com/kubernetes-history-borg-legacy/</link>
					<comments>https://linuxcent.com/kubernetes-history-borg-legacy/#respond</comments>
		
		<dc:creator><![CDATA[Vamshi Krishna Santhapuri]]></dc:creator>
		<pubDate>Wed, 04 Mar 2026 19:30:11 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[Container Orchestration]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Google Borg]]></category>
		<category><![CDATA[Kubernetes History]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://linuxcent.com/kubernetes-history-borg-legacy/</guid>

					<description><![CDATA[<p><span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 5</span> <span class="rt-label rt-postfix">minutes</span></span>Kubernetes didn't emerge from a whiteboard — it was rebuilt from Google's Borg. Trace the 2003–2014 lineage: cgroups, containers, and the design decisions that became k8s.</p>
<p>The post <a href="https://linuxcent.com/kubernetes-history-borg-legacy/">The Borg Legacy: How Google Built the Blueprint for Kubernetes (2003–2014)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></description>
										<content:encoded><![CDATA[<span class="span-reading-time rt-reading-time" style="display: block;"><span class="rt-label rt-prefix">Reading Time: </span> <span class="rt-time"> 5</span> <span class="rt-label rt-postfix">minutes</span></span><style>
pre{position:relative;background:#1e1e1e;color:#d4d4d4;<br />
    padding:16px 16px 16px 20px;border-radius:6px;overflow-x:auto;<br />
    font-family:'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace;<br />
    font-size:.88em;line-height:1.6;border-left:4px solid #555}<br />
code{background:#f4f4f4;padding:2px 5px;border-radius:3px;font-size:.9em}<br />
pre code{background:transparent;padding:0;color:inherit}<br />
pre[data-lang="bash"],pre[data-lang="sh"],<br />
pre[data-lang="shell"],pre[data-lang="zsh"]{border-left-color:#4ec9b0}<br />
pre[data-lang="yaml"],pre[data-lang="json"],<br />
pre[data-lang="toml"],pre[data-lang="xml"]{border-left-color:#569cd6}<br />
pre[data-lang="python"],pre[data-lang="go"],pre[data-lang="rust"],<br />
pre[data-lang="java"],pre[data-lang="c"],pre[data-lang="cpp"]{border-left-color:#c586c0}<br />
pre[data-lang="text"],pre[data-lang="output"],<br />
pre[data-lang="console"]{border-left-color:#888}<br />
.lc-copy-btn{position:absolute;top:8px;right:8px;background:#2d2d2d;color:#ccc;<br />
    border:1px solid #444;border-radius:4px;padding:3px 9px;font-size:.75em;<br />
    font-family:system-ui,sans-serif;cursor:pointer;opacity:0;<br />
    transition:opacity .15s,background .15s;line-height:1.6}<br />
pre:hover .lc-copy-btn{opacity:1}<br />
.lc-copy-btn:hover{background:#3a3a3a;color:#fff}<br />
.lc-copy-btn.copied{color:#4ec9b0;border-color:#4ec9b0}<br />
.lc-lang-badge{position:absolute;top:8px;left:20px;font-family:system-ui,sans-serif;<br />
    font-size:.7em;color:#666;text-transform:uppercase;letter-spacing:.04em;<br />
    line-height:1;pointer-events:none;opacity:0;transition:opacity .15s}<br />
pre:hover .lc-lang-badge{opacity:1}<br />
table{border-collapse:collapse;width:100%;margin:16px 0}<br />
th,td{border:1px solid #ddd;padding:10px 14px;text-align:left}<br />
th{background:#f0f0f0;font-weight:600}<br />
tr:nth-child(even){background:#fafafa}<br />
</style>
<p><script>
(function(){
  if(window.__lcCodeEnhanced)return;
  window.__lcCodeEnhanced=true;
  function enhance(){
    document.querySelectorAll('pre').forEach(function(pre){
      var code=pre.querySelector('code');
      var lang='';
      if(code){var m=(code.className||'').match(/language-(\S+)/);if(m)lang=m[1].toLowerCase();}
      if(lang)pre.setAttribute('data-lang',lang);
      if(lang){var badge=document.createElement('span');badge.className='lc-lang-badge';badge.textContent=lang;pre.insertBefore(badge,pre.firstChild);}
      var btn=document.createElement('button');
      btn.className='lc-copy-btn';btn.textContent='Copy';btn.setAttribute('aria-label','Copy code to clipboard');
      pre.appendChild(btn);
      btn.addEventListener('click',function(){
        var text=code?code.innerText:pre.innerText;
        if(navigator.clipboard&&window.isSecureContext){
          navigator.clipboard.writeText(text).then(function(){ok(btn);}).catch(function(){fb(text,btn);});
        }else{fb(text,btn);}
      });
    });
  }
  function ok(btn){btn.textContent='Copied!';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},2000);}
  function fb(text,btn){
    try{var ta=document.createElement('textarea');ta.value=text;ta.style.cssText='position:fixed;left:-9999px;top:-9999px;opacity:0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);ok(btn);}
    catch(e){btn.textContent='✗ Failed';setTimeout(function(){btn.textContent='Copy';},2000);}
  }
  if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',enhance);}else{enhance();}
})();
</script></p>
<hr />
<h2 id="introduction">Introduction</h2>
<p>Every piece of infrastructure has a lineage. Kubernetes didn&#8217;t appear from nowhere in 2014. It is, in almost every meaningful sense, Google&#8217;s Borg system rebuilt for the world — with a decade of hard lessons baked in.</p>
<p>To understand Kubernetes, you have to understand what came before it. And what came before it ran (and still runs) more compute than most organizations will ever touch.</p>
<hr />
<h2 id="googles-scale-problem-2003">Google&#8217;s Scale Problem (2003)</h2>
<p>By the early 2000s, Google was running hundreds of thousands of jobs across tens of thousands of machines. Web indexing, ads, Gmail, Maps — all of these needed compute, and none of them could afford to waste it.</p>
<p>In 2003-2004, Google engineer Rohit Seth proposed a kernel feature called <strong>cgroups</strong> (control groups) — a mechanism to limit, prioritize, account, and isolate resource usage of process groups. The Linux kernel merged cgroups in 2.6.24 (2008). This was the primitive that would later make containers possible.</p>
<p>Simultaneously, Google built <strong>Borg</strong> — an internal cluster management system that could run hundreds of thousands of jobs, from many thousands of different applications, across many clusters, with each cluster having up to tens of thousands of machines. Borg was never open-sourced. It ran (and still runs) Google&#8217;s entire production workload.</p>
<hr />
<h2 id="what-borg-got-right">What Borg Got Right</h2>
<p>Borg introduced concepts that engineers didn&#8217;t yet have names for. They became the vocabulary of modern infrastructure:</p>
<p><strong>Workload types:</strong><br />
Borg separated workloads into two classes: long-running services (high-priority, latency-sensitive) and batch jobs (best-effort, preemptible). Kubernetes would later call these Deployments and Jobs.</p>
<p><strong>Declarative specification:</strong><br />
Borg jobs were described in a configuration language (BCL, a dialect of GCL). You declared what you wanted; Borg figured out how to achieve it. Sound familiar?</p>
<p><strong>Resource limits and requests:</strong><br />
Borg tasks had both a request (what you need) and a limit (what you can use). Kubernetes adopted this model directly — <code class="" data-line="">resources.requests</code> and <code class="" data-line="">resources.limits</code> in pod specs trace directly back to Borg.</p>
<p><strong>Health checking and rescheduling:</strong><br />
Borg monitored task health and automatically rescheduled failed tasks. The kubelet&#8217;s liveness and readiness probes are descendants of this.</p>
<p><strong>Cell (cluster) topology:</strong><br />
Borg organized machines into &#8220;cells&#8221; — what Kubernetes calls clusters. The Borgmaster (control plane) managed the cell.</p>
<hr />
<h2 id="omega-the-sequel-that-didnt-ship">Omega: The Sequel That Didn&#8217;t Ship</h2>
<p>Around 2011, Google started building <strong>Omega</strong> — a more flexible scheduler designed to address Borg&#8217;s limitations. Borg had a monolithic scheduler; Omega introduced a shared-state, optimistic-concurrency model where multiple schedulers could operate concurrently without stepping on each other.</p>
<p>A 2013 paper from Google (&#8220;Omega: flexible, scalable schedulers for large compute clusters&#8221;) made these ideas public. Omega itself stayed internal, but many of its scheduling concepts influenced Kubernetes&#8217; extensible scheduler design.</p>
<hr />
<h2 id="the-docker-moment-march-2013">The Docker Moment (March 2013)</h2>
<p>On March 15, 2013, Solomon Hykes stood at PyCon and demonstrated Docker with a five-minute talk titled &#8220;The future of Linux Containers.&#8221; The demo ran a container. That was it. The room understood immediately.</p>
<p>Docker solved the packaging and distribution problem. Linux had had containers (via LXC and cgroups/namespaces) for years, but running one required deep kernel knowledge. Docker wrapped all of that in a UX that a developer could actually use.</p>
<p>Google&#8217;s engineers watched. They recognized the pattern: Docker was doing for containers what the smartphone did for mobile computing — making an existing capability accessible to everyone.</p>
<p>The Google engineers building the next generation of infrastructure realized: once containers become ubiquitous, someone will need to orchestrate them at scale. And they had already built that system internally, twice.</p>
<hr />
<h2 id="the-decision-to-open-source-fall-2013">The Decision to Open-Source (Fall 2013)</h2>
<p>In late 2013, a small group of Google engineers — Brendan Burns, Joe Beda, Craig McLuckie, Ville Aikas, Tim Hockin, Dawn Chen, Brian Grant, and Daniel Smith — began a new project internally codenamed &#8220;Project Seven&#8221; (a reference to the Borg drone Seven of Nine).</p>
<p>The core insight: Google&#8217;s competitive advantage in infrastructure came from <em>what ran on</em> the cluster management system, not the system itself. Open-sourcing a Kubernetes-like system would benefit Google by standardizing the ecosystem around patterns Google already understood better than anyone.</p>
<p>The initial design decisions were deliberate:</p>
<ul>
<li><strong>Go as the implementation language:</strong> Fast compilation, good concurrency primitives, easy deployment as static binaries</li>
<li><strong>REST API as the primary interface:</strong> Everything in Kubernetes is an API resource. This is not accidental — it makes the system composable and automatable from day one</li>
<li><strong>Labels and selectors over hierarchical naming:</strong> Borg used a hierarchical job/task naming scheme; Kubernetes chose a flat namespace with label-based grouping, which proved far more flexible</li>
<li><strong>Reconciliation loops everywhere:</strong> Every Kubernetes controller is a loop that watches actual state and drives it toward desired state. This is the controller pattern, and it is the heart of Kubernetes extensibility</li>
</ul>
<hr />
<h2 id="first-commit-june-6-2014">First Commit: June 6, 2014</h2>
<p>The first public commit landed on GitHub on June 6, 2014: 250 files, 47,501 lines of Go, Bash, and Markdown.</p>
<p>Three days later, on June 10, 2014, Eric Brewer (VP of Infrastructure at Google) announced Kubernetes publicly at DockerCon 2014. The announcement framed it explicitly as bringing Google&#8217;s infrastructure learnings to the community.</p>
<p>By July 10, 2014, Microsoft, Red Hat, IBM, and Docker had joined the contributor community.</p>
<hr />
<h2 id="what-kubernetes-deliberately-left-out-of-borg">What Kubernetes Deliberately Left Out of Borg</h2>
<p>The designers made intentional decisions about what <em>not</em> to carry forward:</p>
<p><strong>No proprietary language:</strong> Borg&#8217;s BCL/GCL was Google-internal. Kubernetes used plain JSON (later YAML) manifests — standard formats any tool could read and write.</p>
<p><strong>No magic autoscaling by default:</strong> Borg aggressively reclaimed resources. Kubernetes launched without this, adding HPA (Horizontal Pod Autoscaler) later, allowing operators to control the behavior.</p>
<p><strong>No built-in service discovery tied to the scheduler:</strong> Borg had tight coupling between scheduling and name resolution. Kubernetes separated these: Services (kube-proxy, DNS) are distinct from the scheduler, allowing them to evolve independently.</p>
<hr />
<h2 id="the-borg-paper-2015">The Borg Paper (2015)</h2>
<p>In April 2015, Google published &#8220;Large-scale cluster management at Google with Borg&#8221; — the first public detailed description of the system. Reading it alongside the Kubernetes documentation reveals how directly the design decisions transferred.</p>
<p>Key numbers from the paper:<br />
&#8211; Borg ran hundreds of thousands of jobs from thousands of applications<br />
&#8211; Typical cell: 10,000 machines<br />
&#8211; Utilization improvements from bin-packing: significant enough to justify the entire engineering investment</p>
<p>The paper is required reading for anyone who wants to understand why Kubernetes is designed the way it is — not as a series of arbitrary choices but as a deliberately evolved system.</p>
<hr />
<h2 id="the-lineage-that-matters-for-security">The Lineage That Matters for Security</h2>
<p>From a security architecture perspective, the Borg lineage matters because the isolation model was designed for a trusted-internal environment, not a multi-tenant hostile-external one. This created a debt that Kubernetes has spent years paying down:</p>
<ul>
<li><strong>Namespaces</strong> are a soft boundary, not a hard isolation primitive — just as Borg&#8217;s cells were</li>
<li><strong>The default-allow network model</strong> reflects Borg&#8217;s assumption of a trusted internal network</li>
<li><strong>No built-in admission control at launch</strong> — Borg trusted its job submitters</li>
</ul>
<p>Understanding this history explains why features like NetworkPolicy, PodSecurity, RBAC, and OPA/Gatekeeper were retrofitted over years rather than built-in from day one. The system was designed by and for Google&#8217;s internal trust model. The security hardening came as it entered the wild.</p>
<hr />
<h2 id="key-takeaways">Key Takeaways</h2>
<ul>
<li>Kubernetes is Google&#8217;s Borg system rebuilt for the world, carrying 10+ years of cluster management experience</li>
<li>Core Kubernetes primitives — resource requests/limits, declarative specs, health-based rescheduling, label-based grouping — map directly to Borg concepts</li>
<li>The decision to open-source was strategic, not altruistic: Google wanted to standardize the ecosystem on patterns it already mastered</li>
<li>The security gaps in early Kubernetes (no default network isolation, permissive RBAC, no pod-level security controls) trace directly to Borg&#8217;s trusted-internal-network assumptions</li>
<li>Docker&#8217;s accessibility breakthrough created the demand; Google&#8217;s Borg experience supplied the architecture</li>
</ul>
<hr />
<h2 id="whats-next">What&#8217;s Next</h2>
<p><a href="ep02-container-wars.md">EP02: The Container Wars →</a> — Kubernetes 1.0, the CNCF formation, and the three-way fight between Docker Swarm, Apache Mesos, and Kubernetes for control of the container orchestration market.</p>
<hr />
<p><em>Series: Kubernetes: From Borg to Platform Engineering | linuxcent.com</em></p>
<p><a class="a2a_button_mastodon" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="Mastodon" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_email" href="https://www.addtoany.com/add_to/email?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="Email" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_whatsapp" href="https://www.addtoany.com/add_to/whatsapp?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="WhatsApp" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_reddit" href="https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="Reddit" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_copy_link" href="https://www.addtoany.com/add_to/copy_link?linkurl=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&amp;linkname=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" title="Copy Link" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Flinuxcent.com%2Fkubernetes-history-borg-legacy%2F&#038;title=The%20Borg%20Legacy%3A%20How%20Google%20Built%20the%20Blueprint%20for%20Kubernetes%20%282003%E2%80%932014%29" data-a2a-url="https://linuxcent.com/kubernetes-history-borg-legacy/" data-a2a-title="The Borg Legacy: How Google Built the Blueprint for Kubernetes (2003–2014)"></a></p><p>The post <a href="https://linuxcent.com/kubernetes-history-borg-legacy/">The Borg Legacy: How Google Built the Blueprint for Kubernetes (2003–2014)</a> appeared first on <a href="https://linuxcent.com">Linuxcent</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxcent.com/kubernetes-history-borg-legacy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1641</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: linuxcent.com @ 2026-08-25 07:08:35 by W3 Total Cache
-->