WZ-IT supports this through the relevant service: Migrate Docker Compose to Kubernetes with Kompose.
Kompose can translate a Compose file into Kubernetes resources. That produces a starting point, not an accepted production environment (Kubernetes guide). Data, dependencies and the controlled switch of traffic remain decisive. Using a web application with PostgreSQL as an example, this article walks through inventory, conversion, reworking the manifests, data transfer and cutover. As of October 2026.
Contents
- 1. Inventory the application and target cluster
- 2. Run Kompose and revise manifests
- 3. Migrate data and secrets separately
- 4. Validate and switch traffic under control
- When Kompose does not fit
1. Inventory the application and target cluster
Record images, ports, environment variables, volumes and external services. First check whether Kubernetes instead of Compose or Coolify fits the operation. Prerequisites for this procedure: a reachable target cluster, the right kubectl context, a namespace and a documented rollback path to the current environment.
The example is this compose.yaml with a web application and a database (image names and values are placeholders):
services:
web:
image: registry.example.com/shop:1.4.2
ports:
- "8080:8080"
environment:
DB_HOST: db
DB_NAME: shop
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_DB: shop
POSTGRES_USER: shop
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
| Compose inventory | Check in the Kubernetes target |
|---|---|
| Ports | Service and, if needed, external access (Ingress) |
| Volumes | PVC, StorageClass, access mode and data transfer |
| environment and env_file | ConfigMap or Secret depending on content |
| depends_on | Retry logic and application readiness |
| Local image build | Publishable image and registry access |
| Secret files | Kubernetes Secret, kept apart from the manifests |
The Kompose conversion matrix documents supported and unsupported Compose fields. Do not assume a one-to-one semantic transfer.
2. Run Kompose and revise manifests
Install Kompose following the official installation guide. Work on a copy without production credentials:
mkdir k8s-output
kompose convert -f compose.yaml -o k8s-output/
Kompose creates a Deployment per service, a Service per published port and a PersistentVolumeClaim per volume. For volumes it sets the Recreate strategy. Underscores in service names become hyphens because Kubernetes does not accept them. The Kompose user guide lists options that steer the result:
| Option | Effect |
|---|---|
--controller statefulset |
StatefulSet or DaemonSet instead of Deployment |
--volumes |
Volume type: persistentVolumeClaim, emptyDir, hostPath or configMap |
--build, --push-image |
Build the image and push it to a registry |
-f repeated |
Merge several Compose files |
Label kompose.service.expose |
Create an Ingress with a domain |
Label kompose.service.type |
Service type (nodeport, clusterip, loadbalancer, headless) |
Label kompose.volume.size |
PVC size, for example 10Gi |
Read every warning and every generated object. For the example, at least these adjustments are needed:
- Run the database as a StatefulSet or deliberately keep it as a single-replica Deployment and document that.
- Set resources:
requestsandlimitsfor CPU and memory per container. - Add probes: liveness, readiness and startup probes. Readiness controls readiness for traffic; an unsuitable liveness check can cause restarts.
- Take credentials from Secrets instead of plain-text variables in the manifest.
- Add an Ingress if the application is to be reachable externally.
Example probes on the web container:
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 20
Successfully converted YAML does not prove a reachable application.
3. Migrate data and secrets separately
A PVC does not transfer existing data. Choose a backup and restore method that fits the database system, check the target version and plan a write lock or explicitly supported replication. Confirm the recovery path before the cutover (Persistent Volumes).
For the PostgreSQL example, with the application stopped and the same major version:
# On the Compose host: dump in custom format
docker compose exec -T db pg_dump -U shop -Fc shop > shop.dump
# Copy into the database pod and restore
kubectl -n migration-check cp shop.dump db-0:/tmp/shop.dump
kubectl -n migration-check exec db-0 -- pg_restore -U shop -d shop --clean --if-exists /tmp/shop.dump
Afterwards compare row counts of important tables and run an application test against source and target.
Kubernetes Secrets are not an automatic encryption solution: Base64 encoding does not protect credentials. Check encryption at rest and minimal access rights (Secrets). Do not put real values into the example directory or into Git. A Secret from a local file that is not versioned:
kubectl -n migration-check create secret generic db-credentials --from-env-file=.env.k8s
4. Validate and switch traffic under control
Check the current context before every apply. Replace migration-check with the intended, already created test namespace. The server-side dry run changes no resources; the following apply does (kubectl apply).
kubectl config current-context
kubectl apply --dry-run=server -n migration-check -f k8s-output/
# Apply only after review in the intended test namespace:
kubectl apply -n migration-check -f k8s-output/
kubectl get pods,svc,pvc -n migration-check
kubectl rollout status deployment/web -n migration-check
Validate login, writes, reads, restarts, persistence and backup recovery. Record the cutover point and abort criteria:
| Step | Check |
|---|---|
| Before cutover | DNS TTL lowered, write lock on the old system, last dump transferred |
| Cutover | DNS or load balancer to the new system, application test immediately afterwards |
| Observation | Error rate, probes, memory use, database connections |
| Rollback | Keep the old system unchanged until new writes are safeguarded |
After writes on the new system, rollback requires more than a DNS change: data states must agree. WZ-IT addresses this through application modernisation.
When Kompose does not fit
Kompose is a translator, not a platform decision. Consider alternatives if the Compose file uses many unsupported fields, builds hang on the Compose context, several environments with variants must be maintained (then Helm or Kustomize) or the application does without Kubernetes features such as scaling and rollouts. In that case Compose or Coolify remains the simpler choice, and whether you need Kubernetes at all is answered by Do we need Kubernetes?.
Further reading
Relevant service: Migrate Docker Compose to Kubernetes with Kompose.










