[{"data":1,"prerenderedAt":1758},["ShallowReactive",2],{"blog-en-docker-compose-to-kubernetes-migration":3,"blog-en-docker-compose-to-kubernetes-migration-alt":439},{"id":4,"title":5,"author":6,"body":7,"date":1746,"description":1747,"extension":1748,"image":259,"locale":1749,"meta":1750,"navigation":439,"path":1751,"seo":1752,"stem":1753,"tags":1754,"__hash__":1757},"blog\u002Fblog\u002Fen\u002Fdocker-compose-to-kubernetes-migration.md","Migration Guide: Docker Compose to Kubernetes","Kubo Team",{"type":8,"value":9,"toc":1722},"minimark",[10,14,24,29,32,157,166,174,178,181,186,253,457,477,481,489,493,569,573,625,640,644,727,736,740,754,758,828,834,1022,1026,1029,1297,1304,1308,1312,1315,1407,1414,1418,1424,1467,1487,1490,1493,1508,1512,1515,1519,1556,1648,1661,1665,1668,1700,1710,1718],[11,12,13],"p",{},"Docker Compose excels for development and simple deployments, but production environments demand the scalability, high availability, and operational automation that Kubernetes provides. However, migrating from Docker Compose to Kubernetes is not just about rewriting YAML. Success requires understanding the fundamental architectural differences in networking, storage, and secret management.",[11,15,16,23],{},[17,18,22],"a",{"href":19,"rel":20},"https:\u002F\u002Fkubo.hexabase.io\u002F",[21],"nofollow","Kubo"," provides production-grade Kubernetes infrastructure and supports smooth migrations from Docker Compose. This article walks through every phase of the migration process.",[25,26,28],"h2",{"id":27},"fundamental-differences-between-docker-compose-and-kubernetes","Fundamental Differences Between Docker Compose and Kubernetes",[11,30,31],{},"Before starting a migration, understanding the architectural differences between the two systems is essential.",[33,34,35,51],"table",{},[36,37,38],"thead",{},[39,40,41,45,48],"tr",{},[42,43,44],"th",{},"Aspect",[42,46,47],{},"Docker Compose",[42,49,50],{},"Kubernetes",[52,53,54,66,82,96,107,118,135,146],"tbody",{},[39,55,56,60,63],{},[57,58,59],"td",{},"Scope",[57,61,62],{},"Single host",[57,64,65],{},"Multi-node cluster",[39,67,68,71,79],{},[57,69,70],{},"Scaling",[57,72,73,74,78],{},"Manual (",[75,76,77],"code",{},"scale"," option)",[57,80,81],{},"Automatic (HPA \u002F VPA)",[39,83,84,87,93],{},[57,85,86],{},"Health Checks",[57,88,89,92],{},[75,90,91],{},"healthcheck"," directive",[57,94,95],{},"liveness \u002F readiness \u002F startup Probes",[39,97,98,101,104],{},[57,99,100],{},"Networking",[57,102,103],{},"Bridge networks",[57,105,106],{},"Service \u002F Ingress \u002F NetworkPolicy",[39,108,109,112,115],{},[57,110,111],{},"Storage",[57,113,114],{},"Bind mounts \u002F volumes",[57,116,117],{},"PersistentVolume \u002F PersistentVolumeClaim",[39,119,120,123,132],{},[57,121,122],{},"Secrets",[57,124,125,128,129],{},[75,126,127],{},".env"," files \u002F ",[75,130,131],{},"secrets",[57,133,134],{},"Secret \u002F External Secrets Operator",[39,136,137,140,143],{},[57,138,139],{},"Service Discovery",[57,141,142],{},"Container\u002Fservice names",[57,144,145],{},"DNS-based Services",[39,147,148,151,154],{},[57,149,150],{},"Rolling Updates",[57,152,153],{},"None",[57,155,156],{},"Deployment strategy",[11,158,159,160,165],{},"The ",[17,161,164],{"href":162,"rel":163},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Ftasks\u002Fconfigure-pod-container\u002Ftranslate-compose-kubernetes\u002F",[21],"Kubernetes official documentation"," introduces the conversion process using Kompose, but this is only a starting point.",[11,167,168,173],{},[17,169,172],{"href":170,"rel":171},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fcaptain-ai\u002F",[21],"Captain.AI"," can assist your migration process with AI — from analyzing Docker Compose files to optimizing Kubernetes manifests.",[25,175,177],{"id":176},"phase-1-assessment-and-architecture-audit","Phase 1: Assessment and Architecture Audit",[11,179,180],{},"The first step is thoroughly analyzing your current Docker Compose configuration.",[182,183,185],"h3",{"id":184},"checklist","Checklist",[187,188,189,200,210,216,229,239],"ul",{},[190,191,192,196,197],"li",{},[193,194,195],"strong",{},"Service dependencies",": Map startup order defined by ",[75,198,199],{},"depends_on",[190,201,202,205,206,209],{},[193,203,204],{},"Volume mappings",": Distinguish development bind mounts (",[75,207,208],{},".\u002Fsrc:\u002Fapp",") from persistent data",[190,211,212,215],{},[193,213,214],{},"Network configuration",": Identify custom networks and inter-service communication",[190,217,218,221,222,224,225,228],{},[193,219,220],{},"Environment variables",": Catalog ",[75,223,127],{}," files, ",[75,226,227],{},"environment"," directives, and secrets",[190,230,231,234,235,238],{},[193,232,233],{},"Build contexts",": Identify ",[75,236,237],{},"build"," directives (K8S requires pre-built images)",[190,240,241,244,245,248,249,252],{},[193,242,243],{},"Resource constraints",": Note ",[75,246,247],{},"mem_limit",", ",[75,250,251],{},"cpus",", and similar settings",[254,255,260],"pre",{"className":256,"code":257,"language":258,"meta":259,"style":259},"language-yaml shiki shiki-themes tokyo-night","# Typical Docker Compose configuration\nservices:\n  web:\n    build: .\u002Fweb\n    ports:\n      - \"8080:8080\"\n    environment:\n      - database_url=postgres:--db:5432-myapp\n    depends_on:\n      - db\n    volumes:\n      - .-web:-app  # development bind mount\n  \n  db:\n    image: postgres:16\n    volumes:\n      - db-data:-var-lib-postgresql-data\n    environment:\n      - POSTGRES_PASSWORD=secret\n\nvolumes:\n  db-data:\n","yaml","",[75,261,262,271,282,290,303,311,327,335,343,351,359,367,378,385,393,404,411,419,426,434,441,449],{"__ignoreMap":259},[263,264,267],"span",{"class":265,"line":266},"line",1,[263,268,270],{"class":269},"sbD-w","# Typical Docker Compose configuration\n",[263,272,274,278],{"class":265,"line":273},2,[263,275,277],{"class":276},"s0U2E","services",[263,279,281],{"class":280},"sAklC",":\n",[263,283,285,288],{"class":265,"line":284},3,[263,286,287],{"class":276},"  web",[263,289,281],{"class":280},[263,291,293,296,299],{"class":265,"line":292},4,[263,294,295],{"class":276},"    build",[263,297,298],{"class":280},":",[263,300,302],{"class":301},"sPY7s"," .\u002Fweb\n",[263,304,306,309],{"class":265,"line":305},5,[263,307,308],{"class":276},"    ports",[263,310,281],{"class":280},[263,312,314,318,321,324],{"class":265,"line":313},6,[263,315,317],{"class":316},"sgJMe","      -",[263,319,320],{"class":280}," \"",[263,322,323],{"class":301},"8080:8080",[263,325,326],{"class":280},"\"\n",[263,328,330,333],{"class":265,"line":329},7,[263,331,332],{"class":276},"    environment",[263,334,281],{"class":280},[263,336,338,340],{"class":265,"line":337},8,[263,339,317],{"class":316},[263,341,342],{"class":301}," database_url=postgres:--db:5432-myapp\n",[263,344,346,349],{"class":265,"line":345},9,[263,347,348],{"class":276},"    depends_on",[263,350,281],{"class":280},[263,352,354,356],{"class":265,"line":353},10,[263,355,317],{"class":316},[263,357,358],{"class":301}," db\n",[263,360,362,365],{"class":265,"line":361},11,[263,363,364],{"class":276},"    volumes",[263,366,281],{"class":280},[263,368,370,372,375],{"class":265,"line":369},12,[263,371,317],{"class":316},[263,373,374],{"class":301}," .-web:-app",[263,376,377],{"class":269},"  # development bind mount\n",[263,379,381],{"class":265,"line":380},13,[263,382,384],{"class":383},"sGX4V","  \n",[263,386,388,391],{"class":265,"line":387},14,[263,389,390],{"class":276},"  db",[263,392,281],{"class":280},[263,394,396,399,401],{"class":265,"line":395},15,[263,397,398],{"class":276},"    image",[263,400,298],{"class":280},[263,402,403],{"class":301}," postgres:16\n",[263,405,407,409],{"class":265,"line":406},16,[263,408,364],{"class":276},[263,410,281],{"class":280},[263,412,414,416],{"class":265,"line":413},17,[263,415,317],{"class":316},[263,417,418],{"class":301}," db-data:-var-lib-postgresql-data\n",[263,420,422,424],{"class":265,"line":421},18,[263,423,332],{"class":276},[263,425,281],{"class":280},[263,427,429,431],{"class":265,"line":428},19,[263,430,317],{"class":316},[263,432,433],{"class":301}," POSTGRES_PASSWORD=secret\n",[263,435,437],{"class":265,"line":436},20,[263,438,440],{"emptyLinePlaceholder":439},true,"\n",[263,442,444,447],{"class":265,"line":443},21,[263,445,446],{"class":276},"volumes",[263,448,281],{"class":280},[263,450,452,455],{"class":265,"line":451},22,[263,453,454],{"class":276},"  db-data",[263,456,281],{"class":280},[11,458,459,462,463,466,467,470,471,476],{},[193,460,461],{},"Critical",": Development bind mounts (",[75,464,465],{},".\u002Fweb:\u002Fapp",") ",[193,468,469],{},"cannot be migrated"," to Kubernetes. Application code must be included in the image. The ",[17,472,475],{"href":473,"rel":474},"https:\u002F\u002Finstitute.sfeir.com\u002Fen\u002Fkubernetes-training\u002Fmigrate-docker-compose-kubernetes-guide-transition\u002F",[21],"SFEIR migration guide"," emphasizes this point.",[25,478,480],{"id":479},"phase-2-automated-conversion-with-kompose","Phase 2: Automated Conversion with Kompose",[11,482,483,488],{},[17,484,487],{"href":485,"rel":486},"https:\u002F\u002Fkompose.io\u002F",[21],"Kompose"," automatically converts Docker Compose files into Kubernetes manifests.",[182,490,492],{"id":491},"installation","Installation",[254,494,498],{"className":495,"code":496,"language":497,"meta":259,"style":259},"language-bash shiki shiki-themes tokyo-night","# macOS\nbrew install kompose\n\n# Linux\ncurl -L https:\u002F\u002Fgithub.com\u002Fkubernetes\u002Fkompose\u002Freleases\u002Fdownload\u002Fv1.34.0\u002Fkompose-linux-amd64 -o kompose\nchmod +x kompose && sudo mv .\u002Fkompose \u002Fusr\u002Flocal\u002Fbin\u002Fkompose\n","bash",[75,499,500,505,517,521,526,543],{"__ignoreMap":259},[263,501,502],{"class":265,"line":266},[263,503,504],{"class":269},"# macOS\n",[263,506,507,511,514],{"class":265,"line":273},[263,508,510],{"class":509},"sE3pS","brew",[263,512,513],{"class":301}," install",[263,515,516],{"class":301}," kompose\n",[263,518,519],{"class":265,"line":284},[263,520,440],{"emptyLinePlaceholder":439},[263,522,523],{"class":265,"line":292},[263,524,525],{"class":269},"# Linux\n",[263,527,528,531,535,538,541],{"class":265,"line":305},[263,529,530],{"class":509},"curl",[263,532,534],{"class":533},"sT800"," -L",[263,536,537],{"class":301}," https:\u002F\u002Fgithub.com\u002Fkubernetes\u002Fkompose\u002Freleases\u002Fdownload\u002Fv1.34.0\u002Fkompose-linux-amd64",[263,539,540],{"class":533}," -o",[263,542,516],{"class":301},[263,544,545,548,551,554,557,560,563,566],{"class":265,"line":313},[263,546,547],{"class":509},"chmod",[263,549,550],{"class":301}," +x",[263,552,553],{"class":301}," kompose",[263,555,556],{"class":280}," &&",[263,558,559],{"class":509}," sudo",[263,561,562],{"class":301}," mv",[263,564,565],{"class":301}," .\u002Fkompose",[263,567,568],{"class":301}," \u002Fusr\u002Flocal\u002Fbin\u002Fkompose\n",[182,570,572],{"id":571},"basic-conversion","Basic Conversion",[254,574,576],{"className":495,"code":575,"language":497,"meta":259,"style":259},"# Convert docker-compose.yml to Kubernetes manifests\nkompose convert\n\n# Example output:\n# INFO Kubernetes file \"web-service.yaml\" created\n# INFO Kubernetes file \"db-service.yaml\" created\n# INFO Kubernetes file \"web-deployment.yaml\" created\n# INFO Kubernetes file \"db-deployment.yaml\" created\n# INFO Kubernetes file \"db-data-persistentvolumeclaim.yaml\" created\n",[75,577,578,583,591,595,600,605,610,615,620],{"__ignoreMap":259},[263,579,580],{"class":265,"line":266},[263,581,582],{"class":269},"# Convert docker-compose.yml to Kubernetes manifests\n",[263,584,585,588],{"class":265,"line":273},[263,586,587],{"class":509},"kompose",[263,589,590],{"class":301}," convert\n",[263,592,593],{"class":265,"line":284},[263,594,440],{"emptyLinePlaceholder":439},[263,596,597],{"class":265,"line":292},[263,598,599],{"class":269},"# Example output:\n",[263,601,602],{"class":265,"line":305},[263,603,604],{"class":269},"# INFO Kubernetes file \"web-service.yaml\" created\n",[263,606,607],{"class":265,"line":313},[263,608,609],{"class":269},"# INFO Kubernetes file \"db-service.yaml\" created\n",[263,611,612],{"class":265,"line":329},[263,613,614],{"class":269},"# INFO Kubernetes file \"web-deployment.yaml\" created\n",[263,616,617],{"class":265,"line":337},[263,618,619],{"class":269},"# INFO Kubernetes file \"db-deployment.yaml\" created\n",[263,621,622],{"class":265,"line":345},[263,623,624],{"class":269},"# INFO Kubernetes file \"db-data-persistentvolumeclaim.yaml\" created\n",[11,626,627,628,631,632,635,636,639],{},"Kompose generates two Kubernetes resources from each Docker Compose service: a ",[193,629,630],{},"Deployment"," and a ",[193,633,634],{},"Service",". Volumes are converted to ",[193,637,638],{},"PersistentVolumeClaims",".",[182,641,643],{"id":642},"customization-with-kompose-labels","Customization with Kompose Labels",[254,645,647],{"className":256,"code":646,"language":258,"meta":259,"style":259},"services:\n  web:\n    image: myapp:latest\n    ports:\n      - \"8080:8080\"\n    labels:\n      kompose.service.type: LoadBalancer\n      kompose.service.expose: \"myapp.example.com\"\n      kompose.image-pull-policy: Always\n",[75,648,649,655,661,670,676,686,693,703,717],{"__ignoreMap":259},[263,650,651,653],{"class":265,"line":266},[263,652,277],{"class":276},[263,654,281],{"class":280},[263,656,657,659],{"class":265,"line":273},[263,658,287],{"class":276},[263,660,281],{"class":280},[263,662,663,665,667],{"class":265,"line":284},[263,664,398],{"class":276},[263,666,298],{"class":280},[263,668,669],{"class":301}," myapp:latest\n",[263,671,672,674],{"class":265,"line":292},[263,673,308],{"class":276},[263,675,281],{"class":280},[263,677,678,680,682,684],{"class":265,"line":305},[263,679,317],{"class":316},[263,681,320],{"class":280},[263,683,323],{"class":301},[263,685,326],{"class":280},[263,687,688,691],{"class":265,"line":313},[263,689,690],{"class":276},"    labels",[263,692,281],{"class":280},[263,694,695,698,700],{"class":265,"line":329},[263,696,697],{"class":276},"      kompose.service.type",[263,699,298],{"class":280},[263,701,702],{"class":301}," LoadBalancer\n",[263,704,705,708,710,712,715],{"class":265,"line":337},[263,706,707],{"class":276},"      kompose.service.expose",[263,709,298],{"class":280},[263,711,320],{"class":280},[263,713,714],{"class":301},"myapp.example.com",[263,716,326],{"class":280},[263,718,719,722,724],{"class":265,"line":345},[263,720,721],{"class":276},"      kompose.image-pull-policy",[263,723,298],{"class":280},[263,725,726],{"class":301}," Always\n",[11,728,729,730,735],{},"However, as the ",[17,731,734],{"href":732,"rel":733},"https:\u002F\u002Fsupport.tools\u002Fdocker-compose-to-kubernetes-migration-guide\u002F",[21],"Support Tools migration guide"," points out, Kompose \"creates a functional base but is rarely optimal for production,\" necessitating refinement in the next phase.",[25,737,739],{"id":738},"phase-3-production-ready-with-helm-kustomize","Phase 3: Production-Ready with Helm \u002F Kustomize",[11,741,742,743,748,749,639],{},"Elevate Kompose-generated manifests to production quality using ",[17,744,747],{"href":745,"rel":746},"https:\u002F\u002Fhelm.sh\u002F",[21],"Helm"," or ",[17,750,753],{"href":751,"rel":752},"https:\u002F\u002Fkustomize.io\u002F",[21],"Kustomize",[182,755,757],{"id":756},"migrating-to-helm-charts","Migrating to Helm Charts",[254,759,761],{"className":495,"code":760,"language":497,"meta":259,"style":259},"# Scaffold a Helm chart\nhelm create myapp\n\n# Directory structure\nmyapp\u002F\n  Chart.yaml\n  values.yaml\n  templates\u002F\n    deployment.yaml\n    service.yaml\n    ingress.yaml\n    hpa.yaml\n",[75,762,763,768,779,783,788,793,798,803,808,813,818,823],{"__ignoreMap":259},[263,764,765],{"class":265,"line":266},[263,766,767],{"class":269},"# Scaffold a Helm chart\n",[263,769,770,773,776],{"class":265,"line":273},[263,771,772],{"class":509},"helm",[263,774,775],{"class":301}," create",[263,777,778],{"class":301}," myapp\n",[263,780,781],{"class":265,"line":284},[263,782,440],{"emptyLinePlaceholder":439},[263,784,785],{"class":265,"line":292},[263,786,787],{"class":269},"# Directory structure\n",[263,789,790],{"class":265,"line":305},[263,791,792],{"class":509},"myapp\u002F\n",[263,794,795],{"class":265,"line":313},[263,796,797],{"class":509},"  Chart.yaml\n",[263,799,800],{"class":265,"line":329},[263,801,802],{"class":509},"  values.yaml\n",[263,804,805],{"class":265,"line":337},[263,806,807],{"class":509},"  templates\u002F\n",[263,809,810],{"class":265,"line":345},[263,811,812],{"class":509},"    deployment.yaml\n",[263,814,815],{"class":265,"line":353},[263,816,817],{"class":509},"    service.yaml\n",[263,819,820],{"class":265,"line":361},[263,821,822],{"class":509},"    ingress.yaml\n",[263,824,825],{"class":265,"line":369},[263,826,827],{"class":509},"    hpa.yaml\n",[11,829,830,831,298],{},"Externalize environment-specific settings in ",[75,832,833],{},"values.yaml",[254,835,837],{"className":256,"code":836,"language":258,"meta":259,"style":259},"# values.yaml\nreplicaCount: 3\nimage:\n  repository: harbor.example.com\u002Fmyproject\u002Fweb\n  tag: \"1.0.0\"\n  pullPolicy: IfNotPresent\nresources:\n  limits:\n    cpu: 500m\n    memory: 512Mi\n  requests:\n    cpu: 100m\n    memory: 128Mi\ningress:\n  enabled: true\n  hosts:\n    - host: myapp.example.com\n      paths:\n        - path: \u002F\n          pathType: Prefix\n",[75,838,839,844,855,862,872,886,896,903,910,920,930,937,946,955,962,972,979,992,999,1012],{"__ignoreMap":259},[263,840,841],{"class":265,"line":266},[263,842,843],{"class":269},"# values.yaml\n",[263,845,846,849,851],{"class":265,"line":273},[263,847,848],{"class":276},"replicaCount",[263,850,298],{"class":280},[263,852,854],{"class":853},"sOJ5S"," 3\n",[263,856,857,860],{"class":265,"line":284},[263,858,859],{"class":276},"image",[263,861,281],{"class":280},[263,863,864,867,869],{"class":265,"line":292},[263,865,866],{"class":276},"  repository",[263,868,298],{"class":280},[263,870,871],{"class":301}," harbor.example.com\u002Fmyproject\u002Fweb\n",[263,873,874,877,879,881,884],{"class":265,"line":305},[263,875,876],{"class":276},"  tag",[263,878,298],{"class":280},[263,880,320],{"class":280},[263,882,883],{"class":301},"1.0.0",[263,885,326],{"class":280},[263,887,888,891,893],{"class":265,"line":313},[263,889,890],{"class":276},"  pullPolicy",[263,892,298],{"class":280},[263,894,895],{"class":301}," IfNotPresent\n",[263,897,898,901],{"class":265,"line":329},[263,899,900],{"class":276},"resources",[263,902,281],{"class":280},[263,904,905,908],{"class":265,"line":337},[263,906,907],{"class":276},"  limits",[263,909,281],{"class":280},[263,911,912,915,917],{"class":265,"line":345},[263,913,914],{"class":276},"    cpu",[263,916,298],{"class":280},[263,918,919],{"class":301}," 500m\n",[263,921,922,925,927],{"class":265,"line":353},[263,923,924],{"class":276},"    memory",[263,926,298],{"class":280},[263,928,929],{"class":301}," 512Mi\n",[263,931,932,935],{"class":265,"line":361},[263,933,934],{"class":276},"  requests",[263,936,281],{"class":280},[263,938,939,941,943],{"class":265,"line":369},[263,940,914],{"class":276},[263,942,298],{"class":280},[263,944,945],{"class":301}," 100m\n",[263,947,948,950,952],{"class":265,"line":380},[263,949,924],{"class":276},[263,951,298],{"class":280},[263,953,954],{"class":301}," 128Mi\n",[263,956,957,960],{"class":265,"line":387},[263,958,959],{"class":276},"ingress",[263,961,281],{"class":280},[263,963,964,967,969],{"class":265,"line":395},[263,965,966],{"class":276},"  enabled",[263,968,298],{"class":280},[263,970,971],{"class":853}," true\n",[263,973,974,977],{"class":265,"line":406},[263,975,976],{"class":276},"  hosts",[263,978,281],{"class":280},[263,980,981,984,987,989],{"class":265,"line":413},[263,982,983],{"class":316},"    -",[263,985,986],{"class":276}," host",[263,988,298],{"class":280},[263,990,991],{"class":301}," myapp.example.com\n",[263,993,994,997],{"class":265,"line":421},[263,995,996],{"class":276},"      paths",[263,998,281],{"class":280},[263,1000,1001,1004,1007,1009],{"class":265,"line":428},[263,1002,1003],{"class":316},"        -",[263,1005,1006],{"class":276}," path",[263,1008,298],{"class":280},[263,1010,1011],{"class":301}," \u002F\n",[263,1013,1014,1017,1019],{"class":265,"line":436},[263,1015,1016],{"class":276},"          pathType",[263,1018,298],{"class":280},[263,1020,1021],{"class":301}," Prefix\n",[182,1023,1025],{"id":1024},"essential-additions","Essential Additions",[11,1027,1028],{},"Add production-critical configurations that Kompose doesn't auto-generate:",[254,1030,1032],{"className":256,"code":1031,"language":258,"meta":259,"style":259},"# Health checks (Probes)\nlivenessProbe:\n  httpGet:\n    path: \u002Fhealthz\n    port: 8080\n  initialDelaySeconds: 15\n  periodSeconds: 10\nreadinessProbe:\n  httpGet:\n    path: \u002Fready\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 5\n\n# Resource limits\nresources:\n  requests:\n    cpu: 100m\n    memory: 128Mi\n  limits:\n    cpu: 500m\n    memory: 512Mi\n\n# Pod Disruption Budget\napiVersion: policy\u002Fv1\nkind: PodDisruptionBudget\nmetadata:\n  name: web-pdb\nspec:\n  minAvailable: 1\n  selector:\n    matchLabels:\n      app: web\n",[75,1033,1034,1039,1046,1053,1063,1073,1083,1093,1100,1106,1115,1123,1132,1140,1144,1149,1155,1161,1169,1177,1183,1191,1199,1204,1210,1221,1232,1240,1251,1259,1270,1278,1286],{"__ignoreMap":259},[263,1035,1036],{"class":265,"line":266},[263,1037,1038],{"class":269},"# Health checks (Probes)\n",[263,1040,1041,1044],{"class":265,"line":273},[263,1042,1043],{"class":276},"livenessProbe",[263,1045,281],{"class":280},[263,1047,1048,1051],{"class":265,"line":284},[263,1049,1050],{"class":276},"  httpGet",[263,1052,281],{"class":280},[263,1054,1055,1058,1060],{"class":265,"line":292},[263,1056,1057],{"class":276},"    path",[263,1059,298],{"class":280},[263,1061,1062],{"class":301}," \u002Fhealthz\n",[263,1064,1065,1068,1070],{"class":265,"line":305},[263,1066,1067],{"class":276},"    port",[263,1069,298],{"class":280},[263,1071,1072],{"class":853}," 8080\n",[263,1074,1075,1078,1080],{"class":265,"line":313},[263,1076,1077],{"class":276},"  initialDelaySeconds",[263,1079,298],{"class":280},[263,1081,1082],{"class":853}," 15\n",[263,1084,1085,1088,1090],{"class":265,"line":329},[263,1086,1087],{"class":276},"  periodSeconds",[263,1089,298],{"class":280},[263,1091,1092],{"class":853}," 10\n",[263,1094,1095,1098],{"class":265,"line":337},[263,1096,1097],{"class":276},"readinessProbe",[263,1099,281],{"class":280},[263,1101,1102,1104],{"class":265,"line":345},[263,1103,1050],{"class":276},[263,1105,281],{"class":280},[263,1107,1108,1110,1112],{"class":265,"line":353},[263,1109,1057],{"class":276},[263,1111,298],{"class":280},[263,1113,1114],{"class":301}," \u002Fready\n",[263,1116,1117,1119,1121],{"class":265,"line":361},[263,1118,1067],{"class":276},[263,1120,298],{"class":280},[263,1122,1072],{"class":853},[263,1124,1125,1127,1129],{"class":265,"line":369},[263,1126,1077],{"class":276},[263,1128,298],{"class":280},[263,1130,1131],{"class":853}," 5\n",[263,1133,1134,1136,1138],{"class":265,"line":380},[263,1135,1087],{"class":276},[263,1137,298],{"class":280},[263,1139,1131],{"class":853},[263,1141,1142],{"class":265,"line":387},[263,1143,440],{"emptyLinePlaceholder":439},[263,1145,1146],{"class":265,"line":395},[263,1147,1148],{"class":269},"# Resource limits\n",[263,1150,1151,1153],{"class":265,"line":406},[263,1152,900],{"class":276},[263,1154,281],{"class":280},[263,1156,1157,1159],{"class":265,"line":413},[263,1158,934],{"class":276},[263,1160,281],{"class":280},[263,1162,1163,1165,1167],{"class":265,"line":421},[263,1164,914],{"class":276},[263,1166,298],{"class":280},[263,1168,945],{"class":301},[263,1170,1171,1173,1175],{"class":265,"line":428},[263,1172,924],{"class":276},[263,1174,298],{"class":280},[263,1176,954],{"class":301},[263,1178,1179,1181],{"class":265,"line":436},[263,1180,907],{"class":276},[263,1182,281],{"class":280},[263,1184,1185,1187,1189],{"class":265,"line":443},[263,1186,914],{"class":276},[263,1188,298],{"class":280},[263,1190,919],{"class":301},[263,1192,1193,1195,1197],{"class":265,"line":451},[263,1194,924],{"class":276},[263,1196,298],{"class":280},[263,1198,929],{"class":301},[263,1200,1202],{"class":265,"line":1201},23,[263,1203,440],{"emptyLinePlaceholder":439},[263,1205,1207],{"class":265,"line":1206},24,[263,1208,1209],{"class":269},"# Pod Disruption Budget\n",[263,1211,1213,1216,1218],{"class":265,"line":1212},25,[263,1214,1215],{"class":276},"apiVersion",[263,1217,298],{"class":280},[263,1219,1220],{"class":301}," policy\u002Fv1\n",[263,1222,1224,1227,1229],{"class":265,"line":1223},26,[263,1225,1226],{"class":276},"kind",[263,1228,298],{"class":280},[263,1230,1231],{"class":301}," PodDisruptionBudget\n",[263,1233,1235,1238],{"class":265,"line":1234},27,[263,1236,1237],{"class":276},"metadata",[263,1239,281],{"class":280},[263,1241,1243,1246,1248],{"class":265,"line":1242},28,[263,1244,1245],{"class":276},"  name",[263,1247,298],{"class":280},[263,1249,1250],{"class":301}," web-pdb\n",[263,1252,1254,1257],{"class":265,"line":1253},29,[263,1255,1256],{"class":276},"spec",[263,1258,281],{"class":280},[263,1260,1262,1265,1267],{"class":265,"line":1261},30,[263,1263,1264],{"class":276},"  minAvailable",[263,1266,298],{"class":280},[263,1268,1269],{"class":853}," 1\n",[263,1271,1273,1276],{"class":265,"line":1272},31,[263,1274,1275],{"class":276},"  selector",[263,1277,281],{"class":280},[263,1279,1281,1284],{"class":265,"line":1280},32,[263,1282,1283],{"class":276},"    matchLabels",[263,1285,281],{"class":280},[263,1287,1289,1292,1294],{"class":265,"line":1288},33,[263,1290,1291],{"class":276},"      app",[263,1293,298],{"class":280},[263,1295,1296],{"class":301}," web\n",[11,1298,1299,1300,1303],{},"On ",[17,1301,22],{"href":19,"rel":1302},[21],"'s Kubernetes environment, Helm chart deployments are the standard workflow.",[25,1305,1307],{"id":1306},"phase-4-storage-and-network-migration","Phase 4: Storage and Network Migration",[182,1309,1311],{"id":1310},"storage-migration","Storage Migration",[11,1313,1314],{},"Map Docker Compose volumes to Kubernetes PersistentVolumeClaims (PVCs):",[254,1316,1318],{"className":256,"code":1317,"language":258,"meta":259,"style":259},"apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: db-data\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: standard\n  resources:\n    requests:\n      storage: 10Gi\n",[75,1319,1320,1329,1338,1344,1353,1359,1366,1373,1383,1390,1397],{"__ignoreMap":259},[263,1321,1322,1324,1326],{"class":265,"line":266},[263,1323,1215],{"class":276},[263,1325,298],{"class":280},[263,1327,1328],{"class":301}," v1\n",[263,1330,1331,1333,1335],{"class":265,"line":273},[263,1332,1226],{"class":276},[263,1334,298],{"class":280},[263,1336,1337],{"class":301}," PersistentVolumeClaim\n",[263,1339,1340,1342],{"class":265,"line":284},[263,1341,1237],{"class":276},[263,1343,281],{"class":280},[263,1345,1346,1348,1350],{"class":265,"line":292},[263,1347,1245],{"class":276},[263,1349,298],{"class":280},[263,1351,1352],{"class":301}," db-data\n",[263,1354,1355,1357],{"class":265,"line":305},[263,1356,1256],{"class":276},[263,1358,281],{"class":280},[263,1360,1361,1364],{"class":265,"line":313},[263,1362,1363],{"class":276},"  accessModes",[263,1365,281],{"class":280},[263,1367,1368,1370],{"class":265,"line":329},[263,1369,983],{"class":316},[263,1371,1372],{"class":301}," ReadWriteOnce\n",[263,1374,1375,1378,1380],{"class":265,"line":337},[263,1376,1377],{"class":276},"  storageClassName",[263,1379,298],{"class":280},[263,1381,1382],{"class":301}," standard\n",[263,1384,1385,1388],{"class":265,"line":345},[263,1386,1387],{"class":276},"  resources",[263,1389,281],{"class":280},[263,1391,1392,1395],{"class":265,"line":353},[263,1393,1394],{"class":276},"    requests",[263,1396,281],{"class":280},[263,1398,1399,1402,1404],{"class":265,"line":361},[263,1400,1401],{"class":276},"      storage",[263,1403,298],{"class":280},[263,1405,1406],{"class":301}," 10Gi\n",[11,1408,1409,1410,1413],{},"Consider using ",[193,1411,1412],{},"StatefulSets"," for database persistence. StatefulSets provide stable network identities and persistent storage, making them ideal for database workloads.",[182,1415,1417],{"id":1416},"secret-management","Secret Management",[11,1419,1420,1421,1423],{},"Migrate ",[75,1422,127],{}," file secrets to Kubernetes Secrets:",[254,1425,1427],{"className":495,"code":1426,"language":497,"meta":259,"style":259},"# Create a Secret\nkubectl create secret generic db-credentials \\\n  --from-literal=POSTGRES_PASSWORD=secure-password\n\n# Or integrate with external secret stores via External Secrets Operator\n",[75,1428,1429,1434,1453,1458,1462],{"__ignoreMap":259},[263,1430,1431],{"class":265,"line":266},[263,1432,1433],{"class":269},"# Create a Secret\n",[263,1435,1436,1439,1441,1444,1447,1450],{"class":265,"line":273},[263,1437,1438],{"class":509},"kubectl",[263,1440,775],{"class":301},[263,1442,1443],{"class":301}," secret",[263,1445,1446],{"class":301}," generic",[263,1448,1449],{"class":301}," db-credentials",[263,1451,1452],{"class":280}," \\\n",[263,1454,1455],{"class":265,"line":284},[263,1456,1457],{"class":533},"  --from-literal=POSTGRES_PASSWORD=secure-password\n",[263,1459,1460],{"class":265,"line":292},[263,1461,440],{"emptyLinePlaceholder":439},[263,1463,1464],{"class":265,"line":305},[263,1465,1466],{"class":269},"# Or integrate with external secret stores via External Secrets Operator\n",[11,1468,1469,1470,748,1475,1480,1481,1486],{},"For integration with ",[17,1471,1474],{"href":1472,"rel":1473},"https:\u002F\u002Fwww.vaultproject.io\u002F",[21],"HashiCorp Vault",[17,1476,1479],{"href":1477,"rel":1478},"https:\u002F\u002Faws.amazon.com\u002Fsecrets-manager\u002F",[21],"AWS Secrets Manager",", the ",[17,1482,1485],{"href":1483,"rel":1484},"https:\u002F\u002Fexternal-secrets.io\u002F",[21],"External Secrets Operator"," is recommended.",[182,1488,100],{"id":1489},"networking",[11,1491,1492],{},"Docker Compose's service-name-based communication migrates to Kubernetes DNS-based service discovery:",[254,1494,1496],{"className":256,"code":1495,"language":258,"meta":259,"style":259},"# Docker Compose: DATABASE_URL=postgres:\u002F\u002Fdb:5432\u002Fmyapp\n# Kubernetes:     DATABASE_URL=postgres:\u002F\u002Fdb-service.default.svc.cluster.local:5432\u002Fmyapp\n",[75,1497,1498,1503],{"__ignoreMap":259},[263,1499,1500],{"class":265,"line":266},[263,1501,1502],{"class":269},"# Docker Compose: DATABASE_URL=postgres:\u002F\u002Fdb:5432\u002Fmyapp\n",[263,1504,1505],{"class":265,"line":273},[263,1506,1507],{"class":269},"# Kubernetes:     DATABASE_URL=postgres:\u002F\u002Fdb-service.default.svc.cluster.local:5432\u002Fmyapp\n",[25,1509,1511],{"id":1510},"phase-5-testing-and-gradual-rollout","Phase 5: Testing and Gradual Rollout",[11,1513,1514],{},"The final migration phase involves staged rollouts and validation.",[182,1516,1518],{"id":1517},"migration-testing-strategy","Migration Testing Strategy",[1520,1521,1522,1528,1544,1550],"ol",{},[190,1523,1524,1527],{},[193,1525,1526],{},"Staging environment validation",": Full functional testing before production migration",[190,1529,1530,1533,1534,748,1539],{},[193,1531,1532],{},"Load testing",": Validate under production-equivalent load using ",[17,1535,1538],{"href":1536,"rel":1537},"https:\u002F\u002Fk6.io\u002F",[21],"k6",[17,1540,1543],{"href":1541,"rel":1542},"https:\u002F\u002Flocust.io\u002F",[21],"Locust",[190,1545,1546,1549],{},[193,1547,1548],{},"Canary deployment",": Route a portion of traffic to the new environment for gradual migration",[190,1551,1552,1555],{},[193,1553,1554],{},"Rollback plan",": Prepare procedures to immediately revert to the old environment if issues arise",[254,1557,1559],{"className":256,"code":1558,"language":258,"meta":259,"style":259},"# Canary deployment example\napiVersion: apps\u002Fv1\nkind: Deployment\nmetadata:\n  name: web-canary\nspec:\n  replicas: 1  # Only a portion of traffic\n  selector:\n    matchLabels:\n      app: web\n      track: canary\n",[75,1560,1561,1566,1575,1584,1590,1599,1605,1618,1624,1630,1638],{"__ignoreMap":259},[263,1562,1563],{"class":265,"line":266},[263,1564,1565],{"class":269},"# Canary deployment example\n",[263,1567,1568,1570,1572],{"class":265,"line":273},[263,1569,1215],{"class":276},[263,1571,298],{"class":280},[263,1573,1574],{"class":301}," apps\u002Fv1\n",[263,1576,1577,1579,1581],{"class":265,"line":284},[263,1578,1226],{"class":276},[263,1580,298],{"class":280},[263,1582,1583],{"class":301}," Deployment\n",[263,1585,1586,1588],{"class":265,"line":292},[263,1587,1237],{"class":276},[263,1589,281],{"class":280},[263,1591,1592,1594,1596],{"class":265,"line":305},[263,1593,1245],{"class":276},[263,1595,298],{"class":280},[263,1597,1598],{"class":301}," web-canary\n",[263,1600,1601,1603],{"class":265,"line":313},[263,1602,1256],{"class":276},[263,1604,281],{"class":280},[263,1606,1607,1610,1612,1615],{"class":265,"line":329},[263,1608,1609],{"class":276},"  replicas",[263,1611,298],{"class":280},[263,1613,1614],{"class":853}," 1",[263,1616,1617],{"class":269},"  # Only a portion of traffic\n",[263,1619,1620,1622],{"class":265,"line":337},[263,1621,1275],{"class":276},[263,1623,281],{"class":280},[263,1625,1626,1628],{"class":265,"line":345},[263,1627,1283],{"class":276},[263,1629,281],{"class":280},[263,1631,1632,1634,1636],{"class":265,"line":353},[263,1633,1291],{"class":276},[263,1635,298],{"class":280},[263,1637,1296],{"class":301},[263,1639,1640,1643,1645],{"class":265,"line":361},[263,1641,1642],{"class":276},"      track",[263,1644,298],{"class":280},[263,1646,1647],{"class":301}," canary\n",[11,1649,1650,1651,1654,1655,1660],{},"For medium-sized applications, plan ",[193,1652,1653],{},"2-4 weeks"," for the complete migration. The ",[17,1656,1659],{"href":1657,"rel":1658},"https:\u002F\u002Fdasroot.net\u002Fposts\u002F2026\u002F03\u002Fmigrating-docker-compose-kubernetes-helm-kustomize\u002F",[21],"dasroot migration guide"," recommends a similar timeline.",[25,1662,1664],{"id":1663},"summary-a-planned-path-to-production-kubernetes","Summary: A Planned Path to Production Kubernetes",[11,1666,1667],{},"Migrate from Docker Compose to Kubernetes through these five planned phases:",[1520,1669,1670,1676,1682,1688,1694],{},[190,1671,1672,1675],{},[193,1673,1674],{},"Assessment",": Inventory Docker Compose configuration and map dependencies",[190,1677,1678,1681],{},[193,1679,1680],{},"Automated Conversion",": Generate initial manifests with Kompose",[190,1683,1684,1687],{},[193,1685,1686],{},"Production-Ready",": Add Probes, resource limits, and Ingress with Helm\u002FKustomize",[190,1689,1690,1693],{},[193,1691,1692],{},"Storage & Network Migration",": Configure PVCs, Secrets, and Services",[190,1695,1696,1699],{},[193,1697,1698],{},"Gradual Rollout",": Staging validation, canary deployments, and load testing",[11,1701,1702,1705,1706,1709],{},[17,1703,22],{"href":19,"rel":1704},[21]," provides the ideal Kubernetes infrastructure as a migration target from Docker Compose. With ",[17,1707,172],{"href":170,"rel":1708},[21],"'s AI assistance, the entire migration process is supported — from Kubernetes manifest generation to operations automation.",[11,1711,1712,1713,639],{},"If you're considering a migration to Kubernetes, please ",[17,1714,1717],{"href":1715,"rel":1716},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[21],"contact us",[1719,1720,1721],"style",{},"html pre.shiki code .sbD-w, html code.shiki .sbD-w{--shiki-default:#51597D;--shiki-default-font-style:italic}html pre.shiki code .s0U2E, html code.shiki .s0U2E{--shiki-default:#F7768E}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sPY7s, html code.shiki .sPY7s{--shiki-default:#9ECE6A}html pre.shiki code .sgJMe, html code.shiki .sgJMe{--shiki-default:#9ABDF5}html pre.shiki code .sGX4V, html code.shiki .sGX4V{--shiki-default:#A9B1D6}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sE3pS, html code.shiki .sE3pS{--shiki-default:#C0CAF5}html pre.shiki code .sT800, html code.shiki .sT800{--shiki-default:#E0AF68}html pre.shiki code .sOJ5S, html code.shiki .sOJ5S{--shiki-default:#FF9E64}",{"title":259,"searchDepth":273,"depth":273,"links":1723},[1724,1725,1728,1733,1737,1742,1745],{"id":27,"depth":273,"text":28},{"id":176,"depth":273,"text":177,"children":1726},[1727],{"id":184,"depth":284,"text":185},{"id":479,"depth":273,"text":480,"children":1729},[1730,1731,1732],{"id":491,"depth":284,"text":492},{"id":571,"depth":284,"text":572},{"id":642,"depth":284,"text":643},{"id":738,"depth":273,"text":739,"children":1734},[1735,1736],{"id":756,"depth":284,"text":757},{"id":1024,"depth":284,"text":1025},{"id":1306,"depth":273,"text":1307,"children":1738},[1739,1740,1741],{"id":1310,"depth":284,"text":1311},{"id":1416,"depth":284,"text":1417},{"id":1489,"depth":284,"text":100},{"id":1510,"depth":273,"text":1511,"children":1743},[1744],{"id":1517,"depth":284,"text":1518},{"id":1663,"depth":273,"text":1664},"2026-05-27","A step-by-step guide for migrating Docker Compose applications to Kubernetes. Covers Kompose conversion, Helm\u002FKustomize production-readiness, storage, networking, and rollout strategies.","md","en",{},"\u002Fblog\u002Fen\u002Fdocker-compose-to-kubernetes-migration",{"title":5,"description":1747},"blog\u002Fen\u002Fdocker-compose-to-kubernetes-migration",[47,50,1755,487,747,753,1756],"Migration","Container Orchestration","StdVuTdE6ZjNJdr5OO-nckB-Zyy7ls1qM3KY5r1VMOM",1779964618772]