Kubernetes 1.20发布了,带来了很多新特性,同时也废弃了一些旧功能。我们公司把K8s集群从1.16升级到了1.20,过程中踩了不少坑。本文完整记录这次迁移实战,包括迁移前的准备、迁移步骤、遇到的问题和解决方案、迁移后的验证和优化,希望对正在做K8s升级迁移的朋友有帮助。
一、为什么要迁移
我们的K8s集群一直跑在1.16版本,用了一年多,一直很稳定。但随着业务发展,1.16的一些问题越来越明显:
- 版本太老,社区支持减弱:K8s 1.16已经发布很久了,社区的支持和补丁越来越少,很多新的工具和组件不再支持老版本
- 缺少新特性:1.17之后的版本引入了很多有用的特性,比如IPv4/IPv6双栈、CSI迁移、EndpointSlice、Process Namespace Sharing等,这些特性对我们的业务有帮助
- 安全漏洞:老版本存在一些已知的安全漏洞,虽然暂时没被利用,但始终是个风险
- 生态兼容性:很多新的云原生工具(如新版Istio、Knative等)不再支持1.16,要使用这些工具必须升级
综合考虑之后,我们决定把集群从1.16升级到1.20。1.20是2020年底的版本,比较稳定,新特性也比较丰富,而且是很多企业的目标版本。
二、迁移前的准备
K8s版本迁移不是一件小事,准备工作非常重要。准备充分,迁移就顺利;准备不足,迁移就会出各种问题。
1. 了解版本变化
首先要详细了解从1.16到1.20每个版本的变化,特别是破坏性变更和废弃功能。
我们重点关注了这些变化:
- 1.17:IPv4/IPv6双栈alpha、CSI迁移beta、拓扑感知服务路由alpha、EndpointSlice beta
- 1.18:服务端应用kubectl alpha、CSI内联卷beta、节点问题检测器beta、HPA扩展行为字段
- 1.19:Ingress扩展到networking.k8s.io/v1、EndpointSlice稳定、CSI存储容量alpha、Seccomp默认开启
- 1.20:kubectl debug alpha、API优先级和公平性alpha、Docker作为运行时被废弃(dockershim deprecation)、IPv4/IPv6双栈beta、Process Namespace Sharing稳定
特别要注意的是废弃功能:
- dockershim被废弃:1.20开始废弃Docker作为容器运行时,未来版本会移除,需要迁移到containerd或CRI-O
- 旧的Ingress API:extensions/v1beta1的Ingress在1.22会被移除,需要迁移到networking.k8s.io/v1
- 旧的RBAC API:rbac.authorization.k8s.io/v1beta1在1.22会被移除
- 一些alpha特性的API变化
了解这些变化,才能在迁移前做好准备,避免迁移后出现兼容性问题。
2. 评估应用兼容性
接下来要评估集群上运行的所有应用,看看它们对K8s版本有没有依赖,会不会因为版本升级而出问题。
我们的做法是:
- 列出所有运行中的应用和它们的YAML配置
- 检查是否使用了被废弃的API(如旧的Ingress、旧的RBAC)
- 检查是否依赖了特定版本的行为(如某些alpha特性)
- 检查自定义控制器和Operator的兼容性
- 检查Helm Chart的兼容性
我们发现有几个应用还在用旧的extensions/v1beta1 Ingress,需要先迁移到新的API。还有几个Helm Chart版本太老,不支持1.20,需要升级。
3. 准备测试环境
不要直接在生产环境升级,一定要先在测试环境验证。我们搭建了一个和生产环境配置相同的测试集群,先在测试环境做升级,验证所有应用都能正常运行,然后再在生产环境操作。
测试环境要尽可能和生产环境一致:相同的K8s版本、相同的节点配置、相同的网络插件、相同的存储类、相同的应用。这样测试结果才有参考价值。
4. 备份数据
升级前一定要做好备份,包括:
- etcd的备份(最重要,集群的所有状态都存在etcd里)
- 重要的PV数据备份
- 所有YAML配置和Helm Chart的备份
- 集群配置信息(kubeadm配置、网络配置等)
备份是最后的保障,如果升级失败,可以从备份恢复。etcd备份一定要验证可恢复性,不能只备份不验证。
5. 制定回滚计划
升级可能失败,一定要有回滚计划。我们的回滚计划是:
- 如果升级过程中出现严重问题,立即停止升级
- 用备份的etcd数据恢复集群到升级前的状态
- 如果集群无法恢复,用备份的配置重建集群,重新部署应用
- 回滚时间控制在1小时以内
有了回滚计划,升级的时候心里就有底了,出了问题也不慌。
三、迁移步骤
准备工作做好之后,就可以开始迁移了。我们采用的是滚动升级的方式,先升级控制平面,再逐个升级工作节点,尽量减少对业务的影响。
第一步:升级kubeadm和kubectl
首先在所有节点上升级kubeadm和kubectl到1.20版本。注意:kubeadm的版本要先于kubelet升级,而且kubeadm的版本不能比kubelet低超过一个小版本。
我们用的是Ubuntu系统,通过apt安装:
apt-mark unhold kubeadm kubectl
apt-get update && apt-get install -y kubeadm=1.20.x-00 kubectl=1.20.x-00
apt-mark hold kubeadm kubectl第二步:升级控制平面
在第一个master节点上执行:
kubeadm upgrade plan
kubeadm upgrade apply v1.20.xkubeadm upgrade plan会检查升级是否可行,列出需要升级的组件和配置变更。kubeadm upgrade apply会实际执行升级,升级etcd、API Server、Controller Manager、Scheduler等控制平面组件。
升级第一个master节点之后,在其他master节点上执行:
kubeadm upgrade node控制平面升级完成后,验证控制平面组件是否正常:
kubectl get nodes
kubectl get pods -n kube-system
kubectl get componentstatuses第三步:升级工作节点
控制平面升级完成后,逐个升级工作节点。升级工作节点的时候,要先把节点上的Pod驱逐出去,再升级,避免影响业务。
在每个工作节点上:
# 1. 驱逐节点上的Pod
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# 2. 升级kubelet和kubeadm
apt-mark unhold kubelet
apt-get install -y kubelet=1.20.x-00
apt-mark hold kubelet
# 3. 升级节点配置
kubeadm upgrade node
# 4. 重启kubelet
systemctl daemon-reload
systemctl restart kubelet
# 5. 节点重新可调度
kubectl uncordon <node-name>逐个节点升级,确保每个节点升级完成、Pod正常运行后,再升级下一个节点。这样即使某个节点出问题,也不会影响整个集群。
第四步:升级网络插件和其他组件
K8s本身升级完成后,还要升级网络插件(Calico/Flannel/Cilium等)、存储插件(CSI驱动)、Ingress Controller、监控组件(Prometheus/Grafana)、日志组件(EFK/Loki)等,确保它们和1.20兼容。
这些组件的升级要参考各自的官方文档,注意版本兼容性。有些组件的新版本可能有破坏性变更,需要调整配置。
第五步:迁移容器运行时(从Docker到containerd)
K8s 1.20废弃了dockershim,虽然1.20还能用Docker,但未来版本会移除。我们趁这次升级,把容器运行时从Docker迁移到了containerd。
迁移步骤:
- 在节点上安装containerd
- 配置containerd,设置cgroup驱动为systemd(和kubelet一致)
- 修改kubelet配置,指定容器运行时为containerd
- 重启kubelet
- 验证容器运行时是否切换成功
迁移过程中要注意:
- 切换运行时会重启节点上的所有容器,要先drain节点
- 镜像要重新拉取(containerd和Docker的镜像不共享)
- 有些依赖Docker socket的应用(如Docker-in-Docker、某些CI工具)需要调整
四、遇到的问题和解决方案
迁移过程中,我们遇到了不少问题,这里记录几个典型的。
问题1:旧的Ingress API不兼容
现象:升级后,几个用旧的extensions/v1beta1 Ingress的应用,路由不生效了。
原因:1.20虽然还支持extensions/v1beta1的Ingress,但行为有变化,而且某些字段(如pathType)的处理方式不同。
解决方案:
- 把所有旧的Ingress迁移到networking.k8s.io/v1版本
- 显式指定pathType(Prefix/Exact/ImplementationSpecific)
- 检查backend service的配置是否正确
- 用
kubectl convert命令自动转换旧的YAML
迁移后,所有Ingress都正常工作了。
问题2:dockershim废弃导致的问题
现象:升级到1.20后,kubelet日志里有大量的警告,说dockershim被废弃了。而且有些依赖Docker的工具出问题了。
原因:1.20开始废弃dockershim,虽然还能用,但有警告。我们的CI工具依赖Docker socket,切换到containerd后找不到Docker了。
解决方案:
- 长期方案:迁移到containerd,我们已经做了
- 短期方案:如果暂时不能迁移,可以继续用Docker,1.20还支持,只是有警告
- 依赖Docker socket的工具:改成用containerd的API,或者用nerdctl(containerd的Docker兼容CLI)
- CI/CD工具:升级到支持containerd的版本,或者用Kaniko、Buildah等不需要Docker daemon的构建工具
问题3:Calico网络插件版本不兼容
现象:升级后,部分Pod网络不通,Calico的日志里有报错。
原因:我们用的Calico版本太老(3.10),不支持K8s 1.20。
解决方案:
- 升级Calico到支持1.20的版本(3.17+)
- 升级前先看Calico的官方文档,确认版本兼容性
- 升级Calico的时候,注意配置文件的变化,有些参数可能改了
- 升级后验证网络连通性:Pod之间通信、Service访问、NetworkPolicy是否生效
问题4:自定义Controller的API不兼容
现象:我们自己写的一个自定义Controller,升级后不工作了,日志里有API调用错误。
原因:Controller用的client-go版本太老,和1.20的API不兼容。
解决方案:
- 升级client-go到支持1.20的版本
- 检查Controller里用到的API,有没有被废弃或变更的
- 重新编译Controller,部署新版本
- 建议:自定义Controller要跟上K8s版本,不要用太老的client-go
问题5:etcd升级失败
现象:升级第一个master节点的时候,etcd升级失败,控制平面起不来。
原因:etcd的数据目录权限有问题,而且etcd的版本跨度太大(从3.3直接到3.4),中间有兼容性问题。
解决方案:
- 立即停止升级,用备份的etcd数据恢复
- 检查etcd数据目录的权限,确保etcd用户能读写
- 先升级etcd到中间版本,再升级到目标版本,不要跨太大版本
- 升级前先做etcd的健康检查,确保etcd集群状态正常
- 恢复后重新升级,这次成功了
这个问题提醒我们:etcd是集群的心脏,升级etcd一定要谨慎,做好备份和验证。
问题6:节点升级后NotReady
现象:某个工作节点升级后,状态一直是NotReady,Pod调度不上去。
原因:kubelet启动失败,因为cgroup驱动配置不一致。kubelet用的是systemd cgroup驱动,但容器运行时(containerd)用的是cgroupfs驱动,两者不一致导致kubelet启动失败。
解决方案:
- 统一cgroup驱动,都用systemd(推荐)
- 修改containerd配置:
SystemdCgroup = true - 修改kubelet配置:
cgroupDriver: systemd - 重启containerd和kubelet
- 验证节点状态是否恢复正常
这个问题很常见,特别是从Docker迁移到containerd的时候,一定要注意cgroup驱动的一致性。
五、迁移后的验证
升级完成后,不要以为就完事了,一定要做全面的验证,确保集群和所有应用都正常运行。
1. 集群状态验证
# 节点状态
kubectl get nodes -o wide
# 所有Pod状态
kubectl get pods --all-namespaces
# 控制平面组件状态
kubectl get componentstatuses
# 系统事件
kubectl get events --all-namespaces --sort-by='.lastTimestamp'确保所有节点都是Ready状态,所有Pod都是Running状态,没有异常的事件。
2. 应用功能验证
逐个验证所有应用的功能:
- Web应用:访问页面,测试核心功能
- API服务:调用接口,验证返回结果
- 后台任务:检查任务是否正常执行
- 定时任务:验证CronJob是否正常触发
- 有状态应用:检查数据是否完整,主从是否正常
不要只看Pod是Running就认为正常,一定要验证业务功能。有些应用Pod是Running的,但内部已经出问题了。
3. 网络验证
- Pod之间通信:在不同节点的Pod之间ping和curl
- Service访问:测试ClusterIP、NodePort、LoadBalancer类型的Service
- Ingress:测试外部域名访问是否正常
- NetworkPolicy:验证网络策略是否生效
- DNS:测试集群内DNS解析是否正常
4. 存储验证
- PV/PVC:检查持久卷是否正常挂载
- 数据完整性:验证有状态应用的数据是否完整
- 存储类:测试动态存储供给是否正常
- 快照:测试存储快照功能(如果用了)
5. 监控和日志验证
- Prometheus:检查监控指标是否正常采集
- Grafana:检查仪表盘是否正常显示
- 告警:测试告警是否正常触发
- 日志:检查日志是否正常采集和查询
- 链路追踪:检查分布式追踪是否正常
6. 性能验证
- 集群资源使用:CPU、内存、网络、磁盘是否正常
- 应用响应时间:和升级前对比,有没有变慢
- 压测:对核心应用做简单的压测,确保性能没有下降
- 调度性能:测试Pod调度速度,和升级前对比
六、迁移后的优化
迁移完成后,还可以利用新版本的特性做一些优化。
1. 启用新特性
1.20有很多新特性可以用:
- EndpointSlice:替代老的Endpoints,更高效,支持大规模Service
- kubectl debug:方便地调试运行中的Pod
- Process Namespace Sharing:Pod内容器共享进程命名空间,方便sidecar模式
- IPv4/IPv6双栈:如果需要IPv6支持,可以启用
- HPA扩展行为:更灵活的HPA扩缩容配置
根据业务需要,选择性地启用这些新特性,提升集群的能力和效率。
2. 清理废弃资源
迁移后,清理一些不再需要的资源:
- 删除旧的、不再使用的API资源
- 清理废弃的ConfigMap和Secret
- 合并重复的Deployment和Service
- 清理不再使用的PV和PVC
清理后,集群更整洁,管理起来也更方便。
3. 优化资源配置
利用新版本的特性优化资源配置:
- 用HPA的新行为字段,更精细地控制扩缩容
- 用LimitRange和ResourceQuota,更合理地限制资源使用
- 用PriorityClass,确保关键应用优先调度
- 优化Pod的resources request和limit,提高资源利用率
4. 完善监控和告警
迁移后,完善监控和告警:
- 添加新版本组件的监控指标
- 设置关键指标的告警(如节点NotReady、Pod异常重启、API Server延迟)
- 配置etcd的监控和告警(etcd是集群的心脏,一定要重点监控)
- 建立集群健康巡检机制,定期检查集群状态
七、经验和教训
这次迁移,我们总结了一些经验和教训。
1. 不要跨太多版本升级
我们从1.16直接升到1.20,跨了4个版本,中间的变化太多,遇到的问题也多。建议每次升级跨1-2个版本,比如1.16→1.18→1.20,这样每次的变化小,问题少,风险低。
2. 测试环境一定要充分验证
不要在测试环境简单跑一下就去生产环境升级。要在测试环境做全面的验证,包括所有应用的功能测试、性能测试、故障演练。测试环境发现的问题越多,生产环境出问题的概率就越小。
3. 备份和回滚计划是生命线
升级前一定要做好备份,而且要验证备份可恢复。回滚计划要详细,包括回滚步骤、回滚时间、责任人。有了备份和回滚计划,升级的时候心里才有底,出了问题也能快速恢复。
4. 逐个节点升级,不要贪快
工作节点升级的时候,一定要逐个来,确保一个节点升级完成、验证正常后,再升级下一个。不要同时升级多个节点,那样出了问题影响面大,而且不好定位是哪个节点的问题。
5. 关注废弃功能,提前迁移
K8s每个版本都会废弃一些功能,要提前关注,在升级前就完成迁移。不要等功能被移除了才着急,那时候就被动了。特别是API版本的废弃(如Ingress、RBAC),一定要提前迁移到新的API。
6. 文档很重要
迁移过程中,要做好文档记录:升级步骤、遇到的问题、解决方案、验证结果。这些文档不仅对本次迁移有帮助,对以后的升级也有参考价值。而且团队成员可以通过文档了解集群的状态和变化。
八、写在最后
K8s版本迁移是一项复杂但必要的工作。它不是简单地敲几个命令就完事了,而是需要充分的准备、谨慎的操作、全面的验证。
我们这次从1.16升级到1.20,前后花了两周时间(包括准备、测试、生产升级、验证优化),遇到了不少问题,但最终都解决了。升级完成后,集群更稳定、功能更丰富、性能也有提升,这次迁移是值得的。
如果你正在做K8s升级迁移,希望这篇文章能帮到你。记住:准备充分、操作谨慎、验证全面、有回滚计划,就能大大降低迁移的风险。
K8s在快速发展,新版本不断推出,升级迁移会是一个持续的工作。建立规范的升级流程,积累迁移经验,就能让每次升级都顺利完成。
最后,愿每一个K8s运维工程师,都能从容面对每一次版本升级,让集群稳定运行,让业务无忧。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录