<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Architecture on Tom Meurs</title>
    <link>https://tommeurs.nl/en/tags/architecture/</link>
    <description>Recent content in Architecture on Tom Meurs</description>
    <generator>Hugo</generator>
    <language>en</language>
    <copyright>© Tom Meurs</copyright>
    <lastBuildDate>Wed, 23 Sep 2026 19:00:00 +0200</lastBuildDate>
    <atom:link href="https://tommeurs.nl/en/tags/architecture/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Your Dependency&#39;s Business Model Is Part of Your Threat Model</title>
      <link>https://tommeurs.nl/en/posts/license-change-supply-chain-risk/</link>
      <pubDate>Wed, 23 Sep 2026 19:00:00 +0200</pubDate>
      <guid>https://tommeurs.nl/en/posts/license-change-supply-chain-risk/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; A vendor freezing its free edition belongs in your risk register next to the expiring certificate. Thirty-six dated cases below, three kinds of event, and five questions to score your own stack. My own register had the Vault row missing for three years.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;On 11 September, Portainer&amp;rsquo;s CEO published &lt;a href=&#34;https://www.portainer.io/blog/portainer-3-0-is-coming&#34;&gt;&amp;ldquo;Portainer 3.0 is coming, and here&amp;rsquo;s what it means for you&amp;rdquo;&lt;/a&gt;. I read it the Monday after and shrugged.&lt;/p&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s what it says. 3.0 is a Kubernetes-first codebase for enterprise customers, and &amp;ldquo;we are not cutting a separate CE build of it&amp;rdquo;. Community Edition stays on 2.x. 2.45 LTS &amp;ldquo;is the last release in the 2.x line&amp;rdquo;. A few days later they added a clarification: 2.45 keeps getting security fixes, bug fixes and back-ports of any 3.x feature that has a Docker API equivalent, &amp;ldquo;for as long as that LTS is supported&amp;rdquo;. The &lt;a href=&#34;https://docs.portainer.io/start/lifecycle&#34;&gt;lifecycle page&lt;/a&gt; puts that at May 2027. Want 3.x for free? There&amp;rsquo;s a Business Edition key called &lt;a href=&#34;https://www.portainer.io/take-3&#34;&gt;3 Nodes Free&lt;/a&gt;, one per organisation.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Longhorn vs Rook-Ceph: Kubernetes Storage Compared</title>
      <link>https://tommeurs.nl/en/posts/longhorn-vs-rook-ceph/</link>
      <pubDate>Mon, 20 Apr 2026 19:38:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/longhorn-vs-rook-ceph/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Longhorn and Rook-Ceph both give you replicated block storage that survives a node dying. Longhorn is one Helm install and a UI that shows you what a volume is doing. Rook-Ceph is Ceph with a Kubernetes operator around it, so you get block, object and filesystem storage, and the operations that come with them. I run Longhorn on three nodes. Below is why, and when I&amp;rsquo;d switch.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Run your first stateful workload on a self-hosted cluster and you find out fast that nobody hands out PersistentVolumes for free. There&amp;rsquo;s no cloud provider storage class to lean on. You&amp;rsquo;ve got your nodes, their disks, and a Postgres pod that won&amp;rsquo;t schedule. An hour of reading later you&amp;rsquo;re left with two names that keep coming up. &lt;span class=&#34;def&#34; tabindex=&#34;0&#34; data-def=&#34;Block storage for Kubernetes that replicates a volume across nodes. Simple to run and slower than Ceph, which is the trade it makes on purpose.&#34;&gt;Longhorn&lt;/span&gt;&#xA; and Rook-&lt;span class=&#34;def&#34; tabindex=&#34;0&#34; data-def=&#34;A distributed storage system that serves block, file and object from one cluster. Powerful, and heavy enough that running it is a job rather than a setting.&#34;&gt;Ceph&lt;/span&gt;&#xA;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Loki for Kubernetes Logging: The Prometheus-Like Approach</title>
      <link>https://tommeurs.nl/en/posts/loki-kubernetes-logging/</link>
      <pubDate>Tue, 31 Mar 2026 21:15:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/loki-kubernetes-logging/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Loki indexes labels and stores the log text as compressed chunks, so a month of logs fits on commodity hardware. The trade is full-text search. Below is the single-binary install I&amp;rsquo;d hand anyone first, the same chart on MinIO with three replicas, and the knobs I didn&amp;rsquo;t touch until the volume was real.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;You&amp;rsquo;ve got &lt;a href=&#34;https://tommeurs.nl/en/posts/prometheus-thanos-metrics/&#34;&gt;Prometheus for metrics&lt;/a&gt;, so you can already see what&amp;rsquo;s happening across your clusters. Metrics tell you request latency spiked at 14:32. They don&amp;rsquo;t tell you the payment service threw a null pointer because someone shipped a config change with a typo. For that you need the log line.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Thanos Remote Write: Push-Based Metrics for Edge and Multi-Cluster</title>
      <link>https://tommeurs.nl/en/posts/thanos-remote-write-push-architecture/</link>
      <pubDate>Fri, 27 Mar 2026 20:38:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/thanos-remote-write-push-architecture/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Thanos Receive turns the metrics flow around. Each edge Prometheus pushes samples over &lt;code&gt;remote_write&lt;/code&gt; to one central endpoint, buffers in its WAL when the link drops, and never sees an object storage credential. Below is the Receive StatefulSet, the hashring, the edge config, two ways to lock the endpoint down, and the hybrid I run with sidecars on the core clusters.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In my &lt;a href=&#34;https://tommeurs.nl/en/posts/prometheus-thanos-metrics/&#34;&gt;previous post on Prometheus and Thanos&lt;/a&gt;, I set up the sidecar architecture. &lt;span class=&#34;def&#34; tabindex=&#34;0&#34; data-def=&#34;Gives Prometheus long-term storage in object storage and one query view across several Prometheus servers, without changing how Prometheus scrapes.&#34;&gt;Thanos&lt;/span&gt;&#xA; Sidecar runs next to Prometheus, uploads TSDB blocks to object storage, and exposes the data to the Querier over gRPC. For clusters in the same datacenter with a fat, stable link to the central infrastructure, I&amp;rsquo;ve got no complaints. Everything pulls, and everything can reach everything else.&lt;/p&gt;</description>
    </item>
    <item>
      <title>When not to use Kubernetes</title>
      <link>https://tommeurs.nl/en/posts/when-not-to-use-kubernetes/</link>
      <pubDate>Sat, 17 Jan 2026 10:00:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/when-not-to-use-kubernetes/</guid>
      <description>&lt;p&gt;I write a lot about Kubernetes, and I run it at home every day. I like it.&lt;/p&gt;&#xA;&lt;p&gt;So it might surprise you that I spend a fair amount of my time talking people out of it.&lt;/p&gt;&#xA;&lt;p&gt;The situation I keep walking into goes like this. A small team, one product, a roadmap full of features customers are waiting for, and someone has decided the first milestone is a Kubernetes cluster. Three nodes minimum, etcd, a &lt;span class=&#34;def&#34; tabindex=&#34;0&#34; data-def=&#34;Container Network Interface: the plugin contract Kubernetes uses to give a pod its network. Cilium, Calico and Flannel are implementations of it.&#34;&gt;CNI&lt;/span&gt;&#xA;, an ingress controller, cert-manager, a monitoring stack. Weeks of work before a single customer sees anything. Everyone nods along, because that&amp;rsquo;s what a serious setup is supposed to look like.&lt;/p&gt;</description>
    </item>
    <item>
      <title>App-of-Apps Pattern in ArgoCD: Scalable GitOps Architecture</title>
      <link>https://tommeurs.nl/en/posts/argocd-app-of-apps/</link>
      <pubDate>Mon, 21 Apr 2025 20:18:00 +0200</pubDate>
      <guid>https://tommeurs.nl/en/posts/argocd-app-of-apps/</guid>
      <description>&lt;p&gt;My homelab started with one ArgoCD Application. Then a handful. The day I caught myself running &lt;code&gt;kubectl apply -f&lt;/code&gt; for the fifteenth time to register yet another Application, I knew I&amp;rsquo;d built the exact thing I was trying to avoid: manual steps I had to remember, in an order I had to remember, with no record of what should exist.&lt;/p&gt;&#xA;&lt;p&gt;The App-of-Apps pattern fixes that with one idea. You create a single root Application by hand, and it creates everything else. After a cluster wipe I can rebuild the whole thing with one &lt;code&gt;kubectl apply&lt;/code&gt;. That property is the entire reason I run it, and it&amp;rsquo;s the same reason I self-host in the first place: I want the repository to be the truth, not my memory.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD vs Flux: When to Choose What</title>
      <link>https://tommeurs.nl/en/posts/argocd-vs-flux/</link>
      <pubDate>Fri, 28 Mar 2025 21:33:00 +0200</pubDate>
      <guid>https://tommeurs.nl/en/posts/argocd-vs-flux/</guid>
      <description>&lt;p&gt;&amp;ldquo;Should I use ArgoCD or &lt;span class=&#34;def&#34; tabindex=&#34;0&#34; data-def=&#34;The other GitOps engine next to ArgoCD. Controllers in the cluster reconcile from Git with no UI of its own, where ArgoCD leads with one.&#34;&gt;Flux&lt;/span&gt;&#xA;?&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;I get this question over coffee, in Slack, in PR comments, probably once a week. People want me to declare a winner so they can stop thinking about it and go build something.&lt;/p&gt;&#xA;&lt;p&gt;Here is my bias, up front, so you can weigh everything that follows: I run ArgoCD on my own clusters. I have a few years of it under my belt and I like it. That preference is going to leak through no matter how careful I am, so I am telling you now instead of pretending I am neutral.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Running Kubernetes Offline: Edge Computing Without Internet</title>
      <link>https://tommeurs.nl/en/posts/kubernetes-offline-edge/</link>
      <pubDate>Tue, 04 Mar 2025 20:47:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/kubernetes-offline-edge/</guid>
      <description>&lt;p&gt;What happens when your Kubernetes cluster can&amp;rsquo;t reach the internet? I don&amp;rsquo;t mean a slow connection. I mean no connection at all. Ships at sea. Remote mining sites. Factory floors with air-gapped networks. Military deployments.&lt;/p&gt;&#xA;&lt;p&gt;For a lot of people that sounds exotic, like a problem someone else has. I treat it as a baseline design requirement, and I&amp;rsquo;ll explain why it makes my homelab better even though I almost never actually pull the cable.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Graceful Degradation in Kubernetes: What Happens When Components Fail</title>
      <link>https://tommeurs.nl/en/posts/kubernetes-graceful-degradation/</link>
      <pubDate>Thu, 20 Feb 2025 14:22:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/kubernetes-graceful-degradation/</guid>
      <description>&lt;p&gt;Everyone repeats the line that Kubernetes is self-healing. Pods die, they come back. Nodes drop, workloads reschedule. The system reconciles itself toward the state you declared, and most days you never have to think about it.&lt;/p&gt;&#xA;&lt;p&gt;Then one day the thing doing the healing is the thing that broke. The API server is down. etcd won&amp;rsquo;t respond. The scheduler is wedged. Now what?&lt;/p&gt;&#xA;&lt;p&gt;This is the question I actually care about, because &amp;ldquo;self-healing&amp;rdquo; is only useful if I understand its edges. I want to know what degrades gracefully and what takes the whole cluster with it. So I&amp;rsquo;ve run my clusters through a lot of failures on purpose: planned, unplanned, and a few &amp;ldquo;hold my beer&amp;rdquo; experiments on hardware I didn&amp;rsquo;t mind losing. Here is what actually happens when each piece breaks, and why most of it matters less than people fear.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How etcd Actually Works: The Heart of Your Kubernetes Cluster</title>
      <link>https://tommeurs.nl/en/posts/etcd-deep-dive/</link>
      <pubDate>Mon, 27 Jan 2025 21:47:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/etcd-deep-dive/</guid>
      <description>&lt;p&gt;When something goes wrong in Kubernetes, the trail usually leads back to etcd. API server timing out? Check etcd. Pods stuck in pending? Might be etcd. Cluster feels sluggish? Probably etcd.&lt;/p&gt;&#xA;&lt;p&gt;For a long time I treated etcd the way most operators do: as a black box that hums along next to the control plane. &amp;ldquo;The database.&amp;rdquo; You back it up and otherwise leave it alone. But black boxes feel like splinters to me, and the first time an etcd cluster fell over at 2am I realised I had no idea what I was actually looking at. So I learned. And it turns out the whole thing is built on a handful of ideas that, once they click, make most etcd problems diagnosable instead of terrifying.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes High Availability: Stacked vs External etcd Explained</title>
      <link>https://tommeurs.nl/en/posts/kubernetes-high-availability-etcd/</link>
      <pubDate>Wed, 15 Jan 2025 20:23:00 +0100</pubDate>
      <guid>https://tommeurs.nl/en/posts/kubernetes-high-availability-etcd/</guid>
      <description>&lt;p&gt;The first &amp;ldquo;production&amp;rdquo; Kubernetes cluster I ran had a single control plane node. It hummed along happily for weeks, right up until a disk failed and took the whole thing with it. Every pod, every service, gone. That outage taught me what &amp;ldquo;single point of failure&amp;rdquo; actually feels like, and it pushed me toward a question that I keep seeing trip people up: when you build a cluster that survives node loss, do you run etcd on your control plane nodes, or on dedicated nodes of its own?&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
