第 7 篇:从 Docker Compose 迁移到 Kubernetes
0. 本篇定位
上一篇我们用 Docker Compose 把 API、MySQL、Redis、网络、volume、环境变量和 healthcheck 组织成了一份可版本化的本地环境声明。本篇继续向生产编排迈一步,讨论如何从 Compose 迁移到 Kubernetes。
这里的“迁移”不是把 compose.yaml 机械转换成几份 YAML。Compose 更像本地后端服务图,Kubernetes 更像集群期望状态系统。一个 Compose service 到 Kubernetes 里通常要拆成 Deployment、Service、ConfigMap、Secret、Probe、Resource、PVC、Ingress 或 Gateway 等多个对象。拆分不是为了复杂而复杂,而是因为生产环境需要更清楚的职责边界、发布控制、服务发现、配置治理、数据治理和观测证据。
读完本篇后,你应该能做到三件事。第一,知道 Compose service、ports、environment、volumes、healthcheck、depends_on 分别应该迁移到 Kubernetes 哪些对象和能力。第二,理解 Kubernetes 控制器持续维护期望状态,而不是一次性启动容器。第三,能判断哪些服务适合迁移到 Kubernetes,哪些依赖更适合使用外部托管服务。
1. 问题背景
很多团队第一次接触 Kubernetes 时,会从 Compose 文件开始做“字段翻译”。services.api.image 变成 Deployment 里的 image,ports 变成 Service,environment 变成环境变量,volumes 变成 PVC。这样能得到一组看起来能运行的 YAML,但往往缺少生产系统真正需要的设计:selector 是否稳定,readiness 是否阻止未就绪实例接流量,resources 是否能被调度器理解,Secret 是否有生命周期管理,数据是否有备份和恢复策略,发布失败如何回滚。
Compose 的运行场景通常是本地单机。你启动一个项目,服务都在同一台机器上,项目网络提供服务名解析,命名 volume 保留本地数据,depends_on 能减少启动顺序问题。Kubernetes 的运行场景是集群。Pod 会被调度到不同节点,副本会滚动更新,节点可能故障,Pod 可能随时被重建,Service 要给动态 Pod 集合提供稳定入口,配置和密钥要和镜像分离,存储要能被调度和声明。
因此,迁移的核心问题不是“Compose 的某个字段在 Kubernetes 里叫什么”,而是“这个字段背后的职责在生产里应该由哪个对象承担”。比如 Compose 的 ports 同时表达本地宿主机入口和容器端口,而 Kubernetes 中要拆成容器端口、Service 端口、Ingress 或 Gateway 入口。Compose 的 healthcheck 是容器健康命令,Kubernetes 中通常要拆成 startupProbe、readinessProbe、livenessProbe。Compose 的 depends_on 可以影响启动顺序,Kubernetes 中更强调应用重试、探针和控制器恢复。
这篇文章的目标,就是帮你建立这种职责迁移思维。我们会从一个 Compose 后端服务图出发,拆成 Kubernetes 对象,并用排障视角解释每一步为什么存在。
2. 核心概念
从 Compose 到 Kubernetes,本质上是从“本地服务图”迁移到“集群期望状态”。你需要关心的不是 YAML 数量,而是职责是否拆对。
| Compose 概念 | Kubernetes 对应方向 | 迁移时要补的能力 |
|---|---|---|
| service | Deployment、StatefulSet、Job、Service | 区分无状态、状态和一次性任务 |
| service name | Service DNS | selector、endpoint、命名空间 |
| ports | containerPort、Service port、Ingress/Gateway | 内部入口和外部入口分层 |
| environment/env_file | ConfigMap、Secret、env/envFrom | 配置版本、密钥治理、重启语义 |
| volumes | PVC、PV、StorageClass、外部托管服务 | 容量、访问模式、备份恢复 |
| healthcheck | startupProbe、readinessProbe、livenessProbe | 启动、接流量、存活三类语义 |
| depends_on | 应用重试、readiness、initContainer | 不依赖固定启动顺序 |
2.1 迁移不是字段翻译,而是职责拆分
Compose 里的一个 service 往往承担了很多含义:使用什么镜像,启动几个容器,配置从哪里来,端口如何暴露,挂载哪些数据,依赖谁,健康如何判断。在 Kubernetes 中,这些职责通常会被拆开。Deployment 管理无状态副本和滚动发布,Service 提供稳定访问入口,ConfigMap 保存普通配置,Secret 保存敏感配置,PVC 声明存储需求,Ingress 或 Gateway 管理外部入口。
拆分的好处是证据更清楚。用户访问失败时,先看 Ingress 或 Service;Service 没有 endpoints 时,看 selector 和 Pod labels;Pod 起不来时,看 Deployment、ReplicaSet、Pod events 和容器日志;配置不对时,看 ConfigMap、Secret 和 env 注入;数据异常时,看 PVC、PV、StorageClass 和应用数据目录。对象越清楚,排障路径越短。
如果把 Compose 的所有语义塞进一个 Kubernetes 对象里,短期看起来 YAML 少,长期会变成治理混乱。生产环境需要独立演进入口、服务发现、副本、配置、密钥、存储和发布策略。职责拆分不是 Kubernetes 的形式主义,而是为了让系统在故障和变更中可观察、可回滚、可协作。
2.2 无状态 API 的迁移主线
无状态后端 API 是最适合先迁移的对象。Compose 里一个 api service,在 Kubernetes 中通常拆成 Deployment 和 Service。Deployment 负责运行多个 Pod 副本,管理镜像版本、滚动发布、资源限制和探针;Service 负责给这些 Pod 提供稳定 DNS 和虚拟入口。客户端访问 Service,不直接访问某个 Pod。
Deployment 的关键字段包括 replicas、selector、template.metadata.labels、容器 image、ports、envFrom、resources 和 probes。这里最重要的是 selector 和 labels 必须匹配。Deployment 通过 selector 管理 ReplicaSet 和 Pod,Service 也通过 selector 找到 Pod。selector 一旦设计混乱,就会出现 Pod 存在但 Service 没有 endpoints 的经典故障。
Service 的关键是把动态 Pod 集合变成稳定入口。Compose 中 API 访问 MySQL 可以写 mysql:3306;Kubernetes 中则写 mysql.default.svc.cluster.local 或同命名空间下的 mysql。这背后是 Service DNS,而不是容器名 DNS。不要把 Pod IP 写进配置,因为 Pod 是可替换实例,重建后 IP 会变化。
2.3 配置、密钥、存储和入口的迁移主线
Compose 的 environment 可以先拆成 ConfigMap 和 Secret。非敏感配置,例如 profile、日志级别、依赖服务地址、功能开关,适合放 ConfigMap。密码、token、证书、数据库口令,应该放 Secret。Secret 不是完整密钥治理平台,默认也不是加密保险箱,但它至少把敏感值从镜像和普通配置中分离出来,为后续接入外部密钥系统留下边界。
Compose 的 volume 不能简单等同于 Kubernetes PVC。PVC 是存储需求声明,背后还涉及 PV、StorageClass、访问模式、容量和节点可用性。对于数据库这类核心状态,迁移时要先判断是放进集群内运行,还是使用云数据库、外部数据库或托管中间件。很多生产系统更适合把数据库作为外部托管服务,而不是一开始就把 MySQL StatefulSet 塞进集群。
Compose 的 ports 也要拆开。容器内部端口是 Pod 中容器监听的位置;Service port 是集群内部稳定入口;Ingress 或 Gateway 是外部流量入口,通常还涉及域名、TLS、路由、鉴权和限流。把这三层分清楚,才能解释“Pod 正常、Service 正常、但外部访问失败”这种问题。
3. 运行机制
Compose 和 Kubernetes 最大的运行机制差异,是一次性本地启动和持续控制循环。Compose 根据文件启动一组本地容器;Kubernetes 把对象写入 API Server,由控制器持续把实际状态修正到期望状态。
submit manifests -> API Server stores desired state -> controllers create or update resources -> scheduler places Pods on Nodes -> kubelet starts containers -> probes update readiness and liveness -> Service routes to ready endpoints3.1 Compose 启动模型与 Kubernetes 控制模型
Compose 的模型更接近“启动项目”。你执行 docker compose up -d,Compose 读取文件、创建网络和 volume、启动容器、运行 healthcheck。这个模型非常适合本地开发,因为所有服务都在开发者机器上,生命周期由开发者命令驱动。
Kubernetes 的模型更接近“提交期望状态”。你执行 kubectl apply -f manifests/,API Server 保存对象,Deployment 控制器创建 ReplicaSet,ReplicaSet 创建 Pod,Scheduler 选择节点,kubelet 拉镜像并启动容器,Service 控制器和 EndpointSlice 维护服务后端。你不是直接启动容器,而是声明希望集群长期维持什么状态。
这种差异会改变排障方式。Compose 里你常看 docker compose logs 和 docker compose ps;Kubernetes 里你要看 kubectl get、kubectl describe、events、Pod logs、ReplicaSet、EndpointSlice、rollout 状态和探针结果。对象更多,但每个对象暴露的证据也更细。
3.2 迁移流程:分类、映射、补语义
迁移第一步是分类服务。无状态 API 通常迁移到 Deployment;需要稳定身份和持久化数据的服务可能迁移到 StatefulSet 加 PVC,也可能不迁移进集群而使用外部托管服务;一次性初始化或迁移任务可以考虑 Job;本地调试工具、管理 UI、mock 服务可能只保留在 Compose 中。
第二步是映射对象。API 需要 Deployment 和 Service;普通配置进入 ConfigMap;敏感配置进入 Secret;外部入口进入 Ingress 或 Gateway;持久化数据进入 PVC 或外部服务;健康检查进入 probes;资源边界进入 requests 和 limits;发布策略进入 Deployment strategy。
第三步是补齐 Kubernetes 语义。Compose 的 depends_on 不能直接搬过来,要改为应用重试、readinessProbe 和必要的 initContainer。Compose 的 ports 不能只创建 Service,还要考虑外部入口和 TLS。Compose 的 restart 也不能替代 livenessProbe、优雅关闭和滚动发布策略。迁移不是“能跑起来”,而是“能被平台长期维护”。
3.3 伪代码:从 Compose 模型到 Kubernetes 模型
可以用下面的伪代码理解迁移过程。它不是某个工具源码,而是迁移思维模型。
function migrateComposeService(service): workloadType = classify(service)
if workloadType == "stateless_api": deployment = createDeployment( image = service.image, replicas = chooseReplicaCount(service), env = splitConfigAndSecret(service.environment), probes = translateHealthcheck(service.healthcheck), resources = defineRequestsAndLimits(service) ) serviceObject = createService( selector = deployment.podLabels, ports = translateInternalPorts(service.ports) ) ingress = createIngressIfExternalTrafficExists(service.ports) return [deployment, serviceObject, ingress]
if workloadType == "stateful_dependency": return chooseExternalServiceOrStatefulSet(service)
if workloadType == "one_shot_task": return createJob(service)
return keepInComposeOrCreateOptionalTooling(service)这段伪代码强调三点。第一,先分类再映射,不要所有 service 都变 Deployment。第二,先拆职责再写 YAML,不要把端口、配置、存储和入口揉在一起。第三,迁移时要补生产语义:副本、资源、探针、发布策略、密钥、存储和观测。
4. 最小可运行示例
下面从一个 Compose API service 出发,拆成 Kubernetes 的 ConfigMap、Secret、Deployment 和 Service。示例刻意保持最小,但保留迁移时最关键的职责边界。
4.1 原始 Compose 片段
services: api: image: registry.example.com/order-api:1.0.0 ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: local DB_URL: jdbc:mysql://mysql:3306/order DB_USERNAME: root DB_PASSWORD: example healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 10s timeout: 3s retries: 10这个 service 同时表达了镜像、端口、配置、密码和健康检查。迁移到 Kubernetes 时,我们要把这些语义拆开。镜像和副本进入 Deployment,普通配置进入 ConfigMap,密码进入 Secret,内部稳定入口进入 Service,外部入口后续再用 Ingress 或 Gateway 处理。
4.2 Kubernetes 对象拆分
普通配置放 ConfigMap。
apiVersion: v1kind: ConfigMapmetadata: name: order-api-configdata: SPRING_PROFILES_ACTIVE: prod DB_URL: jdbc:mysql://mysql:3306/order DB_USERNAME: app敏感配置放 Secret。示例使用 stringData 便于阅读,实际落库时 Kubernetes 会转成 base64 表示。base64 不是加密,生产仍要结合权限、加密和外部密钥系统治理。
apiVersion: v1kind: Secretmetadata: name: order-api-secrettype: OpaquestringData: DB_PASSWORD: change-me无状态 API 用 Deployment 管理副本和发布。
apiVersion: apps/v1kind: Deploymentmetadata: name: order-apispec: replicas: 2 selector: matchLabels: app: order-api template: metadata: labels: app: order-api spec: containers: - name: api image: registry.example.com/order-api:1.0.0 ports: - containerPort: 8080 envFrom: - configMapRef: name: order-api-config - secretRef: name: order-api-secret resources: requests: cpu: 200m memory: 512Mi limits: memory: 1Gi readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 15 periodSeconds: 5 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 10Service 提供集群内部稳定入口。
apiVersion: v1kind: Servicemetadata: name: order-apispec: selector: app: order-api ports: - name: http port: 80 targetPort: 80804.3 应用、观察和回滚
应用对象:
kubectl apply -f k8s/观察部署状态:
kubectl get deploy,rs,pod,svckubectl rollout status deployment/order-apikubectl get endpointslice查看 Pod 事件和日志:
kubectl describe pod -l app=order-apikubectl logs -l app=order-api --tail=200如果发布失败,可以查看历史并回滚:
kubectl rollout history deployment/order-apikubectl rollout undo deployment/order-api这些命令对应的是 Kubernetes 控制链路,而不是 Compose 的本地启动链路。迁移后要训练团队从 Deployment、ReplicaSet、Pod、Service、EndpointSlice、events 和 probes 的角度看问题。
5. 配置逐行拆解
这一节把迁移后最容易写错的字段拆开。Kubernetes YAML 最怕“字段看起来都写了,但对象关系没有成立”。
5.1 Deployment:replicas、selector、template 和 image
replicas 表示期望副本数。它不是简单的“启动几个容器”,而是让 Deployment 控制器持续维持指定数量的可用 Pod。某个 Pod 被删除或节点异常时,控制器会尝试创建新的 Pod。副本数要结合容量、可用性、连接池和数据库压力设计,不是越多越好。
selector.matchLabels 和 template.metadata.labels 必须匹配。Deployment 用 selector 管理它创建的 Pod,Service 也通常用相同或兼容的 label 选择后端。如果 Deployment selector 和 Pod label 不匹配,Deployment 可能无法管理副本;如果 Service selector 和 Pod label 不匹配,Service 会没有 endpoints。
image 最好使用不可变 tag 或 digest。Compose 本地环境可以临时用 latest,但生产发布应避免 tag 漂移。Kubernetes 只知道你声明了某个镜像引用,不知道这个 tag 是否被覆盖。可靠发布需要镜像构建记录、镜像扫描、digest、发布记录和回滚策略共同保证。
5.2 envFrom、resources 和 probes
envFrom 可以一次性从 ConfigMap 和 Secret 注入环境变量。优点是简洁,缺点是键名冲突和缺失不够显眼。关键配置可以用显式 env 引用,确保变量名、来源和必填关系更清楚。配置变化后,Pod 不一定自动重启,生产中通常需要配合发布流程或配置变更触发策略。
resources.requests 是调度器用于选择节点的重要依据,limits 是运行边界。Java 后端尤其要关注内存限制和 JVM 参数。如果只写 limits 不写 requests,调度可能不稳定;如果 limits 太小,容易 OOMKilled;如果完全不写资源,集群容量管理会失真。
probes 要区分三类语义。startupProbe 适合慢启动应用,避免启动期被 liveness 误杀;readinessProbe 决定 Pod 是否接收 Service 流量;livenessProbe 判断进程是否需要重启。不要用同一个 /health 模糊承载所有语义。数据库短暂不可用时,readiness 可以失败让 Pod 暂停接流量,但 liveness 不一定应该杀掉进程。
5.3 Service、PVC 和外部入口
Service 的 port 是 Service 暴露给集群内部客户端的端口,targetPort 是 Pod 容器实际监听端口。port: 80、targetPort: 8080 很常见,表示集群内访问 order-api:80,转发到 Pod 的 8080。排障时要同时看 Service selector、EndpointSlice、Pod label 和容器监听端口。
PVC 用来声明存储需求,但不是所有 Compose volume 都应该迁移成 PVC。数据库可以先评估是否使用外部托管服务。如果必须在集群内运行,再设计 StatefulSet、PVC、备份、恢复、容量和调度约束。对日志、缓存、临时文件这类状态,要先判断是否真的需要持久化。
外部入口不要用 Service 一把梭。ClusterIP 适合集群内部,NodePort 适合特定场景调试或简化暴露,LoadBalancer 依赖云厂商或负载均衡实现,Ingress 或 Gateway 更适合七层路由、域名和 TLS。生产入口还要考虑鉴权、限流、灰度、WAF 和证书更新。
6. 后端工程场景
从 Compose 到 Kubernetes 的迁移,最好从简单、无状态、低风险的 API 开始,而不是一上来迁移所有数据库和中间件。
6.1 无状态 API 迁移
无状态 API 的迁移路径最清楚。先确保镜像构建稳定,启动命令不依赖本地 bind mount,日志输出到 stdout/stderr,配置通过环境变量或文件注入,健康接口区分 readiness 和 liveness。然后创建 Deployment 和 Service,在测试命名空间验证启动、探针、日志、资源和访问路径。
迁移时要把 Compose 中的本地连接串改成集群连接串。如果 MySQL 仍在 Compose 本地环境里,Kubernetes Pod 访问不到 mysql 这个 Compose service name。生产里要么使用集群内 Service,要么使用外部数据库域名。服务名迁移必须结合运行位置,不要照抄本地配置。
发布策略也要补齐。Compose 中通常是停止旧容器、启动新容器;Kubernetes 中可以滚动发布,但滚动发布是否安全取决于 readinessProbe、优雅关闭、连接池、数据库迁移和向后兼容。没有这些配合,Deployment 也可能把错误版本平滑地发到所有用户面前。
6.2 有状态依赖迁移
MySQL、Redis、Kafka、MinIO 这类依赖不要盲目迁移进 Kubernetes。先问三个问题:这个组件是否已有稳定托管服务,团队是否具备运维它的能力,数据丢失或不可用的业务影响是什么。很多后端系统更适合使用云数据库或平台中间件,而不是业务团队自己维护 StatefulSet。
如果确实要在 Kubernetes 内运行有状态组件,就要补齐 StatefulSet、PVC、StorageClass、备份恢复、容量告警、版本升级和故障演练。PVC 只能表达存储需求,不会自动帮你做数据库备份,也不会保证应用层一致性。把 Compose volume 改成 PVC,只是迁移的开始。
Redis 这类缓存还要区分“可丢弃缓存”和“业务状态”。如果只是缓存,可以接受重建和数据丢失,存储策略就轻;如果承载队列、锁或会话,就要重新评估高可用、持久化和恢复策略。迁移前必须先理解数据语义。
6.3 CI、测试和生产推进
CI 阶段可以先做 Kubernetes manifest 静态校验、镜像构建、单元测试和集成测试。进入测试集群后,再验证 Deployment rollout、Service endpoints、ConfigMap/Secret 注入、日志、探针和资源。不要等到生产才第一次观察 Kubernetes 对象状态。
预发环境要尽量贴近生产入口和依赖,但可以控制流量和数据规模。预发不是“能启动就行”,而是验证发布、回滚、配置变更、数据库迁移、探针、优雅关闭和观测链路。Compose 中很多隐含假设,都会在预发阶段暴露出来。
生产推进要小步。先迁移一个无状态低风险服务,再迁移更多 API;先使用外部数据库,再评估有状态组件;先建立统一模板,再让团队复用。每一步都要有回滚路径和排障手册。Kubernetes 提供能力,但不会自动替团队建立工程纪律。
7. 常见错误与排障
迁移后最常见的问题,不是 YAML 写不出来,而是对象关系没有成立。排障时要沿着请求路径、控制器路径和配置路径分别看证据。
7.1 Service 没有 endpoints
Service 没有 endpoints 是迁移初期最经典的问题。原因通常是 Service selector 和 Pod labels 不匹配,或者 Pod 没有 ready。先看 Service 和 EndpointSlice。
kubectl get svc order-api -o yamlkubectl get endpointslice -l kubernetes.io/service-name=order-apikubectl get pod --show-labels如果没有 endpoints,继续看 Service selector 是否能匹配 Pod labels。若 labels 匹配但 endpoints 仍为空,检查 Pod readiness。Pod 未 ready 时,默认不会进入 Service ready endpoints。此时要看 readinessProbe 是否失败、应用是否监听正确端口、健康接口是否依赖了不可用数据库。
不要一看到外部访问失败就先改 Ingress。请求路径是 Ingress 或 Gateway 到 Service,再到 endpoints,再到 Pod。Service 没有 endpoints 时,入口层配置再正确也没有后端可转发。
7.2 Pod 重启、镜像失败和配置注入错误
Pod 一直重启时,先看状态和事件。
kubectl get podkubectl describe pod <pod-name>kubectl logs <pod-name> --previousImagePullBackOff 多半是镜像名、tag、仓库权限或 imagePullSecret 问题;CrashLoopBackOff 要看应用日志、退出码、配置和资源;OOMKilled 要看内存 limits、JVM 参数和实际内存使用;探针失败要看健康接口路径、端口、启动时间和依赖状态。
配置注入错误时,检查 ConfigMap、Secret 和 Pod 环境变量。
kubectl get configmap order-api-config -o yamlkubectl get secret order-api-secret -o yamlkubectl exec <pod-name> -- printenv | findstr DB_Secret 输出通常是 base64 表示,不要误以为那就是加密。排障时也要注意不要把真实敏感值贴到公开日志或文档里。
7.3 流量、存储和发布证据链
外部访问失败时,沿着入口链路检查。
kubectl get ingresskubectl describe ingress <name>kubectl get svc order-apikubectl get endpointslice -l kubernetes.io/service-name=order-apikubectl logs -l app=order-api --tail=200存储问题沿着 PVC 链路检查。
kubectl get pvckubectl describe pvc <name>kubectl get pvkubectl describe pod <pod-name>发布问题沿着 Deployment 链路检查。
kubectl rollout status deployment/order-apikubectl rollout history deployment/order-apikubectl describe deployment order-apikubectl get rs -l app=order-api迁移后的排障报告最好包含:请求从哪里进入,Service selector 匹配了哪些 Pod,Pod 是否 ready,镜像版本和 digest 是什么,配置来自哪个 ConfigMap/Secret,资源限制是多少,PVC 是否绑定,rollout 当前卡在哪一步。这样报告才是 Kubernetes 语境下的证据链。
8. 生产化边界
从 Compose 迁移到 Kubernetes,只是进入生产化的起点。Kubernetes 提供平台对象,但生产质量还取决于应用设计、团队流程和运维标准。
8.1 应用必须适应动态集群
Kubernetes 中 Pod 是可替换实例。应用不能依赖本地磁盘保存关键状态,不能依赖固定 IP,不能假设依赖永远先启动,不能把启动慢当成异常被杀,不能忽略 SIGTERM。后端服务要支持连接重试、优雅关闭、健康接口、幂等启动和可观测日志。
readiness 和 liveness 要谨慎设计。readiness 失败会让 Pod 不接流量,适合表达“当前不适合处理请求”;liveness 失败会重启容器,适合表达“进程已经无法自愈”。如果把数据库短暂不可用放进 liveness,可能导致大量 Pod 被重启,反而扩大故障。
资源配置也要和应用匹配。Java 后端要结合容器内存限制设置 JVM,连接池大小要和副本数、数据库容量匹配,线程池和队列要有边界。Kubernetes 可以调度资源,但不能替你解决应用自身的容量设计。
8.2 密钥、数据和合规边界
Secret 不是完整密钥平台。生产中还要考虑加密存储、RBAC、审计、轮换、外部密钥系统和最小权限。不要因为用了 Kubernetes Secret,就把所有密钥治理问题都当作已经解决。
数据迁移要特别保守。把 Compose volume 迁移成 PVC 之前,要明确数据来源、备份、恢复、迁移窗口、schema 版本和回滚方案。数据库升级和应用发布要协调,不能只看 Pod 是否 Running。对核心数据来说,恢复演练比 YAML 是否漂亮更重要。
合规和安全还包括镜像来源、镜像扫描、运行用户、文件系统只读、网络策略、入口鉴权、TLS、日志脱敏和审计。Kubernetes 只是承载这些策略的平台,不是自动安全的魔法盒。
8.3 团队模板和平台契约
迁移成功的标志,不是某个服务能在 Kubernetes 跑起来,而是团队形成了可复用模板和平台契约。比如每个后端服务都必须有 resources、readinessProbe、livenessProbe、标准 labels、日志格式、Secret 引用方式、Service 命名规则和 rollout 策略。
平台团队和业务团队要划清边界。平台提供命名空间、Ingress、证书、镜像仓库、监控、日志、Secret 集成、存储类和发布工具;业务团队负责应用配置、健康接口、资源需求、依赖关系、数据迁移和业务回滚。边界不清时,事故中就会互相等对方排查。
从 Compose 迁移到 Kubernetes 的过程,也应该反哺本地开发。Kubernetes 里沉淀出的服务名、环境变量、健康接口和配置结构,可以回到 Compose 中保持一致。这样本地、测试和生产不是三套完全不同的世界,而是同一套职责模型在不同平台上的实现。
9. 什么时候用,什么时候不用
不是所有 Compose 项目都需要迁移到 Kubernetes。迁移的判断标准不是“技术更先进”,而是业务是否需要集群编排能力,以及团队是否准备好承担复杂度。
9.1 适合迁移的场景
无状态后端 API、内部网关、后台任务消费者、需要多副本和滚动发布的服务,通常适合迁移到 Kubernetes。它们能明显受益于 Deployment、Service、探针、资源管理、发布控制和统一观测。
多个团队共享的测试、预发、生产环境也适合 Kubernetes。Compose 在个人机器上很好用,但共享环境需要命名空间、权限、资源隔离、入口治理、日志指标和发布审计。Kubernetes 能把这些能力平台化。
需要标准化交付的组织也适合迁移。只要每个服务都有统一模板,业务团队就不用重复设计端口、探针、资源和发布策略,平台也能更稳定地治理容量、安全和观测。
9.2 不适合立即迁移的场景
纯本地开发依赖不一定要迁移。MySQL、Redis、Mock 服务、调试 UI 和一次性工具,用 Compose 管理可能更轻量。把所有本地工具都塞进 Kubernetes,会增加学习成本和启动成本。
小型单机应用也不一定需要 Kubernetes。如果服务规模很小,发布频率低,没有多副本、滚动发布、资源隔离和平台治理需求,用 Docker Compose 或更简单的部署方式可能更合适。Kubernetes 的复杂度必须换来真实收益。
团队还没有基本容器化纪律时,也不适合直接上 Kubernetes。如果镜像不可重复构建、日志不输出标准输出、配置写死、健康接口缺失、优雅关闭没有实现,直接迁移只会把问题放大。先把应用容器化基本功补齐,再迁移平台。
9.3 默认建议
默认建议是:本地依赖继续用 Compose,生产无状态服务优先迁移 Kubernetes,核心数据库优先评估托管服务或成熟平台能力。不要一口气迁移所有东西,先迁移最容易标准化的无状态 API。
迁移前先做清单:镜像是否稳定,配置是否能拆成 ConfigMap/Secret,健康接口是否可用,应用是否支持重试和优雅关闭,资源需求是否有估算,服务入口是否明确,数据是否有备份恢复方案。清单过不了,就先不要急着写 Kubernetes YAML。
迁移后要用 Kubernetes 的证据链验收:Deployment rollout 成功,Pod ready,Service 有 endpoints,入口可访问,日志可查,指标可看,配置来源明确,Secret 不泄露,回滚命令可执行。能通过这些验证,才算从 Compose 思维真正迈向 Kubernetes 思维。
10. 下一篇衔接
下一篇会正式进入 Kubernetes 的核心对象:Pod、Node 与 Deployment。本文只是从 Compose 迁移视角建立对象拆分意识,下一篇会进一步解释 Pod 为什么是 Kubernetes 最小调度单元,Node 如何承载 Pod,Deployment 如何通过 ReplicaSet 管理副本和滚动发布。
读下一篇前,可以先确认自己能回答:为什么 Compose service 不能简单等同于 Kubernetes Service,为什么无状态 API 通常要拆成 Deployment 和 Service,为什么 Service 没有 endpoints 要先看 selector 和 Pod readiness,为什么 depends_on 不能直接迁移,为什么 PVC 不等于完整数据库生产方案。