Key Takeaways
- ✓Kompose automatically converts docker-compose.yml to Kubernetes manifests, but requires manual adaptation for production
- ✓'Migration in 5 phases: audit, conversion, storage, networking, validation'
- ✓Plan 2 to 4 weeks for a medium-sized application
You're using Docker Compose in development and need to migrate from Docker Compose to Kubernetes for production. This transition represents a fundamental change in how you manage your containers.
According to the CNCF Annual Survey 2025, 82% of container users now run Kubernetes in production. This guide walks you through step by step, from the docker-compose.yml file to working Kubernetes manifests.
TL;DR: Docker Compose to Kubernetes migration follows 5 phases: audit existing systems, convert services, adapt storage, configure networking, and validate. Plan 2 to 4 weeks for a medium-sized application. Backend and Full-Stack developers who master this transition become sought-after profiles in the market.
This skill is at the heart of the LFD459 Kubernetes for Application Developers training.
Why migrate from Docker Compose to Kubernetes?
Docker Compose excels for local development and test environments. Kubernetes meets production requirements: high availability, automatic scaling, rolling updates without interruption.
| Criterion | Docker Compose | Kubernetes |
|---|---|---|
| Scaling | Manual, single host | Automatic, multi-node |
| High availability | Not native | Integrated (ReplicaSets) |
| Rolling updates | Service interruption | Zero-downtime |
| Service discovery | Simple DNS | DNS + load balancing |
| Secrets | Environment variables | Native encrypted objects |
| Monitoring | To configure | Integrated ecosystem |
Key takeaway: Docker Compose suits development. Kubernetes is essential for production with its availability guarantees and native scaling.
The complete comparison of Kubernetes alternatives details the architectural differences between these orchestrators.
What prerequisites before starting migration?
Required technical environment
Install these tools before starting:
# kubectl - Kubernetes CLI
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Kompose - Docker Compose to Kubernetes converter
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-linux-amd64 -o kompose
chmod +x kompose && sudo mv kompose /usr/local/bin/
# Version verification
kubectl version --client
kompose version
Kubernetes test cluster
Use Minikube, Kind or k3s for your local tests:
# Minikube installation
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Start the cluster
minikube start --driver=docker --memory=4096 --cpus=2
Required skills
Migration requires understanding of fundamental Kubernetes concepts. See the Kubernetes fundamentals training for system administrators if these concepts are new to you:
- Pod: minimum deployment unit (one or more containers)
- Deployment: declarative management of ReplicaSets
- Service: network exposure and load balancing
- ConfigMap: externalized configuration
- Secret: encrypted sensitive data
How to analyze your existing docker-compose.yml?
Service audit
List each service in your Compose file and identify:
# Example docker-compose.yml to migrate
version: '3.8'
services:
api:
build: ./api
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/app
depends_on:
- db
volumes:
- ./api:/app
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Correspondence matrix
| Compose element | Kubernetes equivalent | Notes |
|---|---|---|
services | Deployment + Service | One Deployment per service |
ports | Service (ClusterIP/NodePort/LoadBalancer) | Choose type based on exposure |
environment | ConfigMap or Secret | Secret for credentials |
volumes (named) | PersistentVolumeClaim | Requires a StorageClass |
volumes (bind mount) | Not recommended | Use ConfigMap or initContainer |
depends_on | InitContainers or probes | Kubernetes doesn't guarantee order |
build | Image registry | Build separately, push to registry |
Key takeaway: Development bind mounts (./api:/app) don't migrate to Kubernetes. Build immutable images containing your code.
Which method to convert your services?
Automatic conversion with Kompose
Kompose generates Kubernetes manifests from your docker-compose.yml:
# Basic conversion
kompose convert -f docker-compose.yml
# Conversion with advanced options
kompose convert -f docker-compose.yml \
--out ./k8s-manifests \
--with-kompose-annotation=false \
--controller=deployment
This command produces several YAML files. Review each generated file: Kompose creates a functional base but rarely optimal for production.
Manual manifest adaptation
The generated Deployment requires adjustments. Here's an optimized example:
# api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
labels:
app: api
spec:
replicas: 3
selector:
matchLabels:
app: api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.example.com/api:v1.2.3
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
envFrom:
- configMapRef:
name: api-config
- secretRef:
name: api-secrets
The best practices for structuring Kubernetes YAML manifests details each section of this file.
Configuration externalization
Separate environment variables into ConfigMaps and Secrets:
# api-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
LOG_LEVEL: "info"
API_PORT: "8080"
FEATURE_FLAGS: "new-ui=true,beta-api=false"
---
# api-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
type: Opaque
stringData:
DATABASE_URL: "postgres://user:pass@db-service:5432/app"
The LFD459 Kubernetes for Application Developers training covers ConfigMaps and Secrets management in depth over 3 intensive days.
How to manage persistent storage?
Docker volume conversion
Named Docker volumes become PersistentVolumeClaims (PVC):
# postgres-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 10Gi
StatefulSet for databases
Use a StatefulSet instead of a Deployment for PostgreSQL:
# postgres-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
envFrom:
- secretRef:
name: postgres-secrets
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 20Gi
Key takeaway: StatefulSets guarantee stable pod names and persistent storage per replica. Essential for databases.
How to configure Kubernetes networking?
Services and exposure
Create a Service for each exposed Deployment:
# api-service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
# postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
name: db-service
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
type: ClusterIP
Replacing depends_on
Docker Compose uses depends_on for startup order. Kubernetes favors InitContainers and readiness probes:
# In the API Deployment
spec:
template:
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command: ['sh', '-c',
'until nc -z db-service 5432; do echo "Waiting for DB..."; sleep 2; done']
containers:
- name: api
# ... main configuration
This approach is more robust: it verifies actual service availability, not just container startup.
What steps to validate migration?
Progressive deployment
Apply manifests in order:
# 1. Dedicated namespace
kubectl create namespace myapp
# 2. Secrets and ConfigMaps
kubectl apply -f k8s-manifests/secrets/ -n myapp
kubectl apply -f k8s-manifests/configmaps/ -n myapp
# 3. Persistent storage
kubectl apply -f k8s-manifests/pvc/ -n myapp
# 4. Database (StatefulSet)
kubectl apply -f postgres-statefulset.yaml -n myapp
kubectl wait --for=condition=ready pod/postgres-0 -n myapp --timeout=120s
# 5. Application
kubectl apply -f api-deployment.yaml -n myapp
kubectl apply -f api-service.yaml -n myapp
# 6. Verification
kubectl get all -n myapp
Validation checklist
| Check | Command | Expected result |
|---|---|---|
| Pods running | kubectl get pods -n myapp | STATUS = Running |
| Services active | kubectl get svc -n myapp | Non-empty Endpoints |
| Error-free logs | kubectl logs -l app=api -n myapp | No exceptions |
| DB connection | kubectl exec -it deploy/api -- pg_isready -h db-service | Accepting connections |
| Health checks | kubectl describe pod -l app=api -n myapp | Probes passing |
See our guide to solve the 10 most common Kubernetes deployment errors if you encounter problems.
Load tests
# Port-forward for local access
kubectl port-forward svc/api-service 8080:80 -n myapp &
# Basic load test
hey -n 1000 -c 50 http://localhost:8080/api/health
How to plan a rollback?
Pre-migration backup
Keep your Docker Compose environment functional:
# Data export
docker compose exec db pg_dump -U postgres app > backup_pre_migration.sql
# Volume snapshot
docker run --rm -v postgres_data:/data -v $(pwd):/backup \
alpine tar czf /backup/postgres_data_backup.tar.gz /data
Kubernetes rollback
If migration fails, revert to the previous version:
# Rollback a Deployment
kubectl rollout undo deployment/api -n myapp
# Check history
kubectl rollout history deployment/api -n myapp
# Return to a specific revision
kubectl rollout undo deployment/api --to-revision=2 -n myapp
Key takeaway: Kubernetes retains revision history. Test the rollback procedure before going to production.
What post-migration optimizations to apply?
Docker image optimization
According to Cloud Native Now, multi-stage builds reduce image size from 800 MB to 15-30 MB. Use Alpine images (~3 MB) rather than Ubuntu (~70 MB).
# Optimized multi-stage Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o api .
FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/api /usr/local/bin/
EXPOSE 8080
CMD ["api"]
Workload security
Apply Kubernetes workload security recommendations:
# Recommended security context
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
Horizontal Pod Autoscaler
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
What training to master this transition?
As The Enterprisers Project states: "Anybody can learn Kubernetes. With abundant documentation and development tools available online, teaching yourself Kubernetes is very much within reach." However, structured training significantly accelerates skill development.
The difference between LFS458 and LFD459 training depends on the target profile: cluster administration or application development. For Docker Compose to Kubernetes migration, the application developer path is most relevant.
The Kubernetes tutorials and practical guides complement this training with concrete use cases. The complete Kubernetes Training guide presents all available paths.
Take action
Migrating from Docker Compose to Kubernetes transforms your deployment approach. The 96% of organizations using or evaluating Kubernetes confirm this irreversible trend.
Recommended next steps:
- Evaluate your project: identify services, volumes and dependencies
- Test the conversion: use Kompose on a development environment
- Get trained: acquire skills with a certifying training
SFEIR Institute trainings support Backend, Full-Stack developers and software engineers in this transition:
- LFD459 Kubernetes for Application Developers: 3 days to master Deployments, Services, ConfigMaps and prepare for CKAD
- Kubernetes Fundamentals: 1 day to discover essential concepts
- LFS458 Kubernetes Administration: 4 days for complete cluster management and CKA
Contact our advisors to define the path suited to your migration project.