What it takes to migrate from Docker Compose to Kubernetes
A team running Compose files on one or a few hosts often reaches a point where it needs cluster scheduling, rolling updates and identity controls that a single Docker host does not provide. A Compose stack converts into Kubernetes objects such as Deployments, Services, PersistentVolumeClaims and Secrets, but the networking, storage, secrets and health checks need deliberate design, so the effort depends on the stack's shape rather than its line count. A ten-service file with one database and simple HTTP traffic can be far less work than a shorter file that shares named volumes between containers, publishes host ports or relies on startup ordering.
Conversion tools such as Kompose produce a starting point, not a finished deployment. They translate what maps cleanly and skip or approximate what does not, so every generated manifest needs review against the original stack. Plan to inventory each service, volume, network, environment file and secret reference before anything is converted, and record which behaviors the Compose file relied on implicitly. Ask whoever owns the stack to confirm which services must stay reachable from outside the cluster, which can move to internal-only traffic, and which depend on a particular startup sequence.
Where the effort concentrates Networking changes the most. Compose gives each project a default network with service name resolution, while Kubernetes uses Services, DNS names and, for external access, an ingress or Gateway API implementation. Storage needs a decision for every volume: whether it becomes a PersistentVolumeClaim backed by a storage class, moves to an external database service, or is replaced by object storage. Secrets must leave environment files and move into Kubernetes Secrets or an external store, and the cluster must have encryption at rest enabled, because Secrets are stored unencrypted in etcd by default. Health checks also need rewriting: Compose healthcheck commands should become liveness and readiness probes with thresholds that match how the application starts.
What drives cost and duration The main drivers are the number of stateful services, the number of distinct network entry points, the amount of host-level configuration the stack assumed, and how many environments must match. Each stateful component needs its own backup and restore test, and each secret reference needs an owner and a rotation path. Work usually recurs after cutover: someone must maintain the manifests or Helm chart, patch images and track Kubernetes minor version support. Ask for a quote that lists the inventory and conversion review as one-time work and separates ongoing support, image updates and cluster upgrades as recurring items. Confirm with your platform team whether the cluster already exists, which distribution it runs and whether it has the storage class and ingress controller the migrated workloads will need.
Which Compose features map to Kubernetes and which need redesign
This table pairs each common Docker Compose element with its Kubernetes equivalent and sorts it into one of three groups: mechanical conversion, a decision you must make, or a redesign. Kompose can generate starting manifests for many rows, but confirm each conversion against the Kompose version you use because coverage varies by element. The main takeaway is that volumes, secrets, startup ordering and build steps need design work before any manifest is generated.
| Compose element | Kubernetes equivalent and migration notes | Conversion type |
|---|---|---|
| Services and images | Deployment and Pod template. Image references carry over, but pin tags to specific versions. | Mechanical |
| Ports and networks | Service objects for internal traffic and Ingress or Gateway API for external traffic. Compose networks map to namespaces and NetworkPolicy rules, which need design. | Decision needed |
| Environment variables | env entries in the Pod spec. Move shared or sensitive values into ConfigMaps or Secrets. | Mechanical, then review |
| Named volumes | PersistentVolumeClaims backed by a StorageClass. Choose access mode and storage class with your storage team. | Decision needed |
| Bind mounts | No direct equivalent. Host paths tie pods to specific nodes and widen the attack surface. Replace with ConfigMaps, Secrets, image contents or PVCs. | Redesign |
| Secrets | Kubernetes Secrets are stored unencrypted in etcd by default. Enable encryption at rest or use an external store through the Secrets Store CSI Driver. | Decision needed |
| depends_on | No direct equivalent. Use readiness probes for ordering and init containers for one-time setup such as schema migrations. | Redesign |
| Healthchecks and restart policies | Liveness and readiness probes replace Compose healthchecks. Controllers restart failed pods, so restart behavior follows the workload type. | Mechanical, then tune |
| Build directive | No runtime equivalent. Build images in CI, push them to a registry the cluster can reach and reference them by tag. | Redesign |
How networking, volumes and secrets change when Compose moves to a cluster
Three parts of a Compose application need rewriting by hand, and no conversion tool removes that work: service networking, published ports and persistent volumes. In Compose, each service name resolves on a private bridge network created for the project. In Kubernetes, the equivalent is a Service object, which gives a stable DNS name inside the cluster, typically in the form service-name.namespace.svc. Every service that other containers reach by name needs a Service, and the application's connection strings must be changed to match. Confirm that each hostname the application reads from environment variables or configuration files is either replaced by the cluster DNS name or pointed at an external endpoint on purpose.
Published ports are the second rewrite. A Compose ports entry maps a host port directly to a container, which has no direct equivalent in a multi-node cluster. Internal ports usually become a ClusterIP Service. Traffic from outside the cluster should go through an Ingress or a Gateway API route, depending on what your platform team has chosen. Decide that route before cutover, because the choice determines TLS termination, hostnames and how existing firewall rules are reopened. If you are replacing an older ingress controller at the same time, treat that as a separate change so that a failed cutover does not mix two sources of error.
Volumes require a PersistentVolumeClaim for each named volume that holds data, bound to a storage class that the cluster provides. Bind mounts from the host filesystem do not carry over, since pods can be scheduled to any node. Confirm with your chosen Kubernetes distribution which storage classes are available, whether they support ReadWriteOnce or ReadWriteMany access, whether volume expansion and snapshots are supported, and which Container Storage Interface drivers are installed. Test a restore from a snapshot or backup before moving production data, because a volume that cannot be restored is not a migrated volume.
Secrets need the most careful decision because the default is weak. Kubernetes stores Secrets unencrypted in etcd unless you configure encryption at rest, so values copied from a Compose .env file would sit in plain form in the cluster datastore. Before any data moves, decide three things: whether etcd encryption at rest is enabled, how RBAC limits who can read, list or watch Secrets in each namespace, and whether secrets will come from an external store through the Secrets Store CSI Driver. Each option has operational consequences, including who rotates values and how a pod recovers when the external store is unavailable. Ask your distribution vendor or platform team to confirm which of these options they support and how they are configured.
Illustrative check: before cutover, list every environment variable, bind mount and published port in the Compose file, then mark each one as a Service, a route, a PersistentVolumeClaim or a Secret reference. Any item without a mark is a gap. This list also becomes the input for your Helm chart values and for the security review of the target namespace.
Which documented tools and import paths support the move
Four tool paths and one data path connect a Compose application to Kubernetes. Each card names what the tool produces, what it leaves for your team, and what to check in your environment. No tool in this list moves application data, so the data path is covered separately and planned per application.
Kompose for first-pass translation
Kompose reads a Compose file and generates a first set of Kubernetes manifests, which gives your team a starting inventory of services, ports and volumes. It does not produce a finished target design. It will not decide how services are exposed, how secrets are stored or how persistent data is claimed. Check every generated object against your application's requirements, and confirm which Compose keys your Kompose version skips.
kubectl with reviewed manifests
Kubectl applies the manifests your team writes or reviews, and this is where the final design lives. Treat Kompose output as a draft: pin image tags, set resource requests and health probes, and move credentials out of plain environment values. Before applying, run a server-side dry run and diff against the cluster so you know exactly what changes. Verify namespaces, network policies and Pod Security labels in your own cluster.
Helm for packaging
Helm packages the reviewed manifests as a chart with templated values for each environment, such as image tags, hostnames, storage classes and replica counts. It adds release history and upgrade and rollback commands, but it does not validate the design for you, and template errors can stay hidden until render time. Render the chart with each values file, review the output, and confirm how upgrades and rollbacks behave on your cluster version.
kubeadm image listing and private registries
For clusters without internet access, kubeadm config images list shows the control plane images a given version needs, and kubeadm config images pull fetches them. Pass the image repository option to kubeadm init so the cluster pulls from your private registry. Add-on, ingress controller and application images do not appear in that list, so mirror them separately and confirm each tag exists in your registry before cutover.
Application data through native export paths
None of the tools above move application data. Databases, uploaded files and search indexes move through each application's own backup, restore or export path, run against the Compose volumes before cutover. Plan a restore test into the Kubernetes target, record the row counts or checksums you compare, and confirm each application's supported export format and version compatibility before the move starts.
How to migrate from Docker Compose to Kubernetes in stages
This sequence moves a Compose application onto Kubernetes one service at a time, so each step has a clear owner, a verified state and a way back. The result is a cluster that runs the workload, a tested cutover and a documented retirement of the old hosts.
Inventory every Compose file and dependency
Collect every Compose file, override file, environment file, named and bind-mounted volume, published port, image tag and external dependency such as a managed database, message broker or SMTP relay. Record which service depends on which, where secrets are stored today and who owns each service. Kompose can produce a first draft of manifests, but it skips or approximates several Compose features, so treat its output as input to review rather than a deliverable. The step is done when the team can point to a written inventory that the service owners have signed off.
Choose a Kubernetes version and distribution
Pick a minor version that the Kubernetes project still maintains on the day you plan to go live, and check its end-of-life date against your operating window. Confirm the distribution you choose is listed as a CNCF Certified Kubernetes offering and that it supports the APIs your manifests and Helm charts use. Ask the distribution vendor or your platform team which Kubernetes versions they support and how quickly they ship patches. The step is done when the version, distribution and support owner are recorded in the design document.
Build a pilot namespace with one service
Stand up a dedicated namespace and migrate one non-critical, stateless service first. Translate its Compose definition into Deployments, Services, ConfigMaps and Secrets, and set resource requests, limits and health probes explicitly, since Compose rarely carries them over. Apply Pod Security Admission labels for the level you have chosen, and confirm how the service receives its secrets and reaches its dependencies. The step is done when the pilot runs, its health checks pass and the team has a short list of translation decisions that the next services can reuse.
Run the stack in parallel with a data plan
Run the Compose stack and the cluster side by side for the services that are moving, and decide for each piece of data which environment owns writes. A parallel run with two writers to the same database or volume can corrupt data, so either synchronize data in one direction with a defined owner or keep the Compose side read-only while the cluster is tested. For stateful services, rehearse a restore from a backup into the cluster and record the time and steps it took. The step is done when each data store has a named writer, a tested restore or synchronization job, and a checked comparison of record counts or checksums.
Cut traffic over with a rollback path
Move traffic to the cluster by changing DNS, a load balancer target or an upstream proxy, and keep the Compose endpoint warm so the change can be reversed. Before the change, write down the rollback trigger, the person authorized to reverse it and the exact command or DNS record change that does so. Watch error rates, latency and business transactions during the first live period, and avoid changing data ownership during the same window. The step is done when traffic is served from the cluster, the rollback has been confirmed to work in practice and the outcome is recorded.
Migrate the remaining services in batches
Repeat the translation, data and cutover steps for the rest of the stack in batches that match service dependencies, starting with services that have no upstream callers. Package the shared pattern as Helm charts or Kustomize overlays so environments differ only in values, and keep the chart versions in source control. Reconcile any service that still depends on a Compose network name or a host path. The step is done when every service in the inventory has a documented owner, a deployed manifest or chart and a passing health check in the cluster.
Decommission Compose hosts after retention
Once the cluster has run every service through a full business cycle, stop the Compose services, but keep the hosts, volumes and backups for a retention period agreed with the data owners and any compliance function that applies. Confirm that no cron job, monitoring check or external system still points at the old hosts before you disable them. Remove the Compose files and secrets from the old hosts only after the retention period ends and the owners approve. The step is done when the decommission record lists what was removed, when, and where the retained data is kept.
What drives the cost and duration of a Compose to Kubernetes move
This table lists the scope factors that move the cost and duration of a Compose to Kubernetes migration, with whether each one is paid once or recurs and what to request in a written quote. Read it as a checklist to fill in before asking for a quote, because the number of services alone does not set the estimate. The main takeaway is that stateful data, cutover availability and secrets handling usually shape the effort more than the length of the Compose file.
| Driver | Why it changes effort | What to request in a quote |
|---|---|---|
| Number of services and images | Each service needs a workload, Service, configuration and image build or pull decision, so effort grows with service count and image variety | Service inventory with image sources, build contexts and a conversion mapping for each service |
| Stateful services and data volumes | Databases and file stores need storage classes, backup, restore testing and a data copy plan, which is usually one-time but drives most risk | List of stateful services, data sizes, storage requirements and the backup and restore test approach |
| Bind mounts and host networking | Host paths and host network use must be redesigned for pods, often one-time, and can require node-level changes or privilege review | Inventory of bind mounts, published ports and host network settings with the intended replacement for each |
| Secrets handling | Compose env files and inline values must move to Secrets or an external store, with encryption at rest and RBAC decisions that recur as rotation policy runs | Secrets inventory, target store, rotation approach and who owns ongoing rotation |
| External integrations | Each database, API, queue or mail service that the app calls needs network policy, DNS and credential changes, and some need separate testing | List of external endpoints, allowed egress paths and the test owner for each integration |
| Identity and SSO requirements | Login flows, OIDC or SAML clients and group mapping add configuration and testing, and some are recurring when certificates or client secrets rotate | Identity provider, protocols, client registrations and any role or group mapping rules |
| Air-gapped image distribution | Images, Helm charts and kubeadm control plane images need a private registry and an offline update path, which recurs with each release | Registry location, mirror process for images and charts, and the update procedure for disconnected sites |
| Required availability during cutover | Parallel running, DNS or ingress switchover and rollback steps add planning and test cycles that are one-time but scale with downtime limits | Acceptable interruption window, rollback criteria and whether parallel running is included |
| Team Kubernetes experience | Teams new to Kubernetes need enablement, review cycles and more handover work, which can be one-time or continue as ongoing support | Who will operate the cluster after handover, training scope and whether support or a retainer is included |
Packaging the result as Helm charts without locking in environment details
Package the converted manifests as a Helm chart only after you have decided which values change between environments. The goal is one chart that a staging cluster and a production cluster can both install without edits to the templates. Everything that differs by site, such as hostnames, ingress classes, storage classes, image repositories and registry pull secret names, belongs in values that each environment supplies. Hardcoded names copied from the Compose file are the most common reason a chart works in one cluster and fails in the next, so review every literal in the templates before the first release.
Secrets need their own rule. Do not place passwords, tokens or private keys in values.yaml or in environment values files committed to Git. Instead, the chart should reference Secret objects by name and key, and those Secrets should be created by your secrets tooling, such as an external secrets operator, the Secrets Store CSI Driver or a sealed secrets workflow, depending on what your platform team already runs. Kubernetes stores Secrets unencrypted in etcd by default, so confirm with your platform team that encryption at rest is configured before any chart depends on them. Ask which mechanism is approved for creating those Secrets in each environment.
Version the chart alongside the application release. Each application release should map to one chart version and one set of image tags, so that a rollback restores a known pair. Decide who bumps the chart version, how image tags are pinned rather than set to latest, and how a chart change is promoted from a test environment to production. If your organization uses GitOps tooling such as Argo CD, confirm whether it renders charts directly from a Git path or pulls packaged chart versions from a registry, because that choice determines how chart versions and environment values are stored and reviewed.
Test the chart against the Kubernetes minor versions you intend to run, not only the version in your lab. The Kubernetes project maintains the three most recent minor releases, and the version skew policy limits how far kubelets may lag behind kube-apiserver, so a chart tested on one minor version may meet deprecated or removed APIs on another. Run the install, upgrade and rollback steps on a cluster at each target version, and render the chart with a schema or API deprecation check before promotion. Record which Kubernetes versions each chart release has been tested against, and keep that record with the release notes.
Before you finalize conventions, confirm them with your platform team and GitOps owners. Ask which chart repository and naming rules apply, which labels and annotations are required, how values files are laid out per environment, whether Pod Security Admission labels are set at the namespace level rather than in the chart, and who approves a chart release. These decisions shape the chart structure more than the conversion itself, so settle them early. Treat the answers as the acceptance criteria for the chart, and check them again whenever the platform team changes its cluster or delivery tooling.
What usually goes wrong in a Compose to Kubernetes migration
Most failed Compose to Kubernetes migrations trace back to a handful of recurring gaps: data handled without an owner, secrets carried over unchanged, and cluster behavior assumed to match a single Compose host. Each risk below names the check to run before cutover so the problem is caught in staging rather than in production.
Incomplete data copies and dual writes
Volumes copied while Compose is still writing leave databases and uploads inconsistent, and a parallel run lets both systems accept writes to the same data. Before the parallel run, choose one system of record per dataset, freeze writes or use a consistent database dump, and verify row counts and file checksums after the copy. Confirm that the Compose stack is stopped or read-only for each cutover step.
Secrets committed to charts
Values files, environment blocks and Helm templates often carry passwords copied from the Compose file, and those end up in Git history. Kubernetes stores Secret objects unencrypted in etcd by default. Move credentials into Secret references fed by an external store, enable encryption at rest for etcd, and scan the chart repository for literal values before the first commit.
Health checks that do not reflect readiness
A Compose healthcheck that only confirms a process is alive can let Kubernetes route traffic to a pod that has not finished loading its schema or cache. Define separate liveness and readiness probes, and make the readiness probe test the dependencies the service needs to answer requests. Test failure paths by stopping the database and confirming the pod is removed from service rather than restarted in a loop.
Service discovery assumptions that break in cluster DNS
Compose resolves service names on a single bridge network, and hard-coded hostnames, localhost calls or fixed IP addresses fail in cluster DNS. Services become reachable at names such as the service name inside the namespace, and cross-namespace calls need the fully qualified form. Audit every connection string and environment variable, replace them with Service names, and confirm resolution from inside a pod with a test command before cutover.
Containers running as root under Pod Security Standards
Many Compose images run as root or need extra Linux capabilities, and such pods fail admission once a namespace enforces the Baseline or Restricted level. Decide the target level per namespace, set runAsNonRoot and drop capabilities in the workload spec, and rebuild images where a process writes to paths owned by root. Use the namespace warn and audit modes first so violations appear before enforcement blocks a deployment.
Unplanned Kubernetes version upgrades
A cluster that is upgraded during the migration can change API availability and behavior partway through the work, and the migration team then debugs two moving parts at once. Pin the cluster version for the project window and record it in the runbook. Schedule any required upgrade as a separate change that follows the version skew policy, one minor version at a time, and confirm that the Helm charts render against the target API versions.
Can our team migrate from Docker Compose to Kubernetes without a partner?
Can an internal team migrate from Docker Compose to Kubernetes on its own?
Yes, many internal teams can, provided they have someone who knows Kubernetes well enough to write and review manifests, a clear owner for each application, and time to test before cutover. The Compose file is usually the easy part. The harder work is deciding how each service talks to the others, where its data lives, how secrets are supplied, and how traffic moves from the old host to the new cluster without an outage. Teams with no prior cluster operations experience tend to underestimate the testing and rollback planning. A short internal pilot on one non-critical stack is a practical way to find out whether your team has the skills before committing to the full estate.
What drives the cost of a Docker Compose to Kubernetes migration?
The main cost driver is the number and complexity of the services being moved, followed by how many of them hold state. Stateless web and API services are typically straightforward. Databases, message brokers, file storage and anything with bind-mounted data add work in storage design, backup, and cutover testing. Other factors include the number of environments (development, staging, production), integrations with identity, monitoring and CI/CD, and whether the target cluster already exists. Costs are mostly one-time for the migration itself, then recur as your team operates and upgrades the cluster and charts. Ask any provider for a fixed-scope quote that lists the services in scope, the deliverables (manifests or Helm charts, runbooks, test evidence), the environments covered, and what is excluded.
What should a fixed-scope quote for this migration include?
A fixed-scope quote should name every Compose service and its status in scope, state the target cluster and distribution, and list the deliverables in writing. Look for an inventory of volumes, networks, secrets and environment variables, an explanation of how each will be converted, and a statement of what the tooling does not convert automatically. It should also cover packaging (plain manifests, Kustomize or Helm charts), testing and cutover steps, rollback criteria, documentation and knowledge transfer. Clarify what is excluded, such as application code changes, data migration volumes, or new features. Estimates should follow from this written scope rather than from a general description, so ask for the assumptions behind any effort figure.
How long does a migration from Docker Compose to Kubernetes take?
Duration depends mainly on how many services are involved and how many of them are stateful, since each database or storage-backed service needs its own design, backup and cutover plan. Application teams also need time to confirm behavior, and change windows set the pace for production cutover. Migrations with few stateful services and an existing cluster move faster than those requiring new storage classes, identity integration or multiple environments. Because these factors vary widely, we do not publish a general timeline. Request a schedule tied to the written scope, with milestones for each environment and a named set of dependencies on your side.
What does the migration need from our team?
Several inputs are needed before work starts, and delays usually come from missing ones. You will need named application owners who can confirm behavior and sign off on tests, read access to the Compose files, environment files and any data volumes, and a way to supply secrets securely. The work also needs cluster access, including namespaces, RBAC for the people running the migration, and an image registry the cluster can reach. Finally, plan for change windows for production cutover and a rollback path agreed with operations. Confirm each of these items in the written scope so responsibilities are clear on both sides.
Why does stateful data change the migration plan?
Stateless services can usually be redeployed and switched over with little risk, but stateful services need careful planning. Databases, queues and file stores require persistent volumes, backup and restore testing, and a decision about whether data is copied in advance, replicated, or moved during a short window. Compose volumes often use bind mounts or local paths that do not carry over directly, so storage classes must be chosen and tested. Secrets also need attention: Kubernetes stores Secrets unencrypted in etcd by default, so encryption at rest and least-privilege access should be configured as part of the design. Ask which stateful services are in scope and how each will be backed up and restored before cutover.
What do engineers typically get wrong when moving Compose files to Kubernetes?
Common issues include assuming the converter output is production ready, leaving service discovery and port mapping to chance, and forgetting health checks, resource requests and limits. Teams also miss startup ordering dependencies that Compose handled with depends_on, and they often recreate secrets as plain environment variables without a rotation plan. Networking is a frequent problem: Compose networks become namespaces, network policies and ingress, and each needs explicit design. Verify each migrated service in a staging cluster with realistic data, check logs and probes, and confirm rollback steps work before cutover. Converters help with first drafts, but they do not replace review of every resource.
How can we check that the migration worked before cutover?
Verification should compare behavior, not just whether pods start. Run each service in a staging cluster with production-like configuration and data, then test functional paths, integrations, scheduled jobs and failure behavior such as restarts and rollbacks. Confirm that backups of stateful services can be restored into the new environment. Review access controls, secret handling and network exposure against your own security baseline. Keep test results and runbooks as evidence for change approval. Ask any provider to describe the test plan, acceptance criteria and who signs off each step, as these should be part of the written scope.
How DeployOpen scopes and delivers a Kubernetes migration
DeployOpen starts by inventorying the Compose files, images, volumes, secrets and network paths your application depends on, then agrees the conversion approach in writing before any manifests change. The work runs in your own clusters and accounts, and the result is packaged as Helm charts your team can review, run and upgrade.
How we scope
- Inventory every Compose file, override file, image tag, volume, secret and published port the application uses today
- Record which services Kompose converts directly and which need hand-written manifests or Helm templates
- Agree the written scope, deliverables and timeline with you before any conversion work begins
How we build
- Rewrite service discovery, ingress, persistent volume claims and secret handling for the target cluster rather than trusting raw conversion output
- Package the application as Helm charts with values files per environment, then test install, upgrade and rollback in a non-production cluster
- Verify pod security settings against the Baseline and Restricted Pod Security Standards and confirm secrets are encrypted at rest before go-live
How we hand over
- Deliver Helm charts, values files, runbooks and a cutover and rollback procedure written for your operations team
- Walk your engineers through the chart structure, environment promotion and how each Compose behavior maps to a Kubernetes resource
- Document open items, unsupported Compose features and the decisions made during the migration so they remain traceable after handover
How we support
- Offer ongoing support, chart upgrades and continuous testing as a retainer after handover, if your organization wants it
- Plan chart and application updates around the Kubernetes minor version release cadence and the version skew policy
- Agree support scope, response expectations and who owns each component in writing before the retainer starts

