Docker Compose 到 K8s 的迁移路径:不是一键转换那么简单

发布时间:2026/7/10 23:23:50
Docker Compose 到 K8s 的迁移路径:不是一键转换那么简单 Docker Compose 到 K8s 的迁移路径不是一键转换那么简单一、Kompose 转换完的 YAML 也别直接部署Docker Compose 和 K8s 之间的概念鸿沟远超表面相似度。Komposekompose convert能生成初版 YAML但它只是一个语法翻译器——不理解你的服务应该如何编排、网络如何划分、存储如何处理。直接部署 Kompose 转出来的 YAML 大概率会遇到所有服务在同一个 namespace 中网络全通——和 Compose 的行为一致但失去了 K8s 的网络隔离能力数据卷映射为 emptyDir——Pod 重建后数据丢失环境变量硬编码在 Deployment 中——没有 ConfigMap/Secret 概念真正的迁移需要重新理解你的服务在 K8s 的语境下的正确形态。flowchart TD A[Docker Compose 文件] -- B[Kompose 生成初版] B -- C{需要人工调整的维度} C -- D[网络层] C -- E[存储层] C -- F[配置层] C -- G[编排层] D -- D1[划分 namespace] D -- D2[创建 NetworkPolicy] D -- D3[定义 Service Ingress] E -- E1[volume → PVC] E -- E2[bind mount → hostPath/PV] E -- E3[确定 StorageClass] F -- F1[环境变量 → ConfigMap] F -- F2[密码 → Secret] F -- F3[敏感信息加密] G -- G1[depends_on → initContainers] G -- G2[restart → liveness probe] G -- G3[scale → HPA] D1 E1 F1 G1 -- H[Review 测试] H -- I[生产部署]二、概念映射对照表Docker ComposeKubernetes迁移要点servicesDeployment/StatefulSet有状态服务用 StatefulSetnetworksNetworkPolicyService显式定义网络权限volumesPersistentVolumeClaim指定 StorageClassdepends_oninitContainers等待依赖就绪environmentConfigMap/Secret配置与代码分离portsServiceIngress集群外访问需要 Ingressrestart: alwayslivenessProbe健康检查替代无限重启scalereplicas/HPA手动副本 自动伸缩healthcheckreadinessProbe就绪探针控制流量接入三、生产级迁移实践原始 Compose 文件示例version: 3.8 services: api: image: myapp/api:latest ports: - 3000:3000 environment: - DB_HOSTpostgres - DB_PASSWORDsecret123 - REDIS_URLredis://redis:6379 depends_on: - postgres - redis volumes: - ./uploads:/app/uploads restart: always postgres: image: postgres:16 environment: - POSTGRES_PASSWORDsecret123 volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine volumes: - redisdata:/data volumes: pgdata: redisdata:迁移后的 K8s 资源分步展示Step 1: 配置外化——ConfigMap SecretapiVersion: v1 kind: ConfigMap metadata: name: api-config namespace: production data: DB_HOST: postgres-service REDIS_URL: redis://redis-service:6379 NODE_ENV: production --- apiVersion: v1 kind: Secret metadata: name: api-secrets namespace: production type: Opaque data: # 使用 Sealed Secrets 或 External Secrets Operator 管理 DB_PASSWORD: c2VjcmV0MTIz # base64(secret123)——仅为示例生产不要硬编码Step 2: 存储层——PVCapiVersion: v1 kind: PersistentVolumeClaim metadata: name: api-uploads-pvc namespace: production spec: accessModes: - ReadWriteMany # 多副本需要 RWX storageClassName: efs-sc # 根据云厂商选择 resources: requests: storage: 10Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgres-pvc namespace: production spec: accessModes: - ReadWriteOnce storageClassName: gp3 resources: requests: storage: 50GiStep 3: 服务 部署apiVersion: apps/v1 kind: Deployment metadata: name: api namespace: production labels: app: api spec: replicas: 3 selector: matchLabels: app: api template: metadata: labels: app: api spec: containers: - name: api image: myapp/api:v1.2.3 # 用具体版本而非 latest ports: - containerPort: 3000 name: http envFrom: - configMapRef: name: api-config - secretRef: name: api-secrets volumeMounts: - name: uploads mountPath: /app/uploads resources: requests: memory: 256Mi cpu: 250m limits: memory: 512Mi cpu: 500m # 替代 restart: always——精确的健康检查 livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 3000 initialDelaySeconds: 10 periodSeconds: 5 volumes: - name: uploads persistentVolumeClaim: claimName: api-uploads-pvc --- apiVersion: v1 kind: Service metadata: name: api-service namespace: production spec: selector: app: api ports: - port: 80 targetPort: 3000 protocol: TCP type: ClusterIP --- # StatefulSet for PostgreSQL apiVersion: apps/v1 kind: StatefulSet metadata: name: postgres namespace: production spec: serviceName: postgres-service replicas: 1 # PostgreSQL 单实例——生产建议用 Operator selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: containers: - name: postgres image: postgres:16 env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: api-secrets key: DB_PASSWORD ports: - containerPort: 5432 volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data resources: requests: memory: 512Mi cpu: 500m limits: memory: 1Gi cpu: 1000m volumeClaimTemplates: - metadata: name: pgdata spec: accessModes: [ReadWriteOnce] storageClassName: gp3 resources: requests: storage: 50Gi四、迁移中容易忽略的问题数据安全性Compose 中volumes: pgdata在 Docker 管理的卷中。迁移到 K8s 后数据需要迁移。建议先在 K8s 启动一个新的 PostgreSQL 实例用pg_dump/pg_restore导数据验证数据完整性后切 DNS内部 DNS 解析Compose 用服务名作为 DNS。K8s 用service-name.namespace.svc.cluster.local。如果应用代码里硬编码了 Compose 的短主机名需要改为 K8s 的完整域名——或者通过ConfigMap注入正确的连接字符串。资源限制Compose 不限制资源。K8s 如果不设 request/limitNode 可能被 Pod 吃满。迁移后至少要设resources.requests——不设 limit 也可以但 request 必须设。五、总结Compose 到 K8s 的迁移不是格式转换是思维方式切换。Compose 假设一切运行在单机、全通网络、无状态K8s 的设计前提是多节点、网络隔离、声明式状态管理。Konvert 只是帮你省掉了手写 YAML 的体力活但概念重塑——哪些该放进 ConfigMap、哪些需要 NetworkPolicy、哪些必须 StatefulSet——这个判断才是迁移的真正价值。