穿越说明:本文发布于2025年6月26日。Kubernetes 1.32预计于2025年下半年正式发布,本文基于K8s 1.32 beta版本及之前稳定版的特性撰写,最终K8s 1.32稳定版的特性和行为可能会有差异,请以官方发布信息为准。
K8s 1.32+踩坑记:那些让我熬夜的问题
最近团队把Kubernetes集群从1.30升级到了1.32,本以为是一次常规升级,结果踩了一堆坑,连续熬了好几个通宵才搞定。
这篇文章我想记录一下升级过程中遇到的各种问题,以及最终是怎么解决的。如果你也在考虑升级K8s到1.32+,希望这篇文章能帮你避开一些坑,少熬点夜。
先说明一下,我们的集群规模不算大,大概一百多个节点,跑着几百个服务。主要用的是自建集群,不是云厂商的托管K8s。网络用的是Calico,存储用的是Ceph,Ingress用的是Nginx Ingress Controller。不同的环境可能会遇到不同的问题,本文仅供参考。
坑一:kubelet证书过期导致节点NotReady
升级完第一个节点之后,发现节点状态变成了NotReady。查了一下kubelet的日志,发现是证书过期了。
K8s 1.32对kubelet的证书轮换机制做了一些调整。之前的版本中,kubelet证书默认有效期是一年,到期前会自动轮换。但1.32版本中,证书轮换的默认行为变了,如果没有正确配置,证书到期后不会自动轮换,导致kubelet无法连接API Server,节点变成NotReady。
排查过程:
第一,查看节点状态。kubectl get nodes发现节点是NotReady状态。
第二,查看kubelet日志。journalctl -u kubelet发现有证书相关的错误,提示证书已过期。
第三,查看证书有效期。openssl x509 -in /var/lib/kubelet/pki/kubelet.crt -text -noout发现证书确实已经过期了。
第四,手动轮换证书。删除旧的证书文件,重启kubelet,让它重新申请证书。
第五,配置自动轮换。在kubelet配置中设置rotateCertificates: true,确保证书到期前自动轮换。
这个问题的根本原因是升级的时候没有注意到1.32版本对证书轮换默认行为的改变。之前的版本中,即使没有显式配置rotateCertificates,kubelet也会自动轮换证书。但1.32版本中,必须显式配置才能自动轮换。
建议:升级前仔细阅读版本更新说明,特别是关于默认行为改变的部分。升级后检查所有节点的证书有效期,确保证书轮换正常工作。
坑二:Calico与1.32的兼容性问题
升级完控制平面之后,发现Pod之间的网络不通了。查了一下,是Calico的问题。
K8s 1.32对CNI插件的接口做了一些调整,旧版本的Calico不兼容。我们用的Calico版本是3.26,升级K8s到1.32之后,Calico的node组件启动失败,导致Pod网络不通。
排查过程:
第一,查看Pod状态。发现很多Pod是Pending状态,或者是Running但网络不通。
第二,查看Calico node日志。发现有报错,提示不支持当前的K8s版本。
第三,查看Calico兼容性矩阵。发现Calico 3.26不支持K8s 1.32,需要升级到3.28或更高版本。
第四,升级Calico。按照官方文档,把Calico从3.26升级到3.28。
第五,验证网络。升级完成后,测试Pod之间的通信,确认网络恢复正常。
这个问题的教训是:升级K8s之前,一定要检查所有组件的兼容性,包括CNI插件、CSI插件、Ingress Controller、监控组件等。不能只升级K8s本身,其他组件也要跟着升级。
建议:升级前列一个兼容性检查清单,把集群中用到的所有组件都检查一遍。对于不兼容的组件,提前规划好升级方案。最好先在测试环境验证,确认没问题了再升级生产环境。
坑三:API版本废弃导致资源创建失败
升级之后,发现一些资源创建失败了,报错提示API版本不存在。
K8s 1.32废弃了一些旧的API版本,比如extensions/v1beta1、apps/v1beta2、batch/v1beta1等。这些API版本在之前的版本中已经被标记为废弃,在1.32版本中被正式移除了。如果你的资源清单中还在使用这些旧的API版本,升级后就会创建失败。
我们遇到的具体问题:
第一,一些老的Ingress资源还在使用extensions/v1beta1版本,升级后无法创建。需要改成networking.k8s.io/v1版本。
第二,一些老的Deployment资源还在使用apps/v1beta2版本,升级后无法创建。需要改成apps/v1版本。
第三,一些老的CronJob资源还在使用batch/v1beta1版本,升级后无法创建。需要改成batch/v1版本。
排查和解决过程:
第一,收集所有资源清单。把集群中所有的YAML文件都找出来。
第二,检查API版本。用grep搜索所有使用旧API版本的文件。
第三,批量替换。用sed或者脚本批量替换旧的API版本为新的版本。
第四,验证。替换完成后,用kubectl apply --dry-run=client验证资源清单是否正确。
第五,重新应用。验证通过后,重新应用所有资源清单。
这个问题的教训是:K8s的API版本是不断演进的,旧版本会被逐步废弃。在日常开发中,就应该尽量使用最新的稳定API版本,不要使用已经被标记为废弃的版本。这样升级的时候就不会遇到API版本不存在的问题。
建议:在CI/CD流程中加入API版本检查,自动检测使用了废弃API版本的资源清单。定期更新资源清单,使用最新的稳定API版本。
坑四:etcd性能下降导致API Server响应慢
升级之后,发现API Server的响应变慢了,有时候甚至会超时。查了一下,是etcd的性能问题。
K8s 1.32对etcd的使用方式做了一些优化,增加了一些新的功能,但也增加了etcd的负载。如果etcd的配置不够优化,或者硬件资源不足,就会出现性能下降的问题。
我们遇到的具体问题:
第一,etcd的磁盘IO使用率很高,经常达到100%。
第二,etcd的延迟增加,导致API Server响应慢。
第三,在集群负载高的时候,etcd会出现超时,导致一些操作失败。
排查和解决过程:
第一,监控etcd性能。用etcdctl endpoint status和etcdctl endpoint health检查etcd的状态。
第二,检查磁盘IO。用iostat和iotop检查磁盘IO使用情况,发现确实是磁盘IO瓶颈。
第三,优化etcd配置。调整etcd的参数,比如--quota-backend-bytes、--auto-compaction-retention等。
第四,升级硬件。把etcd节点的磁盘从普通SSD升级到NVMe SSD,大幅提升IO性能。
第五,分离etcd和控制平面。把etcd部署在独立的节点上,不和API Server、Controller Manager、Scheduler共享资源。
优化之后,etcd的性能恢复正常,API Server的响应也快了。
这个问题的教训是:etcd是K8s集群的核心,它的性能直接影响整个集群的性能。升级K8s的时候,要考虑到新版本可能会增加etcd的负载,需要提前评估etcd的性能是否足够。
建议:etcd一定要用高性能的SSD,最好是NVMe SSD。定期监控etcd的性能指标,包括延迟、IO使用率、数据库大小等。etcd的数据库不要太大,定期压缩和碎片整理。
坑五:Ingress Controller配置变更导致502错误
升级之后,发现一些服务访问的时候出现502错误。查了一下,是Nginx Ingress Controller的配置变更导致的。
K8s 1.32对Ingress的一些默认行为做了调整,Nginx Ingress Controller也跟着升级了版本。新版本的Nginx Ingress Controller对一些配置的默认值做了改变,导致一些Ingress规则的行为和之前不一样。
我们遇到的具体问题:
第一,一些Ingress规则的proxy-read-timeout默认值变短了,导致一些响应慢的后端服务出现502错误。
第二,一些Ingress规则的proxy-body-size默认值变小了,导致上传大文件的时候出现413错误。
第三,一些使用了正则表达式路径的Ingress规则,在新版本中匹配行为变了,导致路由错误。
排查和解决过程:
第一,查看Nginx Ingress Controller日志。发现有很多 upstream timed out 和 client intended to send too large body 的错误。
第二,查看Ingress规则。检查出问题的Ingress规则,发现没有显式配置超时和body size参数,用的是默认值。
第三,调整配置。在Ingress规则中显式配置proxy-read-timeout、proxy-body-size等参数,覆盖默认值。
第四,检查正则表达式路径。 review所有使用了正则表达式路径的Ingress规则,确保在新版本中能正确匹配。
第五,验证。修改完成后,测试所有服务的访问,确认没有502和413错误。
这个问题的教训是:Ingress Controller的升级也可能会改变默认行为,导致服务访问异常。升级的时候,不仅要关注K8s本身的变化,还要关注Ingress Controller等周边组件的变化。
建议:升级后全面测试所有服务的访问,包括正常访问、大文件上传、长连接、慢响应等场景。对于重要的配置参数,显式设置值,不要依赖默认值,因为默认值可能会在版本升级时改变。
坑六:CSI驱动升级后Pod挂载卷失败
升级之后,发现一些使用了持久化存储的Pod启动失败,报错提示挂载卷失败。查了一下,是CSI驱动的问题。
K8s 1.32对CSI(Container Storage Interface)的规范做了一些更新,旧版本的CSI驱动不兼容。我们用的是Ceph CSI驱动,版本比较旧,升级K8s之后,CSI驱动的node插件启动失败,导致Pod无法挂载卷。
排查过程:
第一,查看Pod事件。kubectl describe pod发现有 MountVolume.SetUp failed 的错误。
第二,查看CSI node插件日志。发现有报错,提示CSI规范版本不兼容。
第三,查看CSI驱动兼容性。发现当前的Ceph CSI版本不支持K8s 1.32,需要升级到新版本。
第四,升级CSI驱动。按照官方文档,把Ceph CSI驱动升级到支持K8s 1.32的版本。
第五,验证。升级完成后,测试Pod挂载卷,确认存储正常工作。
这个问题的教训和Calico的问题类似:升级K8s之前,一定要检查所有组件的兼容性,包括CSI驱动。存储是非常重要的组件,如果存储出问题,可能会导致数据丢失,后果很严重。
建议:升级前在测试环境充分验证存储功能,包括卷的创建、挂载、卸载、删除、扩容、快照等。升级后检查所有使用了持久化存储的Pod,确认存储正常。对于重要的数据,提前做好备份。
坑七:RBAC权限收紧导致服务账号无法访问API
升级之后,发现一些服务的功能异常了,查日志发现是服务账号无法访问K8s API了。
K8s 1.32对RBAC(Role-Based Access Control)的一些默认权限做了收紧。之前的版本中,一些服务账号默认有比较宽松的权限,能访问很多API。但1.32版本中,默认权限收紧了,一些之前能访问的API现在不能访问了,导致服务功能异常。
我们遇到的具体问题:
第一,一些自定义的Controller无法读取ConfigMap和Secret,导致配置加载失败。
第二,一些运维工具无法列出集群中的Node和Pod,导致监控数据缺失。
第三,一些CI/CD工具无法创建和更新Deployment,导致部署失败。
排查和解决过程:
第一,查看服务账号权限。用kubectl auth can-i检查服务账号的权限,发现确实缺少一些权限。
第二,查看审计日志。通过API Server的审计日志,确认是哪些API访问被拒绝了。
第三,创建RBAC规则。为服务账号创建对应的Role和RoleBinding,授予缺少的权限。
第四,遵循最小权限原则。只授予服务账号真正需要的权限,不要授予过多的权限。
第五,验证。修改完成后,测试服务的功能,确认一切正常。
这个问题的教训是:K8s的安全策略在不断收紧,这是好事,但也可能会影响现有的服务。升级的时候,要关注RBAC权限的变化,确保服务账号有足够的权限。
建议:在CI/CD流程中加入权限检查,升级前在测试环境验证服务账号的权限是否足够。遵循最小权限原则,为每个服务账号创建专门的RBAC规则,不要使用默认的service账号。
坑八:CoreDNS配置变更导致域名解析失败
升级之后,发现一些Pod无法解析域名了。查了一下,是CoreDNS的配置变更导致的。
K8s 1.32对CoreDNS的默认配置做了一些调整,包括缓存策略、转发规则、插件顺序等。如果你的集群中有自定义的CoreDNS配置,升级后可能会被覆盖或者不兼容,导致域名解析失败。
我们遇到的具体问题:
第一,一些自定义的域名解析规则失效了,导致内部服务之间无法通过域名访问。
第二,CoreDNS的缓存策略变更,导致一些域名解析结果不正确。
第三,CoreDNS的转发规则变更,导致外部域名解析变慢或者失败。
排查和解决过程:
第一,测试域名解析。在Pod中用nslookup和dig测试域名解析,确认哪些域名解析失败。
第二,查看CoreDNS配置。检查CoreDNS的ConfigMap,发现自定义配置被覆盖了。
第三,恢复自定义配置。重新添加自定义的域名解析规则和转发规则。
第四,调整缓存策略。根据实际需求调整CoreDNS的缓存参数。
第五,验证。修改完成后,测试所有域名的解析,确认解析正常。
这个问题的教训是:CoreDNS是集群域名解析的核心,它的配置变更会影响所有服务的域名解析。升级的时候,要注意保护自定义的CoreDNS配置,不要被默认配置覆盖。
建议:把CoreDNS的配置纳入版本管理,升级前备份配置。升级后对比配置,确认自定义配置没有丢失。全面测试域名解析,包括内部域名和外部域名。
坑九:节点内存占用增加导致OOM
升级之后,发现节点的内存占用增加了很多,一些节点甚至出现了OOM(Out of Memory)。
K8s 1.32增加了一些新功能,这些功能会增加节点的内存占用。比如新的镜像垃圾回收机制、新的设备插件框架、新的CSI功能等。如果节点的内存资源本来就比较紧张,升级后可能会出现内存不足的问题。
我们遇到的具体问题:
第一,kubelet的内存占用增加了,比之前的版本多了大约20%。
第二,容器运行时的内存占用也增加了。
第三,一些节点的内存使用率达到了90%以上,偶尔会出现OOM,导致Pod被杀死。
排查和解决过程:
第一,监控节点内存。用kubectl top nodes和free命令检查节点内存使用情况。
第二,分析内存占用。用ps和top命令分析各个进程的内存占用,确认是kubelet和容器运行时的内存增加了。
第三,调整kubelet配置。优化kubelet的参数,比如--eviction-hard、--system-reserved、--kube-reserved等,合理分配内存。
第四,清理无用镜像。清理节点上不再使用的镜像,释放磁盘和内存。
第五,扩容节点。对于内存确实不够的节点,增加内存或者添加新节点。
优化之后,节点的内存占用恢复正常,没有再出现OOM。
这个问题的教训是:新版本的K8s可能会增加资源占用,升级前要评估节点的资源是否足够。如果节点资源本来就比较紧张,升级后可能会出现资源不足的问题。
建议:升级前监控节点的资源使用率,包括CPU、内存、磁盘、网络等。预留足够的资源余量,不要让节点的资源使用率长期处于高位。升级后密切关注节点的资源使用情况,及时扩容。
坑十:kube-proxy模式变更导致Service不通
升级之后,发现一些Service访问不通了。查了一下,是kube-proxy的模式变更导致的。
K8s 1.32对kube-proxy的默认模式做了调整。之前的版本中,默认模式是iptables。但1.32版本中,默认模式变成了nftables(如果系统支持的话)。nftables是iptables的替代品,性能更好,但行为和iptables有一些差异,可能会导致一些Service规则不生效。
我们遇到的具体问题:
第一,一些自定义的iptables规则和kube-proxy生成的规则冲突,导致Service访问不通。
第二,一些使用了IPVS模式的Service,在新版本中行为变了。
第三,一些节点的内核版本比较旧,不支持nftables,导致kube-proxy启动失败。
排查和解决过程:
第一,查看kube-proxy日志。发现有关于nftables的错误信息。
第二,检查Service规则。用iptables-save和nft list ruleset检查规则,发现一些规则没有正确生成。
第三,切换回iptables模式。在kube-proxy配置中设置mode: iptables,强制使用iptables模式。
第四,升级内核。对于内核版本太旧的节点,升级内核以支持nftables。
第五,验证。修改完成后,测试所有Service的访问,确认Service正常。
这个问题的教训是:kube-proxy的模式变更会影响Service的访问,升级的时候要关注这个变化。如果你的集群中有自定义的iptables规则,或者使用了特殊的网络配置,要特别注意兼容性。
建议:升级前了解kube-proxy的默认模式变化。如果你的集群对网络有特殊要求,可以先保持原来的模式,等稳定后再考虑切换。升级后全面测试Service的访问,包括ClusterIP、NodePort、LoadBalancer等类型。
升级建议
总结了这么多坑,最后给大家一些升级K8s的建议:
第一,仔细阅读版本更新说明。每个版本的更新说明中都会列出新特性、废弃的API、默认行为的改变、已知问题等。升级前一定要仔细阅读,特别是关于默认行为改变和API废弃的部分。
第二,先在测试环境验证。不要直接在生产环境升级,先在测试环境升级,充分验证所有功能。测试环境要尽量和生产环境一致,包括K8s版本、组件版本、配置、工作负载等。
第三,检查所有组件的兼容性。K8s不是孤立的,它依赖很多周边组件,比如CNI插件、CSI驱动、Ingress Controller、监控组件、日志组件、CI/CD工具等。升级前要检查所有组件的兼容性,不兼容的要提前升级。
第四,做好备份。升级前一定要做好备份,包括etcd数据、配置文件、资源清单等。万一升级失败,可以快速回滚。
第五,制定回滚方案。升级前要制定好回滚方案,明确什么情况下需要回滚,怎么回滚,回滚需要多长时间。不要等到出问题了才想怎么回滚。
第六,逐步升级。不要一次性升级所有节点,先升级一个节点,验证没问题了再升级其他节点。控制平面和工作节点也要分开升级,先升级控制平面,再升级工作节点。
第七,升级后全面测试。升级完成后,要全面测试集群的所有功能,包括节点状态、Pod调度、Service访问、存储挂载、域名解析、监控日志、CI/CD等。不要只测试几个核心功能就以为没问题了。
第八,密切监控。升级后的一段时间内,要密切监控集群的状态,包括节点资源、API Server性能、etcd性能、Pod状态、服务可用性等。及时发现和解决问题。
写在最后
K8s升级是一件有风险的事情,每次升级都可能踩坑。但只要做好充分的准备,按照规范的流程操作,大部分问题都是可以避免或者快速解决的。
这次从1.30升级到1.32,我们踩了十个坑,熬了好几个通宵,但最终还是成功完成了升级。升级之后,集群的性能和稳定性都有提升,也用上了一些新功能,总体来说还是值得的。
希望这篇文章能帮你在升级K8s 1.32+的时候少踩一些坑,少熬点夜。如果你也遇到了其他的坑,欢迎在评论区分享,大家一起交流学习。
K8s的版本更新很快,几乎每四个月就有一个新版本。保持集群版本的更新是很重要的,既能获得新功能和性能提升,也能获得安全补丁。但升级的时候一定要谨慎,做好充分的准备。
愿每一次K8s升级都能顺利完成,不用熬夜。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录