๐Ÿงฐ Swift Toolbox/ Blog

What to Watch When Converting Docker Compose to K8s

2026-10-28 ยท Swift Toolbox ยท about 4 min read

A service that runs perfectly under Compose on your own machine cannot be copied to Kubernetes as-is. Compose is about "running a few containers together on one machine"; Kubernetes is about "scheduling, discovering and scaling Pods across a cluster" โ€” the two models are different. A converter can translate the skeleton for you, but several things will not survive the trip and have to be filled in by hand. With the Compose to K8s Converter on this site, paste your compose file and you get a Deployment plus a Service โ€” but first understand what converts and what does not.

Open the Compose to K8s Converter โ†’

What converts: services, images, ports, environment variables

The converter works service by service: each Compose service becomes one Deployment (1 replica), carrying over the image, container ports, environment variables and start command. A service with ports also gets a Service (ClusterIP) with matching ports. This part is mechanical mapping and rarely goes wrong โ€” but check the results anyway: a Compose port mapping of 8080:80 becomes containerPort 80 in the Deployment and port 80 in the Service, while the host-side 8080 simply disappears, because Kubernetes has no concept of a "host port".

What doesn't convert, 1: depends_on is only start order

Compose's depends_on only guarantees start order โ€” it does not guarantee that the dependency is actually ready. In Kubernetes it does not appear in the generated YAML at all, because Deployments have no dependency relationship with each other. The correct fix is to make the app retry its own connections (for example, retry a database connection with backoff), or use a readinessProbe plus an Init Container to wait for the dependency. Don't assume the converted files will behave like Compose and "start the database before the app".

What doesn't convert, 2: build and volumes

Compose's build: . is a local build, and Kubernetes has no idea what to do with it. Before migrating, build the image and push it to a registry (Docker Hub, a private registry or a cloud registry), then change the image field to the registry address. Private registries also need imagePullSecrets.

Volume mounts are the other trouble spot. A Compose mount like ./data:/data is a directory on one host machine, but in Kubernetes a Pod can be scheduled onto any node, so a host directory is unreliable. Stateful data (databases, uploaded files) should move to a PersistentVolumeClaim โ€” create the PVC first, then mount it in the Deployment. Pure cache or temporary files can use emptyDir. The converter does not handle volumes at all, so the generated YAML has no volumes section โ€” fill it in yourself according to the data type.

What doesn't convert, 3: networks and restart policies

Compose's custom networks have no direct equivalent in Kubernetes: service discovery works through Service DNS names (the service name is the DNS name), and cross-namespace access needs the full domain name. Restart policies need translating too: Compose's restart: always maps to a Deployment's restartPolicy: Always (the default), while on-failure is not valid in a Deployment at all โ€” Deployments only accept Always; only Jobs use OnFailure or Never.

Things to add by hand after converting

  1. Replicas and resource limits: the converter defaults to 1 replica and no resource limits. For production, raise replicas to 2 or more based on traffic and add requests and limits โ€” otherwise nothing will stop a single Pod from hogging a node or dying from OOM.
  2. Health checks: a Compose healthcheck does not become a probe. Add livenessProbe and readinessProbe to match what your app actually serves, and never copy /health blindly โ€” the path must be a real endpoint in your app.
  3. Exposing the service: the generated Service is ClusterIP, reachable only inside the cluster. To reach it from outside, change it to NodePort or LoadBalancer, or add an Ingress.
  4. Config and secrets: environment variables written in Compose are fine as plain values, but passwords and keys should no longer sit in plain text in the YAML โ€” move them into a Secret or a ConfigMap.

Suggested migration flow

1. Generate Deployment + Service with the converter, save as k8s.yaml
2. Check image addresses, ports and environment variables are complete
3. Add replicas, resource limits and health checks; move volumes to PVC
4. kubectl apply -f k8s.yaml, in a test namespace first
5. kubectl get pods / kubectl logs to debug, confirm no CrashLoopBackOff
6. Then configure Ingress or LoadBalancer to expose it
In one sentence: the converter translates the skeleton, not the finished product. Services, images, ports and environment variables convert automatically; dependencies, builds, volumes, networking and health checks are model differences that only a human can fill in. Get it running in a test environment first, then move to production.

The whole conversion runs locally in your browser โ€” the compose file is never uploaded. Before applying, it is worth dry-running the result with kubectl apply --dry-run=client -f k8s.yaml.