Docker Compose to Kubernetes converter
Paste a docker-compose.yml and get a Kubernetes Deployment and Service for each service, with a PersistentVolumeClaim for each named volume. Every field that cannot be mapped is listed below the output. The conversion runs in your browser.
By Muhammad Soliman, Founder at SeaGit
Converted in this tab. The text is not uploaded or stored.
4 services converted. 7 items need your attention and 4 notes.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: uploads
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pgdata
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: ghcr.io/example/shop-web:1.4.2
args:
- node
- server.js
env:
- name: NODE_ENV
value: production
- name: PORT
value: '3000'
- name: DATABASE_URL
value: postgres://shop:shop@db:5432/shop
- name: REDIS_URL
value: redis://cache:6379
ports:
- containerPort: 3000
resources:
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
exec:
command:
- /bin/sh
- '-c'
- wget -qO- http://localhost:3000/healthz || exit 1
periodSeconds: 30
timeoutSeconds: 5
initialDelaySeconds: 20
failureThreshold: 3
volumeMounts:
- name: uploads
mountPath: /app/public/uploads
volumes:
- name: uploads
persistentVolumeClaim:
claimName: uploads
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
labels:
app: db
spec:
replicas: 1
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: postgres:16
env:
- name: POSTGRES_DB
value: shop
- name: POSTGRES_USER
value: shop
- name: POSTGRES_PASSWORD
value: shop
livenessProbe:
exec:
command:
- pg_isready
- '-U'
- shop
periodSeconds: 10
volumeMounts:
- name: pgdata
mountPath: /var/lib/postgresql/data
volumes:
- name: pgdata
persistentVolumeClaim:
claimName: pgdata
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache
labels:
app: cache
spec:
replicas: 1
selector:
matchLabels:
app: cache
template:
metadata:
labels:
app: cache
spec:
containers:
- name: cache
image: redis:7-alpine
args:
- redis-server
- '--appendonly'
- 'yes'
ports:
- containerPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: REPLACE_WITH_IMAGE
---
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 3000
targetPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: cache
labels:
app: cache
spec:
type: ClusterIP
selector:
app: cache
ports:
- port: 6379
targetPort: 6379
Not converted, and notes
- Needs reviewtop level
networksTop-level networks are not converted. Kubernetes uses one network per namespace.
- Needs reviewservice web
depends_ondepends_on is not converted. Kubernetes has no start order between Deployments. Make the app retry its dependencies, or use an init container or a readiness probe.
- Noteservice web
portsHost port 3000 is not exposed. The Service uses container port 3000 inside the cluster. Publish it with an Ingress or a LoadBalancer Service.
- Noteservice web
healthcheckhealthcheck is mapped to a livenessProbe. Compose only reports health, but a failing liveness probe makes Kubernetes restart the container. Add a readinessProbe if you want traffic held back instead.
- Needs reviewservice web
volumesReplicas is 2 and the service uses a ReadWriteOnce claim. Only one pod can mount it on most storage. Check the access mode before you scale.
- Noteservice db
healthcheckhealthcheck is mapped to a livenessProbe. Compose only reports health, but a failing liveness probe makes Kubernetes restart the container. Add a readinessProbe if you want traffic held back instead.
- Needs reviewservice worker
buildbuild is not converted. Kubernetes does not build images. Build in CI, push to a registry, and set image to the pushed tag.
- Needs reviewservice worker
env_fileenv_file is not read. Put these variables in a ConfigMap or Secret and load them with envFrom.
- Needs reviewservice worker
networksnetworks is not converted. Pods in a namespace share one cluster network. Use NetworkPolicy to restrict traffic.
- Needs reviewservice worker
imageNo image is set. Replace REPLACE_WITH_IMAGE with the registry image you push for this service.
- Notetop level
volumesEach named volume becomes a PersistentVolumeClaim of 1Gi with ReadWriteOnce. Change the size and access mode, and set storageClassName if your cluster needs one.
How the conversion works
The converter reads the compose file as YAML and walks each service. Compose and Kubernetes both describe a container with an image, a command, environment variables and ports, so those fields carry over directly. A Deployment keeps the containers running and a Service gives them a stable name inside the cluster.
| Compose field | Kubernetes output |
|---|---|
| services.<name> | Deployment (apps/v1) named after the service |
| services.<name> with ports | Service (ClusterIP) with the container port |
| image | containers[].image |
| entrypoint / command | containers[].command / containers[].args |
| environment | containers[].env (name and value) |
| deploy.replicas | spec.replicas |
| deploy.resources | resources.requests and resources.limits |
| healthcheck | livenessProbe (exec) |
| named volume | PersistentVolumeClaim (1Gi, ReadWriteOnce) and a volumeMount |
| build, depends_on, networks, bind mounts | not converted, listed as a warning |
A health check in compose only reports status. A Kubernetes liveness probe restarts the container when it fails. The converter maps healthcheck to a liveness probe because that is the closest field, and the output says so. If you want traffic held back instead, add a readinessProbe by hand.
What it cannot map
Some compose fields describe the machine that runs the container, not the workload. Kubernetes does not have an equivalent for them inside a Deployment, so the converter reports them instead of guessing.
- build: Kubernetes does not build images. Build in CI, push the image to a registry, and set the image field.
- depends_on and networks: no start order or per-network isolation. Use retries, init containers and NetworkPolicy.
- Bind mounts: a path on the host has no meaning on a node that may be replaced. Put the files in the image or a ConfigMap.
- env_file and secrets: the converter does not read files on your computer. Create a ConfigMap or Secret and reference it.
- privileged, devices, sysctls: these change the security boundary, so they need a deliberate securityContext rather than a silent copy.
Run kubectl apply --dry-run=server on the output before you apply it. The server checks the manifests against its own schema and admission rules, which this page cannot see.
kubectl apply --dry-run=server -f kubernetes.yamlAfter the conversion
Work through the warnings first. Replace REPLACE_WITH_IMAGE with a pushed image, decide how each bind mount becomes a ConfigMap or an image file, and move every secret out of the environment list. Then check the Service ports against what the application listens on, and size each PersistentVolumeClaim, which defaults to 1Gi.
Named volumes that several pods share need a storage class with ReadWriteMany support, or a single replica. A claim with the default ReadWriteOnce mode mounts on one node at a time, so the converter flags services that run more than one replica on such a volume.
If you are moving an app to a managed cluster on AWS, the EKS max pods calculator shows how many pods each node can hold before you size the replicas.
Frequently asked questions
Can this run my compose file as-is on Kubernetes?
- Not always. Compose and Kubernetes describe the same things in different ways. The converter maps the common fields: images, commands, environment, ports, replicas, resource limits, health checks and named volumes. Anything it cannot map is listed under Not converted, and you decide what to do about each item before you apply the output.
What happens to depends_on?
- It is not converted. Kubernetes starts Deployments in no fixed order, so there is no direct equivalent. Make the application retry its database and cache connections until they answer, or add an init container that waits for the dependency. The Kubernetes Service name matches the compose service name, so a connection string such as db:5432 keeps working inside the namespace.
Why does a published host port turn into a Service port?
- A host port such as 8000:80 binds a port on one machine, which Kubernetes does not do for a Deployment. The converter keeps the container port (80) as the Service port, so other pods can reach the service on the same port the app already uses. To reach the app from outside the cluster, use an Ingress or a LoadBalancer Service.
Is my compose file uploaded?
- No. The converter is JavaScript that runs in your browser tab. The page does not send the text you paste to SeaGit or any other service. Secrets written into environment values stay in the text you paste, so check the output before you commit it anywhere.
How is this different from kompose?
- kompose is the established command-line converter for compose files, and it is the better fit for a repeatable pipeline. This page is a quick first pass in the browser. It writes no files, runs nowhere else, and puts the unmapped items on screen so you can see them before you run anything.
Sources
Checked 10 October 2026.
- Compose Specification — the service, port, volume, healthcheck and deploy fields the converter reads
- Deployments (Kubernetes documentation) — the Deployment fields the output uses: replicas, selector and template
- Configure liveness, readiness and startup probes (Kubernetes documentation) — how exec probes and their timing fields behave
- Persistent Volumes (Kubernetes documentation) — access modes, and why ReadWriteOnce limits how many pods can mount a claim