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 , 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 levelnetworks

    Top-level networks are not converted. Kubernetes uses one network per namespace.

  • Needs reviewservice webdepends_on

    depends_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 webports

    Host port 3000 is not exposed. The Service uses container port 3000 inside the cluster. Publish it with an Ingress or a LoadBalancer Service.

  • Noteservice webhealthcheck

    healthcheck 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 webvolumes

    Replicas 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 dbhealthcheck

    healthcheck 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 workerbuild

    build is not converted. Kubernetes does not build images. Build in CI, push to a registry, and set image to the pushed tag.

  • Needs reviewservice workerenv_file

    env_file is not read. Put these variables in a ConfigMap or Secret and load them with envFrom.

  • Needs reviewservice workernetworks

    networks is not converted. Pods in a namespace share one cluster network. Use NetworkPolicy to restrict traffic.

  • Needs reviewservice workerimage

    No image is set. Replace REPLACE_WITH_IMAGE with the registry image you push for this service.

  • Notetop levelvolumes

    Each 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 fieldKubernetes output
services.<name>Deployment (apps/v1) named after the service
services.<name> with portsService (ClusterIP) with the container port
imagecontainers[].image
entrypoint / commandcontainers[].command / containers[].args
environmentcontainers[].env (name and value)
deploy.replicasspec.replicas
deploy.resourcesresources.requests and resources.limits
healthchecklivenessProbe (exec)
named volumePersistentVolumeClaim (1Gi, ReadWriteOnce) and a volumeMount
build, depends_on, networks, bind mountsnot 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.yaml

After 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.

  1. Compose Specification — the service, port, volume, healthcheck and deploy fields the converter reads
  2. Deployments (Kubernetes documentation) — the Deployment fields the output uses: replicas, selector and template
  3. Configure liveness, readiness and startup probes (Kubernetes documentation) — how exec probes and their timing fields behave
  4. Persistent Volumes (Kubernetes documentation) — access modes, and why ReadWriteOnce limits how many pods can mount a claim