/ Docs / 03 — Migration
Document 03 · Migration
Why Kubernetes — architecture decisions

The decisions made during the migration, why Kubernetes was chosen over simpler alternatives, and how the migration was sequenced.

Why not just Docker Compose?

Docker Compose was the obvious first step — containerise the WordPress stack, run it with Compose. Simpler, faster, fewer moving parts. So why Kubernetes instead?

ADR-001 — Use Kubernetes over Docker Compose
✓ Decided
Context: The stack needs to be containerised. Docker Compose is simpler. Kubernetes is significantly more complex but matches the commercial tooling used in professional environments.

Decision: Kubernetes. The goal is a professional portfolio, not just a running website. Kubernetes gives us rolling deployments, namespace isolation, RBAC, resource limits, health checks, and the ability to run multiple services (Redis, Tomcat, GitLab, Jenkins) on the same cluster.

Consequences: Steeper setup. MetalLB required for LoadBalancer services. Persistent storage needs more thought (PV/PVC). But every manifest is a document — the cluster is self-describing.
ADR-002 — Self-hosted homelab over managed cloud
✓ Decided
Context: EKS, GKE, AKS are all available. They handle the control plane, etcd, and upgrades automatically.

Decision: Self-hosted 3-node cluster on physical hardware. Managed K8s hides the complexity that's actually valuable to understand — kubeadm, CNI, etcd, node management. Also zero ongoing cloud cost for compute.

Consequences: Full responsibility for control plane health, upgrades, and node management. OVH VPS required as the public-facing proxy (homelab has no public IP). WireGuard tunnel for connectivity.
Migration sequence
1
Build the cluster
3-node kubeadm cluster — kube1 (control-plane), kube2, kube3 (workers). ContainerD runtime, Flannel CNI, MetalLB, NFS provisioner.
2
Containerise WordPress
WordPress + MySQL as Kubernetes Deployments in the wordpress6 namespace. MySQL on ClusterIP (internal only), WordPress on LoadBalancer via MetalLB.
3
Set up the proxy
OVH VPS running nginx as reverse proxy. WireGuard tunnel to homelab. Routes MetalLB IPs through wg0. TLS termination with Let's Encrypt.
4
Build additional services
Redis StatefulSet, Tomcat deployments (base/dev/prod), GitLab CI/CD, Jenkins, Wazuh SIEM DaemonSet. Each in its own namespace.
5
Portal + dashboard + docs
mfa2fa.com portal landing page. Live cluster dashboard in cluster-dashboard namespace. This documentation site in mfa2fa-docs namespace.
What the migration proved

The WordPress site that ran on a single VPS now runs as two pods across two worker nodes, behind a MetalLB LoadBalancer, proxied through an encrypted WireGuard tunnel, with rolling update capability and automatic restart on failure.

✓ The original site is preserved. The new infrastructure is live. The migration is documented. Anyone with a Kubernetes cluster and these docs can reproduce it from scratch.
The real value: Every service on the cluster is declarative — defined in YAML manifests, stored in GitLab, reproducible. The old VPS setup had none of that. If the VPS died, the site was gone. If the cluster dies, kubectl apply -f . brings it back.