Advanced Search
Search Results
190 total results found
Lessons on lab storage
Pick storage per workload. Shared app data → NFS. Databases → local disk on their own VM. One size does not fit all. NFSv4, single port, subnet-scoped. Smallest firewall footprint, simplest mental model. A default StorageClass keeps manifests clean. Apps shou...
The bare-metal LoadBalancer problem
Ask Kubernetes for a Service of type LoadBalancer in the cloud and you get a real load balancer with a real IP, because the cloud provider has a controller watching for exactly that. On bare metal — a home lab — nobody's listening. The service just sits there ...
MetalLB in L2 mode
MetalLB has two modes: BGP (it speaks routing protocols to your network gear) and L2 (it answers ARP for the service IPs). For a flat single-subnet lab, L2 is the obvious pick — no router configuration, it just works on the local network. The config is two sma...
Why an API gateway, not just an ingress
Once you can get an external IP, you need something to route HTTP to the right app and, ideally, to add the cross-cutting concerns every API needs — auth, rate limiting, request shaping. A plain ingress controller (like ingress-nginx) does routing well. An API...
Kong, backed by PostgreSQL
Kong can run config-only ("DB-less") or backed by a database. I chose DB-backed, against the existing PostgreSQL server, for two reasons: it exercises the database layer the lab already has, and it's the mode that supports runtime configuration and the admin w...
Securing the admin surface (the loopback trick)
Kong's Admin API is powerful — it can reconfigure the whole gateway — and the open-source edition has no built-in authentication on it (that's a paid feature). So you must not expose it casually. Two honest options: Leave it internal. The ingress controller t...
TLS lives at the edge, not in the gateway
A natural instinct is to give Kong a certificate and let it serve HTTPS. I did that first — and then remembered the lab already terminates TLS at the edge (pfSense/HAProxy, with a wildcard cert). Doing it in both places is redundant and causes a redirect loop:...
The build half of the platform
A cluster runs containers; it doesn't build them. Something has to turn a git push into an image sitting in a registry, ready to deploy. That's CI/CD, and in this lab it's two pieces working together: git push -> Gitea (git.example.com) ...
The Gitea Actions runner
Gitea ships a CI system that speaks the same workflow syntax as GitHub Actions. To actually run jobs you register a runner — and that's a dedicated VM here (GIT-Runner, 10.100.100.11). Why a separate VM rather than running builds in the cluster? Builds are bur...
Docker-out-of-Docker, and custom job images
Jobs run inside containers, but the jobs themselves need to build containers. The classic tangle is "Docker inside Docker." The cleaner approach used here is Docker-out-of-Docker: the runner mounts the host's Docker socket into the job container, so docker bui...
Pulling private images (the bit people trip on)
Here's a subtle thing. Those custom job images live in the private registry, which requires authentication. So how does the runner pull them? It doesn't do anything special — it asks the host's Docker engine to pull, and Docker uses the credentials in the runn...
A pipeline, end to end
A workflow file in a repo (.gitea/workflows/build.yml) is all it takes. Because the job image already has the tools, the workflow is short: name: build on: { push: { branches: [main] } } jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions...
Lessons on the build pipeline
Give builds their own box. Bursty, disk-heavy, sometimes privileged — you don't want that sharing fate with your cluster workloads. Docker-out-of-Docker over Docker-in-Docker. Mount the socket; skip the privileged nested daemon. Bake a real job image. Tools-i...
Three databases, on purpose
The platform runs three relational databases — PostgreSQL (10.100.100.13), MariaDB (10.100.100.14), and MySQL (10.100.100.15) — each on its own VM, each on local disk, not on the cluster's NFS. Why three? Because real applications disagree about what they want...
Tuning a database for the hardware it has
A freshly installed database ships with cautious, generic defaults. On a box you've sized deliberately (4 vCPU, 4 GiB RAM, SSD-backed disk), a little tuning goes a long way. The themes are the same across all three engines: Let it use the RAM. Tell the engine...
Every app gets its own credentials
This is a hard rule in the lab: no application ever connects as the database admin. Each app gets its own database, its own user, and its own password, scoped to just that database. # for an app 'foo', on PostgreSQL: CREATE DATABASE foo; CREATE USER foo WITH P...
Seeing what the cluster is doing: logs to Loki
The lab already had a central log store (Loki — see its book in Core Infrastructure), with a Promtail agent on every VM shipping system logs. When the cluster arrived, the job was to feed its logs in too. On the Kubernetes nodes the node-level Promtail agent w...
Lessons on data and observability
Match storage to the workload: databases get local disk on dedicated VMs, never NFS. Tune for the box you have: give the engine the RAM, tell it the disk is SSD, log slow queries. MariaDB ≠ MySQL: running both proved it. Check settings against your actual eng...