政策快报平台上线第一年,所有服务部署在物理机上。一台机器跑数据库,一台跑应用,一台跑爬虫。部署靠手动操作,发布靠复制文件。
那时候,发布一次需要30分钟:登录服务器、停服务、备份、上传新包、启动、验证。如果出了问题,回滚更麻烦。
后来我们逐步做了容器化改造:从物理机到Docker,从Docker到Kubernetes。每次升级都解决了当时最痛的运维问题,也引入了新的复杂度。今天复盘这个过程。
正文:3个阶段的演进
阶段一:物理机时代(第一年)
部署方式: 物理机+手工部署,SSH登录服务器,手动停服、上传jar包、重启。数据库单独一台机器,应用单独一台,爬虫单独一台。
主要问题:
-
发布慢: 手工操作,每次发布需要30分钟以上
-
回滚难: 出问题了要找回旧包,重新上传、重启,来回至少折腾一小时
-
环境不一致: 开发、测试、生产环境配置不同,经常出现"本地跑得好好的,上线就挂了"
-
资源利用率低: 每台机器只能跑一个服务,即使CPU闲置也无法复用
阶段二:Docker时代(第二年)
部署方式: 应用打包成Docker镜像,通过Docker Compose管理多容器编排。镜像推送到私有仓库,部署时拉取镜像、启动容器。
解决了:
-
环境一致性问题(镜像即环境,开发测试生产跑同一个镜像)
-
部署速度提升(从30分钟降到5分钟左右)
-
资源隔离(容器之间互相隔离,不会因为一个服务的故障影响其他服务)
新问题:
-
容器编排能力有限(Docker Compose适合单机,多机部署需要额外工具)
-
服务发现和负载均衡需要手动配置
-
容器数量多了之后,手动管理变得困难
阶段三:Kubernetes时代(现在)
部署方式: 所有服务容器化后迁移到Kubernetes集群(3个Master节点+5个Worker节点),通过YAML定义服务部署,使用Helm管理应用版本。GitLab CI自动构建镜像并推送到Harbor仓库,ArgoCD自动同步到K8s集群。
解决了:
-
自动伸缩:根据CPU/内存使用率自动扩容Pod副本数,流量高峰自动增加实例,低谷自动缩容
-
自动恢复:Pod异常自动重启、节点故障自动迁移
-
滚动更新:发布过程零停机,新版本逐步替换旧版本,发现问题随时暂停
-
资源优化:多服务共享集群资源,利用率显著提升
关键技术决策与踩坑
决策一:自建K8s还是用云厂商托管?
我们选择了云厂商托管K8s(ACK/TKE),因为:不需要自己维护Master节点(节省运维人力);云厂商提供了与SLB、存储、日志的深度集成;扩容节点方便,点击即可增加Worker节点。
踩坑一:资源配置不合理
初期Pod的CPU/内存request和limit设置不合理。有的服务设得太低,流量高峰时OOM;有的设得太高,资源浪费。
经验: 先观察一周的监控数据,根据实际使用量调整request/limit,定期review资源使用情况,持续优化。
踩坑二:日志收集混乱
容器化之后,日志不再写入本地文件,而是输出到stdout。如果不用统一收集,日志会分散在各个Pod里。
经验: 使用ELK/EFK统一收集容器日志。每个Pod自动将stdout日志发送到ES,通过Kibana统一查询,问题排查更加高效。
踩坑三:配置管理复杂
不同环境(dev/test/prod)的配置不同。如果把配置写在镜像里,每次环境变更都要重新构建镜像。
经验: 使用ConfigMap管理配置,不同环境使用不同的ConfigMap,镜像与配置分离。
效果数据
| 指标 | 物理机时代 | 容器化+K8s后 |
|---|---|---|
| 发布耗时 | 30分钟+ | 2-3分钟(滚动更新) |
| 回滚耗时 | 30分钟+ | 1分钟(kubectl rollout undo) |
| 资源利用率 | ~30% | ~65% |
| 故障恢复 | 手工处理,30分钟+ | 自动重启,2-3分钟 |
| 扩缩容 | 手工,需要加机器 | 自动,秒级生效 |
结尾
容器化改造不是"为了用新技术而用新技术",是每一步都为了解决当时最痛的问题。
物理机时代最痛的是"发布慢、回滚难",Docker解决了环境一致性和部署速度,K8s解决了自动化和弹性。每一步都踩过坑,但每一步都在解决问题。如果回到起点,还是会走同样的路。