Table of Contents
- 1. Course Overview
- 2. Docker Compose vs Kubernetes Comparison
- 3. Migration with Kompose
- 4. Migration with Skaffold
- 5. Full Hands-On Practice
- 6. Summary and Resources
1. Course Overview
This course is aimed at developers who want to move from running their containers with Docker Compose locally to running them in Kubernetes — whether for development, staging, testing, or other scenarios.
Prerequisites
| Skill | Detail |
|---|---|
| Command-line tools | Using terminals, shells |
| Docker | Containers, images, builds (Dockerfile) |
| Kubernetes core concepts | Pods, Deployments, Services, ConfigMaps, Secrets |
Course Path
flowchart LR
A[Docker Compose\nand Kubernetes Review] --> B[Compose → K8s\nMapping]
B --> C[Kompose\nAutomatic Conversion]
C --> D[Skaffold\nLive Development]
D --> E[Hands-On Practice\nFull Project]
Demo Projects
- angular-jumpstart — Angular application + Node.js backend (2 services)
- CodeWithDanDockerServices — Multi-service application: nginx + node + mongo + redis (4 services)
2. Docker Compose vs Kubernetes Comparison
2.1 Docker Compose Review
Docker Compose is a tool for defining and running multi-container Docker applications. With a single YAML file, you configure all application services and start them with a single command.
Typical Multi-Container Application Architecture
graph TD
Client["Client / Browser"] --> Proxy["Reverse Proxy\n(nginx)"]
Proxy --> App["Frontend App\n(JavaScript)"]
App --> API1["Backend API 1\n(Node.js)"]
App --> API2["Backend API 2"]
API1 --> DB["Database\n(MongoDB / PostgreSQL)"]
API1 --> Cache["Cache\n(Redis)"]
API2 --> DB
Example docker-compose.yml (2-service application)
version: "3.8"
services:
nginx:
container_name: nginx
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- app-net
node:
container_name: node-server
image: my-node-app:latest
ports:
- "3000:3000"
env_file:
- .env
networks:
- app-net
networks:
app-net:
driver: bridge
Docker Compose Capabilities
| Feature | Docker Compose |
|---|---|
| Building images | ✅ docker compose build |
| Starting containers | ✅ docker compose up |
| Stopping and cleanup | ✅ docker compose down |
| Viewing logs | ✅ docker compose logs |
| Basic scaling | ✅ (single node only) |
| Multi-node scaling | ❌ |
| Auto-healing | ❌ |
| Rolling updates | ❌ |
2.2 Kubernetes Review
Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications.
Kubernetes Architecture
graph TD
Dev["Developer\nkubectl"] -->|commands| Master["Master Node\n(Control Plane)"]
Master --> W1["Worker Node 1"]
Master --> W2["Worker Node 2"]
Master --> W3["Worker Node 3"]
W1 --> P1["Pod\n[Container]"]
W1 --> P2["Pod\n[Container]"]
W2 --> P3["Pod\n[Container]"]
W3 --> P4["Pod\n[Container]"]
Key Kubernetes Resources
| Resource | Role |
|---|---|
| Pod | Basic unit — runs one or more containers |
| Deployment | Manages Pods, rolling updates, scaling |
| ReplicaSet | Ensures the desired number of Pods is running |
| Service | Exposes Pods on the network (ClusterIP, NodePort, LoadBalancer) |
| ConfigMap | Stores non-sensitive configuration (key/value) |
| Secret | Stores sensitive data (passwords, tokens) |
| PersistentVolumeClaim | Claims persistent storage |
| Ingress | HTTP/HTTPS routing rules to Services |
| Namespace | Logical isolation of resources |
Sample Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
2.3 Docker Compose → Kubernetes Mapping
The main migration challenge is moving from a single file (docker-compose.yml) to multiple YAML files in Kubernetes.
Mapping Diagram
flowchart LR
subgraph Compose["docker-compose.yml"]
S["service: nginx\n- image\n- ports\n- volumes\n- environment\n- networks"]
end
subgraph K8s["Kubernetes Manifests"]
D["Deployment\n(Pod template, replicas,\nimage, ports)"]
SVC["Service\n(ClusterIP / NodePort /\nLoadBalancer)"]
CM["ConfigMap\n(environment variables)"]
SEC["Secret\n(sensitive data)"]
PVC["PersistentVolumeClaim\n(persistent volumes)"]
end
S -->|"containers + replicas"| D
S -->|"ports exposure"| SVC
S -->|"env_file / environment"| CM
S -->|"secrets"| SEC
S -->|"volumes"| PVC
Detailed Mapping Table
| Docker Compose Concept | Kubernetes Equivalent | Notes |
|---|---|---|
services: | Deployment + Service | 1 Compose service → at least 2 K8s files |
image: | spec.containers[].image | Identical |
ports: | Service.spec.ports + containerPort | Split between Service and Deployment |
volumes: (bind mount) | hostPath volume | Avoid in production |
volumes: (named volume) | PersistentVolumeClaim | Recommended for persistent storage |
environment: | ConfigMap + env in container | For non-sensitive values |
env_file: | ConfigMap or Secret | Secrets for sensitive values |
networks: (bridge) | Not needed | K8s handles intra-cluster networking natively |
depends_on: | initContainers or health checks | No direct equivalent in K8s |
build: | CI/CD pipeline or Skaffold | K8s does not build images |
restart: always | restartPolicy: Always | Default behavior in Deployment |
scale: | spec.replicas | K8s supports multi-node scaling |
container_name: | metadata.name (Pod) | Pod name is managed by Deployment |
Side-by-Side Comparison: nginx service
Docker Compose:
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
environment:
- API_URL=http://node:3000
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- app-net
Kubernetes — Equivalent Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
env:
- name: API_URL
valueFrom:
configMapKeyRef:
name: nginx-config
key: API_URL
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-conf
configMap:
name: nginx-configmap
Kubernetes — Equivalent Service:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer # or NodePort for local development
Kubernetes — ConfigMap for environment variables:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
API_URL: "http://node:3000"
Before/After Migration Architecture
graph TB
subgraph Before["BEFORE — Docker Compose (local machine)"]
DC["docker-compose.yml\n(1 file)"]
DC --> C1["Container: nginx"]
DC --> C2["Container: node"]
DC --> C3["Container: mongo"]
DC --> C4["Container: redis"]
C1 & C2 & C3 & C4 --> BN["Bridge Network\napp-net"]
end
subgraph After["AFTER — Kubernetes Cluster"]
NS["Namespace: production"]
NS --> ND["Deployment: nginx\n+ Service: nginx"]
NS --> NOD["Deployment: node\n+ Service: node"]
NS --> MOD["Deployment: mongo\n+ Service: mongo\n+ PVC: mongo-data"]
NS --> RD["Deployment: redis\n+ Service: redis"]
NS --> CM2["ConfigMap: app-config"]
NS --> SEC2["Secret: mongo-secret"]
ND & NOD & MOD & RD -.->|"ClusterIP\nDNS-based"| KN["Kubernetes\nCluster Network"]
end
Before -->|"kompose convert\nor skaffold init"| After
3. Migration with Kompose
3.1 Kompose Overview
Kompose = Kubernetes + Docker Compose (creative name fusion).
Kompose is a tool to help users familiar with Docker Compose move to Kubernetes. It takes a Docker Compose file and translates it into Kubernetes resources.
Why use Kompose?
- Avoids manually rewriting all Kubernetes YAML files
- Fast and official conversion
- Generates Deployments and Services by default
- Supports volume types (PVC, hostPath, emptyDir)
- Can generate DaemonSets and other resources via flags
Kompose Workflow:
flowchart LR
A["docker-compose.yml"] -->|"kompose convert"| B["nginx-deployment.yaml"]
A -->|"kompose convert"| C["nginx-service.yaml"]
A -->|"kompose convert"| D["node-deployment.yaml"]
A -->|"kompose convert"| E["node-service.yaml"]
A -->|"kompose convert"| F["[other resources]\nConfigMap, PVC..."]
3.2 Installing Kompose
macOS
# Download the binary
curl -L https://github.com/kubernetes/kompose/releases/latest/download/kompose-darwin-amd64 -o kompose
# Set executable permissions
chmod +x kompose
# Move to PATH
sudo mv ./kompose /usr/local/bin/kompose
# Verify
kompose version
Linux
curl -L https://github.com/kubernetes/kompose/releases/latest/download/kompose-linux-amd64 -o kompose
chmod +x kompose
sudo mv ./kompose /usr/local/bin/kompose
Windows (PowerShell)
# Download from GitHub Releases
# Place kompose.exe in a folder on your PATH
# https://github.com/kubernetes/kompose/releases
kompose version
3.3 The kompose convert Command
Basic Command
# Convert docker-compose.yml in the current directory
kompose convert
Available Flags
| Flag | Shorthand | Description |
|---|---|---|
--file | -f | Specifies an alternative Compose file (e.g., docker-compose.prod.yml) |
--out | -o | Output directory for generated YAML files |
--stdout | Prints YAML to console instead of files | |
--volumes | Volume type: persistentVolumeClaim (default), hostPath, emptyDir | |
--replicas | Number of replicas for Deployments | |
--controller | Controller type: deployment (default), daemonset, replicationcontroller | |
--with-kompose-annotation | Adds Kompose annotations to generated YAML |
Usage Examples
# Convert with specific file and output to a directory
kompose convert -f docker-compose.yml -o ./k8s/
# Print to console for review before saving
kompose convert --stdout
# Convert using hostPath instead of PVC
kompose convert --volumes hostPath -o ./k8s/
# Convert with 3 replicas
kompose convert --replicas 3 -o ./k8s/
# Full help
kompose convert --help
3.4 Kompose in Action
Demo Project: angular-jumpstart
This project contains two services in its docker-compose.yml:
- nginx — Serves the JavaScript frontend (Angular)
- node — Node.js backend API
# 1. Navigate to the project directory
cd angular-jumpstart
# 2. Create the output folder
mkdir output
# 3. Run the conversion
kompose convert -f docker-compose.yml -o ./output/
# Result:
# INFO Kubernetes file "output/nginx-service.yaml" created
# INFO Kubernetes file "output/node-service.yaml" created
# INFO Kubernetes file "output/nginx-deployment.yaml" created
# INFO Kubernetes file "output/node-deployment.yaml" created
Deploying the Generated Resources
# Apply all generated files
kubectl apply -f ./output/
# Check Deployments
kubectl get deployments
# Check Pods
kubectl get pods
# Check Services
kubectl get services
3.5 Analyzing the Generated YAML
Service Generated by Kompose (before cleanup)
apiVersion: v1
kind: Service
metadata:
annotations:
kompose.cmd: kompose convert -f docker-compose.yml -o ./output/
kompose.version: 1.28.0 (c4137012e)
creationTimestamp: null # Remove or set a valid date
labels:
io.kompose.service: nginx # Kompose label — can be renamed
name: nginx
spec:
ports:
- name: "80"
port: 80
targetPort: 80
selector:
io.kompose.service: nginx
status:
loadBalancer: {} # Default type = ClusterIP
Cleaned-Up Service (after recommended changes)
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: nginx
type: LoadBalancer
Deployment Generated by Kompose (before cleanup)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.28.0
creationTimestamp: null
labels:
io.kompose.service: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: nginx
strategy: {}
template:
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.28.0
creationTimestamp: null
labels:
io.kompose.service: nginx
spec:
containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80
resources: {}
restartPolicy: Always
status: {}
Recommended Changes After Generation
| Element | Recommended Action |
|---|---|
annotations: kompose.* | Remove (unnecessary metadata in production) |
creationTimestamp: null | Remove |
labels: io.kompose.service | Replace with app: <name> |
strategy: {} | Configure: type: RollingUpdate with maxSurge and maxUnavailable |
resources: {} | Define CPU/memory requests and limits |
replicas: 1 | Adjust as needed |
| Service type | Verify whether ClusterIP, NodePort, or LoadBalancer is appropriate |
Full Example After Cleanup (nginx + node application)
nginx-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
restartPolicy: Always
4. Migration with Skaffold
4.1 Skaffold Overview
Skaffold = local Kubernetes development.
Skaffold handles the workflow for building, pushing, and deploying your application, allowing you to focus on what matters most: writing code.
flowchart TD
Dev["Developer\n(modifies code)"] -->|"change\ndetection"| Skaffold
Skaffold -->|"rebuild"| Builder["Build\n(Docker image)"]
Builder -->|"push"| Registry["Image Registry\n(local or remote)"]
Registry -->|"redeploy"| K8s["Kubernetes Cluster\n(local: Docker Desktop\nor minikube)"]
K8s -->|"Pods updated"| App["Application\n(accessible)"]
Docker Compose vs Skaffold Comparison
| Feature | Docker Compose | Skaffold |
|---|---|---|
| Building images | ✅ | ✅ |
| Running containers | ✅ (local) | ✅ (in Kubernetes) |
| Live reload on code change | ✅ (watch) | ✅ (rebuild + redeploy) |
| File syncing without rebuild | ❌ | ✅ |
| Deploy to remote cluster | ❌ | ✅ |
| Multi-service orchestration | Basic | Via Kubernetes |
| Convert to K8s manifests | ❌ | ✅ (via internal Kompose) |
Important note: Skaffold uses Kompose internally for Docker Compose → Kubernetes manifest conversion.
4.2 Installing Skaffold
macOS
# Via Homebrew (recommended)
brew install skaffold
# Via curl
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-darwin-amd64
sudo install skaffold /usr/local/bin/
# Verify
skaffold version
Linux
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install skaffold /usr/local/bin/
Windows
# Via Chocolatey
choco install skaffold
# Verify
skaffold version
4.3 Skaffold Commands
Main Commands
| Command | Description |
|---|---|
skaffold init | Initializes a Skaffold project (generates skaffold.yaml) |
skaffold run | Build, push and deploy once |
skaffold dev | Development mode: watches for changes and redeploys automatically |
skaffold build | Build images only |
skaffold deploy | Deploy only (no build) |
skaffold delete | Removes deployed resources |
Important Flags for skaffold init
# Initialize from a Docker Compose file
skaffold init --compose-file docker-compose.yml
# Initialize from existing Kubernetes manifests
skaffold init -k ".k8s/*.yaml"
# With Dockerfile artifact specifications
skaffold init \
--compose-file docker-compose.yml \
-a '{"builder":"Docker","payload":{"path":"./docker/nginx/Dockerfile"},"image":"my-nginx"}' \
-a '{"builder":"Docker","payload":{"path":"./docker/node/Dockerfile"},"image":"my-node"}'
4.4 skaffold init in Action
Project angular-jumpstart
# Step 1: Initialize from Docker Compose
skaffold init \
--compose-file docker-compose.yml \
-a '{"builder":"Docker","payload":{"path":"./Dockerfile.nginx"},"image":"nginx-app"}' \
-a '{"builder":"Docker","payload":{"path":"./Dockerfile.node"},"image":"node-app"}'
# Result: creates skaffold.yaml and K8s manifests in .k8s/
Generated skaffold.yaml File
apiVersion: skaffold/v4beta6
kind: Config
metadata:
name: angular-jumpstart
build:
artifacts:
- image: nginx-app
context: .
docker:
dockerfile: Dockerfile.nginx
- image: node-app
context: .
docker:
dockerfile: Dockerfile.node
manifests:
rawYaml:
- .k8s/*.yaml
4.5 skaffold dev in Action
# Launch development mode
skaffold dev -f skaffold.yaml
What happens during skaffold dev:
sequenceDiagram
participant Dev as Developer
participant Skaffold as Skaffold
participant Docker as Docker Build
participant K8s as Kubernetes
Dev->>Skaffold: skaffold dev
Skaffold->>Docker: Build initial images
Docker-->>Skaffold: Images built
Skaffold->>K8s: kubectl apply (manifests)
K8s-->>Skaffold: Deployments stable
Skaffold-->>Dev: Application accessible ✅
loop File Watching
Dev->>Dev: Code modification
Skaffold->>Docker: Rebuild image
Docker-->>Skaffold: New image
Skaffold->>K8s: Automatic redeployment
K8s-->>Skaffold: Pod updated
Skaffold-->>Dev: Changes visible ✅
end
Dev->>Skaffold: Ctrl+C
Skaffold->>K8s: Resource cleanup
File Syncing (Rebuild Optimization)
For cases where rebuilding a full image is too slow (e.g., Angular with npm install), Skaffold offers file sync — syncing only modified files without a rebuild:
# In skaffold.yaml
build:
artifacts:
- image: my-node-app
context: .
docker:
dockerfile: Dockerfile
sync:
infer:
- "src/**/*.js" # Sync these files without rebuild
- "src/**/*.ts"
Useful Commands During skaffold dev
# View logs in real time
skaffold dev --tail
# Disable automatic cleanup on exit
skaffold dev --cleanup=false
# Force port-forwarding
skaffold dev --port-forward
5. Full Hands-On Practice
5.1 Conversion with Kompose
Project: CodeWithDanDockerServices
This more complex project contains 4 services: nginx, node, mongo, redis.
# Project available at: github.com/DanWahlin/CodeWithDanDockerServices
docker-compose.yml (excerpt with 4 services):
version: "3.8"
services:
nginx:
image: codewithdan/nginx:latest
ports:
- "80:80"
networks:
- app-net
node:
image: codewithdan/node-service:latest
ports:
- "3000:3000"
environment:
- MONGO_URI=${MONGO_URI}
- REDIS_URL=${REDIS_URL}
depends_on:
- mongo
- redis
networks:
- app-net
mongo:
image: mongo:6
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
networks:
- app-net
redis:
image: redis:alpine
ports:
- "6379:6379"
networks:
- app-net
volumes:
mongo-data:
networks:
app-net:
driver: bridge
Conversion Procedure
# PowerShell: set required environment variables
$env:MONGO_URI = "mongodb://admin:secret@mongo:27017/appdb"
$env:REDIS_URL = "redis://redis:6379"
$env:MONGO_USER = "admin"
$env:MONGO_PASSWORD = "secret"
# Verify kompose is installed
kompose version
# Convert with output to a directory
kompose convert -f docker-compose.yml -o ./output/
# Generated files:
# output/nginx-deployment.yaml
# output/nginx-service.yaml
# output/node-deployment.yaml
# output/node-service.yaml
# output/mongo-deployment.yaml
# output/mongo-service.yaml
# output/redis-deployment.yaml
# output/redis-service.yaml
# output/mongo-data-persistentvolumeclaim.yaml
Result: PersistentVolumeClaim for MongoDB
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongo-data
labels:
app: mongo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Secret for MongoDB (created manually)
# Create the Secret for MongoDB credentials
kubectl create secret generic mongo-secret \
--from-literal=MONGO_INITDB_ROOT_USERNAME=admin \
--from-literal=MONGO_INITDB_ROOT_PASSWORD=secret
Or in YAML:
apiVersion: v1
kind: Secret
metadata:
name: mongo-secret
type: Opaque
stringData:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secret # In production: use a vault
Full Deployment
# Apply the Secret first
kubectl apply -f mongo-secret.yaml
# Apply all manifests
kubectl apply -f ./output/
# Check status
kubectl get all
# Check PVCs
kubectl get pvc
# Check Pod logs
kubectl logs deployment/node
5.2 Using Skaffold
skaffold.yaml for CodeWithDanDockerServices
apiVersion: skaffold/v4beta6
kind: Config
metadata:
name: codewithdan-services
build:
artifacts:
- image: codewithdan/nginx
context: .
docker:
dockerfile: docker/nginx/Dockerfile
- image: codewithdan/node-service
context: .
docker:
dockerfile: docker/node/Dockerfile
- image: codewithdan/mongo
context: .
docker:
dockerfile: docker/mongo/Dockerfile
- image: codewithdan/redis
context: .
docker:
dockerfile: docker/redis/Dockerfile
manifests:
rawYaml:
- .k8s/*.yaml
Initialization and Launch
# Initialize from the existing docker-compose.yml
skaffold init \
--compose-file docker-compose.yml \
-a '{"builder":"Docker","payload":{"path":"docker/nginx/Dockerfile"},"image":"codewithdan/nginx"}' \
-a '{"builder":"Docker","payload":{"path":"docker/node/Dockerfile"},"image":"codewithdan/node-service"}' \
-a '{"builder":"Docker","payload":{"path":"docker/mongo/Dockerfile"},"image":"codewithdan/mongo"}' \
-a '{"builder":"Docker","payload":{"path":"docker/redis/Dockerfile"},"image":"codewithdan/redis"}'
# Create the Mongo Secret before launching
kubectl apply -f mongo-secret.yaml
# Launch in development mode
skaffold dev -f skaffold.yaml
# Or run once
skaffold run -f skaffold.yaml
6. Summary and Resources
Full Migration Flow
flowchart TD
Start["Docker Compose\nApplication"] --> Assess["Analyze\ndocker-compose.yml"]
Assess --> HasSecrets{"Has sensitive\nvariables?"}
HasSecrets -->|Yes| CreateSecrets["Create\nKubernetes Secrets"]
HasSecrets -->|No| ChooseTool
CreateSecrets --> ChooseTool["Choose migration\ntool"]
ChooseTool --> Kompose["Kompose\n(static conversion)"]
ChooseTool --> Skaffold["Skaffold\n(dev workflow)"]
Kompose -->|"kompose convert\n-f docker-compose.yml\n-o ./k8s/"| GeneratedYAML["Generated\nKubernetes YAML"]
Skaffold -->|"skaffold init\n--compose-file"| SkaffoldYAML["skaffold.yaml\n+ K8s YAML"]
GeneratedYAML --> Review["Review\nand cleanup\nYAML"]
SkaffoldYAML --> Review
Review --> Cleanup["Remove unnecessary\nKompose annotations\nConfigure resources,\nstrategy, labels"]
Cleanup --> Apply["kubectl apply\n-f ./k8s/"]
Apply --> Test["Validation\ntesting"]
Test --> Done["✅ Application\nin Kubernetes"]
Migration Tool Comparison
| Criteria | Kompose | Skaffold |
|---|---|---|
| Main purpose | File conversion | Development workflow |
| Key command | kompose convert | skaffold init, skaffold dev |
| Generates K8s manifests | ✅ | ✅ (via internal Kompose) |
| Live development | ❌ | ✅ |
| File syncing | ❌ | ✅ |
| Auto-rebuild on change | ❌ | ✅ |
| Complexity | Low | Medium |
| Use case | One-shot migration | Continuous development on K8s |
Skaffold Alternatives
Other tools offer similar workflows:
| Tool | Highlight |
|---|---|
| Skaffold | Kompose integration, file sync, multi-cluster |
| Tilt | Web UI, multi-services, highly configurable |
| Draft | Automatic language detection, CI/CD optimized |
| Garden | Dependency graph, integrated testing |
Quick Reference Commands
# ─── Kompose ──────────────────────────────────────────────
# Basic conversion
kompose convert
# Convert to a specific directory
kompose convert -f docker-compose.yml -o ./k8s/
# Print to console
kompose convert --stdout
# With specific volume type
kompose convert --volumes hostPath
# ─── Skaffold ─────────────────────────────────────────────
# Initialize from Compose
skaffold init --compose-file docker-compose.yml
# Initialize from existing manifests
skaffold init -k ".k8s/*.yaml"
# Development mode (live reload)
skaffold dev
# One-shot deployment
skaffold run
# Cleanup resources
skaffold delete
# ─── kubectl (post-migration) ─────────────────────────────
# Deploy all manifests
kubectl apply -f ./k8s/
# Check everything
kubectl get all
# Follow logs
kubectl logs -f deployment/my-app
# Describe a Pod for debugging
kubectl describe pod <pod-name>
# Access a Pod interactively
kubectl exec -it <pod-name> -- /bin/sh
Post-Migration Best Practices
- Standardized labels — Replace
io.kompose.servicelabels withapp: <name>and optionallyversion,tier,environment - Resources requests/limits — Always define CPU and memory limits to avoid starved pods
- Health checks — Add
livenessProbeandreadinessProbefor critical services - Secrets management — Never store credentials in plain text; use Kubernetes Secrets, HashiCorp Vault, or cloud-native solutions
- Namespace isolation — Use Namespaces to separate dev/staging/production
- Rolling update strategy — Configure
maxSurgeandmaxUnavailablefor zero-downtime deployments - Service type review — Verify whether
ClusterIP,NodePort, orLoadBalanceris appropriate for each service
Additional Resources
| Resource | Link |
|---|---|
| Kompose Documentation | https://kompose.io |
| Kompose GitHub Repository | https://github.com/kubernetes/kompose |
| Skaffold Documentation | https://skaffold.dev |
| angular-jumpstart Project | https://github.com/danwahlin/angular-jumpstart |
| CodeWithDanDockerServices Project | https://github.com/DanWahlin/CodeWithDanDockerServices |
| Blog | https://codewithdan.com |
Search Terms
kubernetes · developers · moving · docker · compose · containers · skaffold · kompose · generated · migration · commands · comparison · resources · action · application · architecture · cleanup · deployment · mapping · service · angular-jumpstart · changes · codewithdandockerservices · command