前言

这周核心工作就是把原有 Docker Compose 维护的整套业务服务完整迁移到 Kubernetes 集群。平时开发测试用 Compose 非常顺手,配置少、上手快,但真正往 K8s 迁移的时候,会发现概念变多、配置项成倍增加,很多人直接复制转换后的 YAML 上线直接踩坑。我这边把完整思考、实操、排错全部整理出来,尽量还原真实迁移的完整流程。

一、迁移前思考:什么场景才需要从 Compose 迁移 K8s

Docker Compose 仅仅适用于单机环境,所有服务都运行在同一台服务器。

  • Compose 优势:配置简单,几行 yaml 就可以启动一整套服务,本地开发、小测试环境非常友好。
  • Compose 短板:没有多节点调度、没有故障自愈、没有滚动更新,机器一旦故障所有服务全部停止;无法实现弹性扩缩容;没有统一健康检查机制。

K8s 能力:跨多台机器调度 Pod,节点故障自动把业务调度到正常节点;支持灰度滚动更新;可以配置 CPU 内存限制;探针检测业务存活;配合 Service 实现服务发现。

重要提醒:不是所有项目都必须上 K8s。如果只是单机小工具,访问量很低,Compose 完全够用,不要为了技术而强行上 K8s,会增加维护成本。适合迁移场景:业务需要多机器部署、需要高可用、后续会扩容实例、生产业务。

二、Docker Compose 和 K8s 资源对应关系

搞懂两者的映射,迁移就有思路,不会对着大量 yaml 无从下手。

Docker ComposeK8s 对应资源说明
servicesDeployment无状态业务,web、后端服务,可多副本
servicesStatefulSet有状态服务:MySQL、Redis,需要稳定网络标识、持久存储
portsService(NodePort/ClusterIP/LoadBalancer)负责流量转发,pod 销毁重建 IP 会变,service 提供稳定访问入口
volumesPV + PVCCompose 数据卷,K8s 通过 PVC 申请存储资源,PV 后端对接存储
environmentspec.containers[].env容器环境变量,配置账号、地址、时区等
restart: alwaysDeployment 默认 restartPolicy:Always容器异常自动重启
depends_on无直接等价Compose 仅控制启动顺序,K8s 没有该能力,需要应用层做等待

原始 docker‑compose.yaml 示例

version: '3.8'
services:
  web:
    image: nginx:1.24
    ports:
      - "8080:80"
    environment:
      - TZ=Asia/Shanghai
    restart: always
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
  redis:
    image: redis:6
    restart: always
    volumes:
      - redis-data:/data
volumes:
  redis-data:

上面这个 Compose 配置,直接复制到 K8s 是无法运行,格式完全不兼容,需要转换、手动优化。

三、完整实操迁移步骤

步骤 1:安装 kompose 转换工具

kompose 可以读取 compose 文件,自动输出 K8s 的 Deployment、Service、PVC 模板,只做模板生成,绝对不能直接部署上线,必须人工修改

Linux 安装命令:

#下载二进制程序
curl -L https://github.com/kubernetes/kompose/releases/download/v1.31.2/kompose-linux-amd64 -o kompose
#赋予执行权限
chmod +x kompose
#移动到全局命令目录
mv ./kompose /usr/local/bin/kompose
#验证是否安装成功
kompose version

执行转换:

#基于docker‑compose.yaml生成k8s yaml文件
kompose convert -f docker-compose.yaml

执行完毕,当前目录会生成:web-deployment.yamlweb-service.yamlredis-deployment.yamlredis-persistentvolumeclaim.yaml等文件。

运维小提示:kompose 工具的缺陷:不会自动添加资源限制、存活 / 就绪探针;镜像拉取策略默认 Always;存储部分配置经常不符合内网生产规范,全部需要人工修改。

步骤 2:优化无状态服务 Deployment(web 示例)

kompose 生成出来的配置缺少生产必备配置,需要手动补齐resources资源配额livenessProbe存活探针readinessProbe就绪探针imagePullPolicy镜像拉取策略

web-deployment.yaml 优化后完整内容

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: default #指定命名空间,业务建议分开不同namespace隔离
spec:
  replicas: 2 #业务副本数量,根据业务压力调整
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: nginx:1.24
        #内网环境节点本地已有镜像,优先使用本地镜像,避免外网拉取失败
        imagePullPolicy: IfNotPresent
        env:
        - name: TZ
          value: Asia/Shanghai
        #资源限制,防止单个服务占满节点CPU内存,导致集群雪崩
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 128Mi
        #就绪探针:判断服务是否准备好接收流量,没就绪不会接入service流量
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
          timeoutSeconds: 3
        #存活探针:业务卡死无响应,自动重启Pod
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 15
        volumeMounts:
        - name: nginx-conf
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: default.conf
      volumes:
      - name: nginx-conf
        configMap:
          name: nginx-conf
          items:
          - key: default.conf
            path: default.conf

注意:Compose 直接挂载本地配置文件,K8s 不支持直接挂载宿主机文件(不推荐),需要转为 ConfigMap 存放配置。

步骤 3:Service 配置,暴露业务访问入口

apiVersion: v1
kind: Service
metadata:
  name: web-svc
  namespace: default
spec:
  type: NodePort #内网测试使用NodePort;生产建议LoadBalancer或者Ingress
  selector:
    app: web #标签匹配pod,流量转发给标签app=web的pod
  ports:
  - port: 80        #service内部端口
    targetPort: 80  #pod容器端口
    nodePort: 30080 #节点对外端口,范围30000‑32767

步骤 4:有状态服务注意事项(示例 Redis)

像 Redis、MySQL 这类带持久化数据的服务,不要直接使用 Deployment,优先使用StatefulSet。关键点:

  1. PVC 持久存储一定要规划,数据不能存 Pod 内部,Pod 重建数据直接丢失。
  2. StatefulSet 的 Pod 拥有稳定网络身份,适合数据库类组件。

步骤 5:部署到 K8s 集群,执行命令

#一次性应用所有yaml资源,创建deployment、service、configmap、pvc
kubectl apply -f web-deployment.yaml -f web-service.yaml -f nginx-configmap.yaml

#查看deployment部署状态
kubectl get deployments

#查看pod运行状态,STATUS全部Running代表启动正常
kubectl get pods -o wide

#查看service端口
kubectl get svc

#查看pod详细事件,排错使用,如果pod异常,看事件报错
kubectl describe pod pod‑name

#查看容器业务日志
kubectl logs ‑f pod‑name

步骤 6:业务验证

访问集群节点 IP:30080,确认 nginx 页面正常打开;查看日志确认没有报错;模拟杀死 Pod,测试集群是否自动新建 Pod,验证自愈能力。

#删除pod,测试自愈,删除之后deployment会自动重新拉起pod
kubectl delete pod web‑7f9685798‑xxxx

四、真实踩坑记录,全部是迁移时实际遇到的问题

坑 1:直接使用 kompose 输出的 yaml 直接部署,Pod 反复重启,节点资源占满

现象:Pod 不断 CrashLoopBackOff,节点 CPU 内存打满,影响集群其他业务。排查:kompose 生成配置不会自带 resources 资源限制,容器可以无限制占用节点 CPU 内存。解决:手动补充requests(申请资源)和limits(最大占用资源)。

坑 2:容器日志时间相差 8 小时,时区不对

现象:业务日志打印的时间是 UTC 时间,和实际北京时间差 8 小时。排查:镜像默认 UTC 时区,没有配置东八区。解决:Pod 环境变量增加TZ=Asia/Shanghai;部分基础镜像不识别环境变量时区,需要挂载宿主机/etc/localtime

坑 3:ImagePullBackOff 镜像拉取失败

现象:Pod 状态 ImagePullBackOff,无法启动。** 排查场景 1:内网离线环境,镜像不在镜像仓库,节点本地存在镜像。kompose 默认imagePullPolicy: Always,每次都去远程拉取镜像。解决:修改imagePullPolicy: IfNotPresent,本地有镜像优先使用本地镜像。排查场景 2:镜像名称写错、镜像版本不存在、私有仓库没有配置 secret 密钥。

坑 4:Compose 的 depends_on 迁移后,服务启动顺序错乱

现象:web 服务启动比数据库早,业务直接报错连不上数据库。排查: Compose 的 depends_on 仅仅控制容器启动先后,不会等待数据库就绪;K8s 没有等价字段。解决: 在业务容器启动脚本增加等待逻辑,等待数据库端口可连通之后,再启动主程序,不能依赖编排工具控制顺序。

坑 5:配置文件挂载直接写宿主机路径,Pod 启动失败

现象:kompose 把 compose 挂载本地文件直接生成为 hostPath;集群多节点时,其他节点没有这个文件,Pod 启动异常。排查: hostPath 只适合单节点调试,多节点集群严禁大量使用 hostPath。解决: 普通配置转为 ConfigMap;密钥信息使用 Secret。

坑 6:没有配置探针,流量发送给还没启动完成的 Pod

现象:业务刚启动需要初始化十几秒,Pod 刚启动就接收请求,大量请求报错 502。排查: 缺少 readinessProbe 就绪探针,Pod 容器进程起来就被加入 Service 流量池,但业务程序还没初始化完成。解决: 配置就绪探针,业务真正就绪之后才接入流量。

五、迁移的整体流程建议(生产环境流程)

  1. 先在测试 K8s 集群完成整套迁移,完整跑通业务所有接口,验证读写、存储、重启、故障自愈。
  2. 有状态组件优先做数据备份,迁移前备份数据库。
  3. 不要直接删除原有 Compose 业务,两套环境并行运行一段时间,确认新集群无问题,再下线旧环境。
  4. 命名空间做业务隔离,不同项目放到不同 namespace,方便权限、资源配额管理。
  5. 存储提前规划,不要把业务数据存于 Pod 内部,Pod 重建数据丢失。
  6. 资源配额提前评估,根据业务实际负载设置 CPU 内存,不要全部写很大,浪费服务器资源。

六、本周总结

Docker Compose 迁移 K8s,不是简单工具一键转换就完事。kompose 只能帮我们节省手写基础模板的时间,生产环境必须人工二次优化资源限制、探针、镜像策略、配置管理、存储

优先迁移无状态 web、后端服务,把整套流程摸清楚之后,再处理 MySQL、Redis 这类有状态组件,循序渐进,不容易出现大规模故障。完成业务迁移之后,业务已经跑在 K8s 集群,但是我们看不到集群资源使用率、看不到业务日志,下周就开始搭建 K8s 监控与日志体系。

个人运维小感悟:很多新人学习 K8s 会记大量参数命令,一上来直接折腾数据库这种复杂有状态服务,很容易心态崩掉。建议先拿简单 Nginx、测试后端服务练习完整迁移流程,理解 Pod、Deployment、Service、探针、存储概念,再去处理复杂业务。

更多推荐