{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/so-about-that-docker-swarm-post-i-moved-to-k3s/",
    "result": {"data":{"site":{"siteMetadata":{"title":"catch { snail }","author":"Andrew"}},"markdownRemark":{"id":"3c4b6f49-35c9-5934-8419-3cd4bf9126d3","excerpt":"Last November I wrote a guide on configuring Docker Swarm. Two weeks later, Mirantis bought Docker’s enterprise business and gave Swarm what sounded like a two…","html":"<p>Last November I wrote a guide on <a href=\"/configure-docker-swarm\">configuring Docker Swarm</a>. Two weeks later, Mirantis bought Docker’s enterprise business and gave Swarm what sounded like a two-year countdown. They’ve since softened that to “we’ll keep supporting it,” but the writing is on the wall, and the wall is written in YAML.</p>\n<p>So this summer I finally did the thing I’d been avoiding since 2017: I learned Kubernetes properly. The trick that made it not miserable is that I didn’t install Kubernetes. I installed <strong>k3s</strong>.</p>\n<h2 id=\"k3s-kubernetes-without-the-ceremony\" style=\"position:relative;\"><a href=\"#k3s-kubernetes-without-the-ceremony\" aria-label=\"k3s kubernetes without the ceremony permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>k3s: Kubernetes without the ceremony</h2>\n<p>Rancher’s k3s is a certified Kubernetes distribution compressed into a single ~50MB binary. It swaps etcd for SQLite, strips the legacy cloud-provider baggage, and ships batteries included (Traefik as ingress, out of the box). Install is genuinely this:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">curl</span> -sfL https://get.k3s.io <span class=\"token operator\">|</span> <span class=\"token function\">sh</span> -\n<span class=\"token function\">sudo</span> k3s kubectl get <span class=\"token function\">node</span></code></pre></div>\n<p>Thirty seconds later there’s a working single-node “cluster” on my €5 Hetzner VPS, idling at around 500MB of RAM. That’s the entire moat between “Kubernetes is for companies with a platform team” and “Kubernetes runs my hobby junk” — and it turns out the moat was just packaging.</p>\n<h2 id=\"the-migration\" style=\"position:relative;\"><a href=\"#the-migration\" aria-label=\"the migration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The migration</h2>\n<p>My Swarm stack was this blog, a couple of side projects, and — because the theme of this year apparently insists — the <a href=\"/commit-message-driven-development\">GPT-2 commit-message server</a> from April, still faithfully dealing me chores every morning.</p>\n<p><code class=\"language-text\">kompose</code> will mechanically convert a compose file into manifests, but I recommend writing them by hand at least once, because the pain is educational. A Swarm service becomes three objects: a <strong>Deployment</strong> (what to run), a <strong>Service</strong> (how to reach it), an <strong>Ingress</strong> (how the outside reaches the Service). Add cert-manager and Let’s Encrypt certificates become just another object the cluster keeps renewed for me — the first moment where the K8s way felt <em>better</em> rather than merely fancier.</p>\n<p>Lessons collected the honest way:</p>\n<ul>\n<li><strong>Set resource limits immediately.</strong> The GPT-2 pod happily ate the whole node until the OOM killer introduced itself. <code class=\"language-text\">resources.limits.memory: 900Mi</code> and we’re friends again.</li>\n<li>The Traefik v1 that ships with current k3s reads standard Ingress objects fine; ignore old tutorials full of custom annotations.</li>\n<li>Helm 3 (tiller is gone, good riddance) for other people’s software, plain manifests in git for mine.</li>\n<li>You will write a stupid amount of YAML. There’s no enlightenment coming on this one; buy a better keyboard.</li>\n</ul>\n<h2 id=\"the-part-where-it-finally-clicked\" style=\"position:relative;\"><a href=\"#the-part-where-it-finally-clicked\" aria-label=\"the part where it finally clicked permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The part where it finally clicked</h2>\n<p>Here’s the mental model I wish someone had led with, instead of diagrams of pods.</p>\n<p>Swarm — and honestly most of the tools I grew up on — is <strong>imperative</strong>: you issue commands, it executes them, done. <code class=\"language-text\">docker service scale web=3</code> is an <em>action</em>.</p>\n<p>Kubernetes is not an orchestrator that runs your commands. It’s a <strong>database of desired state with robots attached</strong>. You write down a fact you’d like to be true — “three replicas of this exist, reachable at this name, with valid TLS” — and control loops compare that desire to reality, forever, and push reality toward it. Node dies at 3am? Reality drifted from the spec; the loop corrects it. Nobody, including you, issued a command.</p>\n<p>You don’t tell Kubernetes what to <em>do</em>. You tell it what should be <em>true</em>.</p>\n<p>And I can’t stop noticing that this is the same shape as my complaint about language models this spring — that GPT-2 executes text-continuation without any notion of your <em>intent</em>, and that the missing piece is a system trained to pursue what you meant. Kubernetes is what it looks like when infrastructure makes that leap: from “execute my steps” to “converge on my intent.” Declarative beats imperative for the same reason in both worlds — steps go stale, intent doesn’t. Apparently 2020 is the year I learn this lesson once per quarter in a different domain.</p>\n<h2 id=\"do-you-need-this\" style=\"position:relative;\"><a href=\"#do-you-need-this\" aria-label=\"do you need this permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Do you need this?</h2>\n<p>No. Let’s be adults: for one VPS of hobby projects, docker-compose plus a systemd unit is fewer moving parts and I’d defend that choice in court. I did it because Swarm’s future is cloudy, because the industry has voted and K8s won, and because the reconciliation-loop model is the actually transferable knowledge — it’s the same idea underneath Terraform, GitOps, and every “controller” you’ll meet for the next decade.</p>\n<p>But I’ll admit the real reason: there is something deeply pleasing about a server that repairs itself while I sleep. The commit-message bot went down twice this month. Both times, by the time the uptime alert reached my phone, the pod had already been rescheduled and the alert resolved itself.</p>\n<p>The robot assigns me chores, and other robots keep the robot alive. The system works.</p>","frontmatter":{"title":"So about that Docker Swarm post: I moved to k3s","date":"August 15, 2020","description":"Migrating my little stack from Swarm to lightweight Kubernetes, and the mental model that finally made K8s click"}}},"pageContext":{"slug":"/so-about-that-docker-swarm-post-i-moved-to-k3s/","previous":{"fields":{"slug":"/gpt-3-my-fine-tuning-posts-might-already-be-obsolete/"},"frontmatter":{"title":"GPT-3: my fine-tuning posts might already be obsolete"}},"next":{"fields":{"slug":"/i-ran-terraform-destroy-on-my-own-production-on-purpose/"},"frontmatter":{"title":"I ran terraform destroy on my own production (on purpose)"}}}},
    "staticQueryHashes": ["3435731857","426816048","63159454"]}