Phase 7: The Migration Project
Time: weeks 7-8. Goal: move your real Docker deployment. This is the capstone - and you can start sketching it from Phase 3 onward.
The recipe
A repeatable, step-by-step process for migrating a compose stack.
1. Inventory
List every compose service and classify it:
- Stateless app - the easy bulk.
- Stateful store - DBs, queues, caches. Each needs a deliberate decision.
- One-off / cron task - becomes Jobs and CronJobs.
- Infra you should NOT migrate - candidates for managed services instead.
2. Images
k8s pulls from a registry; there is no build: directive.
- Confirm everything builds to a registry-pushed image.
- Set up a registry path and an image tagging scheme. Never
latest- k8s can't roll back what it can't distinguish, and cachedlatesttags cause "why is the old version running" mysteries.
3. Per stateless service: Deployment + Service
| Compose construct | Becomes |
|---|---|
environment: / .env | ConfigMap (+ Secret for credentials) |
depends_on | Readiness probes + retry logic in the app |
restart: always | Nothing - controllers give you this for free |
healthcheck: | Liveness/readiness probes |
| service name DNS | Service (ClusterIP), usually the same name |
depends_on deserves emphasis: k8s has no startup ordering, by design. Pods start whenever. Your app must tolerate its dependencies being briefly unavailable (retry on connect) and use readiness probes to avoid receiving traffic before it's ready. If your app crashes when the DB isn't up yet, fix the app, don't fight the platform.
4. Per stateful service: decide honestly
Two options per store:
- In-cluster: StatefulSet + PVC. Fine for dev/test, defensible for prod if you know what you're doing.
- Managed service outside the cluster: for production databases, the boring answer is usually right.
5. Networking
- Compose service-name DNS maps almost 1:1 to k8s Services, so inter-service URLs often survive unchanged.
- All published ports (
-p) collapse into one Ingress with host/path rules.
6. Cron and one-offs
Host crontabs and docker run scripts become CronJobs and Jobs.
7. Cutover
- Run both stacks in parallel.
- Point a test domain at the k8s ingress.
- Validate everything against the test domain.
- Flip DNS.
- Keep the compose stack as rollback for a week before decommissioning.
On kompose
kompose auto-converts compose files to k8s manifests. Use it once as a cheat sheet to compare against your own work, but write the manifests by hand - the auto-generated output is mediocre and using it directly skips the learning this whole syllabus exists for.
What to defer
Service meshes (Istio), authoring operators/CRDs, multi-cluster, GitOps (ArgoCD/Flux) are all real, but they're layer two. GitOps is the first one worth adding once the migration is done: your manifests already live in git, ArgoCD just makes the cluster follow the repo.
Checkpoint (done = done)
- Every compose service has a classified destination and a manifest.
- The full stack runs on k8s in parallel with the old deployment.
- You executed a cutover plan with a tested rollback path.