Docker Compose和K8s什么时候该升级
Docker Compose 和 K8s 什么时候该升级
很多团队一开始跑业务,Docker Compose 就够用了。一个 docker-compose.yml,把 Nginx、API、MySQL、Redis、Worker 拉起来,日志用 docker logs 看,出问题 ssh 上去重启一下,简单直接。小团队、单机部署、内部系统、低并发业务,用 Compose 并不丢人,反而是维护成本最低的做法。
真正要关注的不是“现在是不是该上 K8s”,而是业务运行过程中有没有开始出现 Compose 不擅长处理的问题。K8s 不是升级版 Compose,它解决的是调度、弹性、发布、隔离、服务发现、故障转移这一类平台问题。业务没到那个阶段,硬上 K8s,团队会先被 YAML、Ingress、CNI、CSI、RBAC、Helm、监控告警折腾一轮。
Docker Compose 适合停留在哪些场景
实际使用中发现,Compose 最舒服的区间是:服务数量不多,机器数量少,发布频率可控,故障能靠人工快速处理。比如一个官网、一个管理后台、一个中小型 API 服务,外加 Redis 和 MySQL,单机或者两三台机器就能撑住,这种场景没必要急着迁到 K8s。
Compose 的优势很明确:文件少、学习成本低、排障路径短。服务挂了看容器日志,端口冲突查 docker ps,磁盘满了 df -h,网络不通进容器 curl。对于很多业务来说,这种直观性比平台化更重要。
比较典型的 Compose 使用边界
服务实例数量在 10 个以内,基本都能用 Compose 管住。比如 web、api、admin、worker、redis、mysql、nginx、prometheus、grafana 这种组合,只要资源规划得当,跑得很稳。
发布频率如果是一周几次,甚至一天一两次,Compose 也能接受。配合简单的脚本,比如 git pull、docker compose build、docker compose up -d,足够支撑很多中小项目。
机器规模是一个关键点。如果只有 1 台机器,Compose 反而最合适。如果有 2 到 3 台机器,可以继续用 Compose,但要明确每台机器承担什么角色,比如一台跑应用,一台跑数据库,一台跑缓存和定时任务。再往上扩,就会开始痛。
这里补充一点,Compose 并不等于不能做生产。生产环境里大量项目就是 Compose 跑的,关键是有没有做好日志、备份、监控、重启策略和资源限制。比如 restart: always、healthcheck、CPU/memory limit、日志轮转,这些基础配置比盲目上 K8s 更重要。
出现这些情况,Compose 会开始吃力
服务数量变多,依赖关系开始混乱
当服务从 5 个变成 20 个,再到 50 个,Compose 文件会越来越长。某个服务依赖 Redis、Kafka、MySQL、对象存储、内部 API,启动顺序、环境变量、网络别名、端口映射都堆在一起,改一次配置要非常小心。
这时候最常见的问题不是“跑不起来”,而是“没人敢改”。一个 docker-compose.yml 几百行,里面夹着生产数据库地址、第三方 API Key、不同环境变量,开发、测试、生产靠复制文件区分。时间久了,文件之间一定会漂移。
K8s 在这类场景下的价值不是 YAML 更少,而是把 Deployment、Service、ConfigMap、Secret、Ingress、PVC 分开管理。配置边界清楚以后,团队协作会轻松很多。
单机资源不够,需要跨机器调度
Compose 最大的限制之一是它天然偏单机。虽然可以自己把服务拆到多台机器上,但调度是人工做的。比如 A 机器 CPU 打满,B 机器还有空闲,Compose 不会自动帮你迁移容器。某台机器宕机,上面的容器也不会自动漂移到其他节点。
当业务开始需要 3 台以上应用服务器,而且希望服务能在不同机器之间自动分布,K8s 的价值就出来了。Deployment 副本数设置为 3,调度器会根据节点资源把 Pod 放到合适的位置。节点挂了,Pod 会在其他节点重新拉起。这个能力靠 Compose 自己拼脚本也能做一部分,但维护成本会越来越高。
发布越来越频繁,需要灰度和回滚
Compose 发布新版本通常是重新 build 或 pull 镜像,然后 up -d。小项目没问题,服务多了以后就比较粗糙。尤其是用户流量大、接口不能中断的场景,直接重启容器可能带来短暂 502。
K8s 的 RollingUpdate 在这里比较好用。比如 maxSurge 设置 25%,maxUnavailable 设置 0,新 Pod Ready 以后再摘旧 Pod。配合 readinessProbe,可以避免还没启动完成的实例被流量打进来。
实际发布中,readinessProbe 比很多人想象得重要。没有它,K8s 看到容器进程启动了就可能开始转发流量,但应用内部可能还在加载配置、连接数据库、预热缓存。这个阶段接流量,接口就会抖。
业务开始有弹性需求
如果业务流量稳定,白天晚上差别不大,Compose 没什么问题。但如果流量有明显峰谷,比如游戏开服、活动秒杀、直播互动、广告投放带来的突发访问,单靠手动扩容会很累。
K8s 可以配 HPA,根据 CPU、内存或者自定义指标自动扩 Pod。比如 API 服务平时 3 个副本,CPU 超过 60% 持续 3 分钟扩到 6 个副本,流量下降后再缩回去。这个能力不是所有业务都需要,但对峰值明显的业务很有用。
多说一句,HPA 不是万能按钮。数据库连接数、Redis 连接数、下游限流都要一起考虑。只扩应用 Pod,不管数据库承载能力,很容易把瓶颈从 Web 层推到 DB 层。
可以用这些数据判断是否要从 Compose 迁到 K8s
如果想更工程化地判断,可以看几个运行数据。不是拍脑袋说“业务大了就上 K8s”,而是看维护成本有没有明显上升。
服务数量:5 个以内,Compose 很舒服;10 到 20 个,开始要规范文件和发布脚本;超过 30 个,尤其是服务之间调用复杂时,K8s 会更适合。
机器数量:1 台机器,Compose 优先;2 到 3 台机器,Compose 还能撑,但要做好角色拆分;超过 5 台应用节点,人工分配服务会越来越麻烦,可以认真评估 K8s。
发布频率:一周 1 到 3 次,Compose 没压力;一天多次发布,且要求不停机,K8s 的滚动发布、健康检查和回滚会更省心。
故障恢复要求:允许人工 5 到 10 分钟内处理,Compose 可以接受;要求节点故障后自动恢复,K8s 更合适。
团队规模:1 到 3 个开发兼运维,Compose 简单直接;团队里有专门运维、SRE 或平台人员,K8s 的维护成本才比较容易摊开。
哪些情况不建议急着上 K8s
业务还没稳定,架构天天变
早期项目最怕把时间花在平台复杂度上。接口还在变,数据库表还在改,服务边界还没定,这时上 K8s 很容易变成“业务没复杂,部署先复杂”。
这个阶段更建议用 Compose 把交付链路跑顺。镜像怎么构建,配置怎么管理,日志怎么收集,数据库怎么备份,监控怎么告警,这些基础做扎实,比一开始就搭 K8s 更实际。
团队没有人维护 K8s
K8s 集群不是装完就完了。节点升级、证书、CNI 网络、CoreDNS、Ingress Controller、存储插件、镜像仓库、监控告警、权限控制,任何一块出问题都会影响业务。
实际使用中发现,很多小团队上 K8s 后最大的问题不是 Pod 不会写,而是集群出问题没人能判断。比如 DNS 解析慢、Node NotReady、Pod 一直 Pending、PVC 挂载失败、Ingress 规则冲突,这些都需要经验。
如果团队没有人能处理这些问题,又不打算购买托管 K8s 服务,Compose 反而更稳。
只是为了“看起来更先进”
容器化不等于必须 K8s。Compose 能解决的问题,就没必要引入更重的平台。尤其是单体应用、低并发后台、内部工具、定时任务类系统,上 K8s 带来的收益很有限。
技术选型里很常见的一种浪费,是把小系统做成大平台的样子。部署链路长了,排障链路长了,权限链路也长了,最后一次普通发布要改 Helm values、等 CI、看 Pod、查 Ingress、查 Service,再看日志,效率反而下降。
什么时候该升级 Docker Compose 本身
这里的升级有两层意思:一是升级 Docker Compose 版本,二是升级 Compose 项目的组织方式。
现在更推荐使用 Docker Compose V2,也就是 docker compose 命令,而不是老的 docker-compose。V2 和 Docker CLI 集成更好,维护也更活跃。老项目如果还在用 docker-compose 1.x,可以安排迁移测试。
版本升级要看兼容性
Compose 升级前要重点看 compose file schema、网络行为、变量解析、depends_on、healthcheck 等配置是否有变化。尤其是老项目里用了 version: "2" 或 version: "3" 的文件,迁移时建议先在测试环境跑一遍。
比较稳的做法是保留原 compose 文件,复制一份做迁移测试。测试内容包括容器是否正常启动、环境变量是否解析正确、volume 是否挂载正确、容器间 DNS 是否正常、restart 策略是否符合预期。
不要在生产机器上直接升级 Docker Engine 和 Compose,然后立刻重启所有容器。Docker 版本变化可能影响 iptables、存储驱动、日志驱动,出问题时回滚不一定轻松。
项目组织方式也要升级
很多 Compose 项目一开始只有一个 docker-compose.yml,后面会慢慢变成 docker-compose.prod.yml、docker-compose.test.yml、docker-compose.override.yml。文件多了以后,如果没有规范,很快就会乱。
建议把镜像构建、运行配置、敏感配置分开。镜像通过 CI 构建并推到 registry,Compose 只负责拉取指定 tag。数据库密码、API Token 不要直接写在 yml 里,至少用 .env 管理,更严格一点可以接入 Vault 或云厂商 Secret 管理。
日志也要提前处理。默认 json-file 如果不限制大小,容器日志能把磁盘打满。生产环境建议配置 max-size 和 max-file,比如 max-size=100m,max-file=3。这个坑在 Compose 和 K8s 里都会遇到,只是表现形式不同。
什么时候该升级 K8s
K8s 升级比 Compose 更敏感。它不是单个二进制升级,而是控制面、kubelet、kube-proxy、CNI、CSI、Ingress Controller、metrics-server、CoreDNS 等组件一起受影响。
实际生产里,K8s 不建议长期停在太老的版本。太老的版本会遇到安全补丁缺失、云厂商支持结束、插件不兼容、新版本 API 无法使用等问题。比如还在用很老的 Ingress API,升级时就可能碰到 apiVersion 变更。
安全补丁是最直接的升级理由
如果当前版本曝出严重 CVE,尤其是 apiserver、kubelet、container runtime、Ingress Controller 相关漏洞,就要尽快评估升级或打补丁。公网暴露的控制面、节点端口、Ingress 入口风险更高。
有些团队只关注业务镜像漏洞,忽略集群组件漏洞。K8s 本身也是攻击面,RBAC 配置过宽、ServiceAccount Token 泄露、容器逃逸风险、Ingress 配置错误,都可能引发安全问题。
版本进入 EOL 后要安排升级
K8s 官方版本支持周期有限,云厂商托管集群也会给出版本维护期限。版本 EOL 后,托管服务可能不再提供补丁,部分插件也会停止适配。
生产集群比较稳的节奏是不要追最新小版本,但也不要落后太多。比如当前稳定版本已经到 1.30、1.31,而集群还停在 1.23、1.24,就要尽快排计划。跨度越大,API 废弃、插件兼容、升级路径都会更麻烦。
插件兼容性开始卡业务
有时不是 K8s 主版本逼你升级,而是周边生态在推着你走。比如新版 cert-manager、Ingress NGINX、Istio、Argo CD、Prometheus Operator、CSI Driver 要求更高的 K8s 版本。业务想用新能力,集群版本太旧,就只能先升级集群。
这里最容易被忽略的是 API deprecation。比如 extensions/v1beta1、networking.k8s.io/v1beta1 这类老 API,在新版本里可能不可用。升级前要用 kubectl 或 pluto、kubent 这类工具扫一遍废弃 API。
K8s 升级前不要只看版本号
先看工作负载是否能被驱逐
K8s 节点升级通常涉及 drain。节点 drain 时,Pod 会被驱逐并调度到其他节点。如果业务没有多副本,或者 PodDisruptionBudget 配得太死,升级就会卡住。
比如一个服务只有 1 个副本,升级节点时它被驱逐,短时间内就会中断。数据库、消息队列、状态服务更要谨慎,不能像无状态 API 一样随便 drain。
升级前建议检查 Deployment 副本数、PDB、节点资源余量、Pod 反亲和、PVC 绑定情况。很多升级失败不是版本问题,而是集群没有足够资源接住被驱逐的 Pod。
再看 CNI 和网络策略
CNI 是 K8s 升级里最容易出隐性问题的部分之一。Calico、Cilium、Flannel、Terway 等插件都有自己的兼容矩阵。K8s 升级前要确认当前 CNI 版本是否支持目标版本。
网络问题一旦出现,排障会比应用错误复杂得多。Pod 能不能解析 DNS,Service 能不能访问,NodePort 是否正常,NetworkPolicy 是否生效,Ingress 到后端是否通,这些都要有测试用例。
如果集群还跑着 BGP 模式的 Calico,更要提前看路由和节点状态。BGP session 异常时,业务表现可能是部分节点访问不通,不是全挂,这种问题最难定位。
存储插件要单独验证
有状态服务跑在 K8s 上,升级前必须验证 CSI Driver。PVC 能不能重新挂载,节点重启后卷是否自动恢复,StorageClass 参数是否兼容,这些都不能省。
实际使用中发现,很多业务迁到 K8s 后,无状态服务很好管,真正麻烦的是 MySQL、Elasticsearch、Kafka、MinIO 这类有状态组件。不是说不能跑,而是升级、扩容、迁移时要有预案。
Compose 迁到 K8s 的过程不要一步到位
从 Compose 迁到 K8s,建议先迁无状态服务。API、Web、Worker 这类服务比较适合先上 K8s。数据库、Redis、消息队列可以先留在云数据库、独立服务器或现有环境里。
这样做的好处是风险小。业务入口和应用层先享受滚动发布、自动恢复、扩缩容能力,状态层保持稳定。等团队熟悉 K8s 后,再评估是否把有状态组件迁进去。
迁移时配置要重新设计
Compose 里常见的 environment 到 K8s 里可以拆成 ConfigMap 和 Secret。端口映射从 ports 变成 Service。反向代理从 Nginx 配置变成 Ingress。数据卷从 volume 变成 PVC。
这不是机械转换。很多工具能把 compose 文件转成 K8s YAML,但生产环境不建议直接拿来用。自动转换出来的资源通常只是能跑,健康检查、资源限制、安全上下文、滚动策略、探针都要重新补。
资源限制尤其要写。没有 requests 和 limits 的 Pod,调度质量会很差。建议至少给 CPU request、memory request、memory limit。CPU limit 是否要加,看业务类型。延迟敏感服务有时不建议给太紧的 CPU limit,容易被 throttle。
服务器和网络环境会影响选择
容器平台再好,也要跑在合适的服务器和网络上。Compose 单机部署更看重单机稳定性、磁盘 IO、带宽质量。K8s 集群更看重节点间网络、内网延迟、负载均衡、镜像拉取速度和故障隔离。
如果是游戏、API 网关、活动业务这类流量波动比较明显的场景,服务器线路和防护能力要提前选好。遇到 DDoS 时,K8s 只能帮你恢复 Pod,挡不住入口带宽被打满。入口防护、防火墙策略、高防 IP、回源线路这些要在架构设计时就考虑。
如果你也在找这种适合容器部署、游戏业务、高防场景的服务器,可以看看129云。比如宁波高防-B型提供 4C、8G DDR4 ECC、70G U.2、上行 25Mbps 峰值、下行 300Mbps、100Gbps 防御,适合入口抗攻击要求比较明确的业务。海外业务可以看日本软银直连线路,香港多 IP 站群场景则可以关注 CN2 线路。需要确认线路、带宽和防护策略时,可以直接打客服热线 400-9177118。
Compose 和 K8s 升级时最容易忽略的细节
镜像 tag 不要一直用 latest
Compose 里很多项目喜欢 image: app:latest,K8s 里也有人这么写。短期方便,长期一定会坑。出了问题时不知道当前跑的是哪个版本,回滚也不清楚该回到哪里。
生产环境建议使用明确 tag,比如 git commit hash、构建号、日期版本。K8s 里 imagePullPolicy 也要配合设计,不要让节点缓存导致发布结果和预期不一致。
健康检查不要只写端口存活
很多人把健康检查写成 curl / 或 nc 端口。端口通不代表服务可用。更好的方式是提供 /healthz 和 /readyz,区分进程存活和是否可以接流量。
例如应用启动后先连接 MySQL、Redis,加载必要配置,完成后 readinessProbe 才返回 200。这样发布时新实例不会过早接流量。
日志和监控要先于升级
升级前没有监控,升级后出问题只能靠猜。至少要能看到 CPU、内存、磁盘、网络、容器重启次数、接口错误率、P95/P99 延迟。
Compose 环境可以用 node_exporter、cAdvisor、Prometheus、Grafana。K8s 环境可以用 kube-state-metrics、metrics-server、Prometheus Operator。日志可以用 Loki、ELK、Filebeat、Fluent Bit,根据团队熟悉程度选。
回滚不是一句命令
Compose 回滚通常是拉回旧镜像再 up -d。K8s 可以 kubectl rollout undo。但真正的回滚难点在数据库变更、配置变更、消息格式变更。
如果新版本改了表结构,旧版本还能不能跑?如果新增了配置项,旧版本是否兼容?如果消息队列里的消息格式变了,回滚后消费者会不会解析失败?这些要在发布前确认。
比较稳的升级节奏
Compose 环境
先在测试机升级 Docker Engine 和 Compose V2,跑一遍完整启动流程。确认 compose 文件、volume、network、env、healthcheck 都正常后,再安排生产窗口。
生产升级前备份 compose 文件、.env、数据库、关键挂载目录。升级 Docker 前记录当前版本和服务状态。升级后不要立刻清理旧镜像和旧容器,观察一段时间再做 prune。
K8s 环境
先升级测试集群或预发集群,跑业务回归。扫描废弃 API,确认 Helm chart、Operator、CNI、CSI、Ingress Controller 兼容目标版本。
生产集群升级时,控制面和工作节点分开处理。节点逐台 drain、升级、恢复、观察。关键业务设置合理 PDB,确保升级过程中至少有足够副本可用。
升级后重点看 CoreDNS、CNI、Ingress、存储挂载、节点状态、Pod 重启次数、业务错误率。不要只看 kubectl get nodes 全部 Ready 就认为结束,Ready 只能说明节点状态正常,不代表业务链路没问题。
实际判断时可以按业务压力来选
如果业务是单机能跑稳、服务少、发布不频繁,继续用 Compose,把备份、监控、日志、资源限制补齐。
如果业务已经多服务、多节点、频繁发布,需要自动恢复、滚动发布、服务发现和弹性扩容,就该评估 K8s。
如果现在已经在用 K8s,升级节奏跟着安全补丁、EOL、插件兼容、API 废弃走,不要等到云厂商强制升级或者插件装不上时才处理。
有状态服务、入口流量、防护能力、跨地域网络这些不要和平台升级混在一起赌运气。比如入口层需要高防,先把高防线路和回源链路定好;海外访问要求低延迟,就提前选好 CN2、GIA、软银直连这类线路,再谈 Compose 还是 K8s。