migration8 min read

Migrate from Docker Compose to Kubernetes: Step-by-Step Transition Guide

SFEIR Institute

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.

CriterionDocker ComposeKubernetes
ScalingManual, single hostAutomatic, multi-node
High availabilityNot nativeIntegrated (ReplicaSets)
Rolling updatesService interruptionZero-downtime
Service discoverySimple DNSDNS + load balancing
SecretsEnvironment variablesNative encrypted objects
MonitoringTo configureIntegrated 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 elementKubernetes equivalentNotes
servicesDeployment + ServiceOne Deployment per service
portsService (ClusterIP/NodePort/LoadBalancer)Choose type based on exposure
environmentConfigMap or SecretSecret for credentials
volumes (named)PersistentVolumeClaimRequires a StorageClass
volumes (bind mount)Not recommendedUse ConfigMap or initContainer
depends_onInitContainers or probesKubernetes doesn't guarantee order
buildImage registryBuild 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

CheckCommandExpected result
Pods runningkubectl get pods -n myappSTATUS = Running
Services activekubectl get svc -n myappNon-empty Endpoints
Error-free logskubectl logs -l app=api -n myappNo exceptions
DB connectionkubectl exec -it deploy/api -- pg_isready -h db-serviceAccepting connections
Health checkskubectl describe pod -l app=api -n myappProbes 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:

  1. Evaluate your project: identify services, volumes and dependencies
  2. Test the conversion: use Kompose on a development environment
  3. Get trained: acquire skills with a certifying training

SFEIR Institute trainings support Backend, Full-Stack developers and software engineers in this transition:

Contact our advisors to define the path suited to your migration project.