先说明一下:标题提到的K8s 1.25在本文写作时(2022年1月)尚未正式发布,根据K8s的发布节奏,预计2022年8月发布。本文基于K8s 1.22/1.23的实际使用经验,总结升级和使用过程中的常见坑和实战经验,并展望未来版本可能带来的变化。
Kubernetes(简称K8s)是目前最流行的容器编排平台,几乎所有互联网公司都在用。但K8s很复杂,版本更新快(每三个月一个版本),API变化多,每次升级都可能遇到兼容性问题。我用K8s有几年了,从1.16用到1.23,踩过不少坑,也积累了一些经验。
今天分享K8s使用和升级过程中的常见坑,以及对应的解决方案。包括API废弃、存储问题、网络问题、安全问题、性能问题等。希望能帮大家少踩坑,更顺畅地使用K8s。
一、版本升级的坑
K8s版本升级是最容易出问题的环节。每次升级都可能有API废弃、行为变化、兼容性问题。
1. API版本废弃
K8s经常废弃旧版本的API,比如:
- 1.16废弃了extensions/v1beta1的Deployment、ReplicaSet等
- 1.22废弃了一批beta API,包括certificates.k8s.io/v1beta1、rbac.authorization.k8s.io/v1beta1等
- 1.25预计会移除PodSecurityPolicy(PSP),用Pod Security Admission替代
升级前一定要检查集群里有没有用废弃的API。可以用kubectl api-resources查看当前支持的API,也可以用kubent(Kubernetes No Trouble)工具扫描集群里的废弃API。
如果不检查就升级,可能会导致资源创建失败、应用无法部署。我曾经升级1.22的时候,因为没注意到Ingress的API从networking.k8s.io/v1beta1变成了v1,导致所有Ingress都失效了,折腾了半天才修复。
2. etcd数据迁移
升级K8s版本,etcd的数据格式可能会变化。虽然一般是向后兼容的,但跨大版本升级(比如从1.20直接升到1.23)可能会有问题。
建议:
- 升级前备份etcd数据
- 不要跨多个版本升级,一个版本一个版本升(比如1.20→1.21→1.22→1.23)
- 先在测试环境升级,验证没问题再升生产环境
3. kubelet和控制面版本不一致
K8s支持kubelet比控制面低一个版本(比如控制面1.23,kubelet 1.22),但不能差太多。升级的时候要先升控制面,再升节点,不要反过来。
我见过有人先升了节点,kubelet版本比控制面高,导致节点无法注册,Pod调度不上去。一定要注意升级顺序。
二、存储相关的坑
存储是K8s里最容易出问题的部分之一。
1. PV/PVC绑定问题
PersistentVolume(PV)和PersistentVolumeClaim(PVC)的绑定有一些坑:
- PVC一旦绑定了PV,就不能改了,删除PVC后PV的回收策略(Retain/Delete/Recycle)决定了数据是否保留
- StorageClass的volumeBindingMode如果是WaitForFirstConsumer,PVC会一直Pending,直到有Pod使用它才绑定
- 本地存储(local PV)需要手动清理,删除PVC后PV不会自动复用
建议:重要数据用Retain策略,删除PVC后数据还在,可以手动恢复。用StorageClass动态 provisioning,不用手动创建PV。
2. 容器里挂载的文件权限问题
很多镜像用root用户运行,挂载的文件属主是root,而应用用非root用户运行,就会有权限问题(Permission denied)。
解决方案:
- 在Dockerfile里指定USER,或者用securityContext.runAsUser指定用户
- 用initContainer修改挂载目录的权限
- 用fsGroup指定挂载卷的组ID
3. ConfigMap/Secret更新不生效
ConfigMap和Secret更新后,已经挂载的Pod不会自动更新(除非用subPath挂载单个文件)。需要重启Pod或者用Reloader之类的工具自动触发滚动更新。
我踩过这个坑:改了ConfigMap里的配置,以为应用会自动加载,结果等了半天没反应,最后才知道要重启Pod。现在我们用了Reloader,ConfigMap/Secret更新后自动滚动更新相关的Deployment,很方便。
三、网络相关的坑
网络是K8s另一个复杂的部分。
1. Service类型选择
K8s有几种Service类型:ClusterIP、NodePort、LoadBalancer、ExternalName。选择不当会有问题:
- NodePort的端口范围是30000-32767,不能用80/443,需要在前面加负载均衡器
- LoadBalancer需要云厂商支持,本地集群没有
- ExternalName是DNS别名,不能做端口映射
一般生产环境用Ingress(比如Nginx Ingress、Traefik)来暴露HTTP服务,用LoadBalancer暴露TCP/UDP服务。
2. Ingress的坑
Ingress是最常用的暴露服务的方式,但也有很多坑:
- 不同Ingress Controller的注解(annotation)不一样,Nginx Ingress和Traefik的注解不通用
- TLS证书要提前创建好Secret,或者用cert-manager自动签发
- 路径匹配规则要注意,Nginx Ingress默认是前缀匹配,要用精确匹配需要加注解
- 后端服务的端口要和Service的端口一致,不是容器端口
建议:统一用一种Ingress Controller,熟悉它的注解和配置。用cert-manager管理证书,不用手动续签。
3. 网络策略(NetworkPolicy)
NetworkPolicy用来控制Pod之间的网络访问,但默认是不生效的,需要网络插件支持(比如Calico、Cilium)。如果用的是Flannel,NetworkPolicy不生效。
我曾经配置了NetworkPolicy以为能限制访问,结果用的是Flannel,完全不生效,相当于没配。后来换成了Calico才生效。用之前要确认网络插件支持。
四、安全相关的坑
安全是K8s里很重要但容易被忽视的部分。
1. 容器以root运行
很多Dockerfile默认用root用户运行容器,这有安全风险。如果容器被攻破,攻击者就有root权限。
建议:
- 在Dockerfile里创建非root用户,用USER指定
- 用securityContext.runAsNonRoot: true强制非root
- 用readOnlyRootFilesystem: true让根文件系统只读
2. RBAC权限过大
很多图省事,给ServiceAccount绑定cluster-admin权限,这很危险。如果Pod被攻破,整个集群都危险。
建议:遵循最小权限原则,只给需要的权限。用Role而不是ClusterRole,限定命名空间。定期审计RBAC配置。
3. 镜像漏洞
镜像里可能有已知漏洞,部署到生产环境有风险。
建议:
- 用基础镜像的最新稳定版,定期更新
- 用镜像扫描工具(比如Trivy、Clair)扫描漏洞
- 用镜像签名(cosign)验证镜像来源
- 只从可信的镜像仓库拉取镜像
4. PodSecurityPolicy(PSP)废弃
前面提到,K8s 1.25会移除PodSecurityPolicy(PSP),用Pod Security Admission替代。如果你的集群用了PSP,升级1.25前要迁移到新的Pod Security标准。
Pod Security Admission是1.22引入的alpha特性,1.23 beta,1.25稳定。它有三个级别:Privileged(不受限)、Baseline(基本安全)、Restricted(严格安全)。可以在命名空间级别配置。
建议:提前了解Pod Security Admission,在测试环境试用,为1.25升级做准备。
五、性能和资源的坑
1. 资源请求和限制设置不当
Pod的resources.requests和resources.limits设置很重要:
- requests太低,节点会超卖,导致资源争抢
- limits太低,应用会被OOMKill或者CPU节流
- limits的CPU是硬限制,超过会被节流,导致应用变慢
- memory limits超过会被OOMKill,不会被节流
建议:根据应用的实际使用情况设置requests和limits。可以用VPA(Vertical Pod Autoscaler)自动推荐资源值。CPU可以不设limits(只设requests),避免不必要的节流;memory一定要设limits,防止OOM影响节点。
2. HPA配置问题
Horizontal Pod Autoscaler(HPA)用来自动扩缩容,但配置不好会有问题:
- HPA需要metrics-server支持,很多集群默认没装
- 自定义指标(比如QPS、队列长度)需要Prometheus Adapter
- 扩缩容有冷却时间,不会立刻缩容,防止抖动
- 最小副本数不要设0(除非用KEDA支持0副本)
建议:装metrics-server,用CPU/内存做基础扩缩容。需要自定义指标用Prometheus Adapter。设置合理的最小/最大副本数和目标利用率。
3. 节点资源碎片化
集群运行久了,节点上的资源会碎片化,大Pod调度不上去。比如每个节点还剩2核4G,但一个需要4核8G的Pod调度不了。
建议:
- 用descheduler定期重平衡Pod
- 节点规格尽量统一,不要大小不一
- 用优先级和抢占(PriorityClass)保证重要Pod能调度
六、日常运维的坑
1. kubectl命令误用
kubectl是日常用得最多的工具,但也容易出错:
- kubectl delete不要加--all,可能误删所有资源
- 生产环境用--dry-run=client先预览,确认没问题再执行
- 用kubectl diff查看变更
- 重要操作前用kubectl get导出备份
建议:生产环境开启kubectl的审计日志,限制delete权限。用kubectx和kubens快速切换集群和命名空间。
2. 日志和监控缺失
K8s集群里Pod是动态的,IP会变,传统的日志监控方式不适用。
建议:
- 用EFK(Elasticsearch+Fluentd+Kibana)或Loki收集日志
- 用Prometheus+Grafana监控指标
- 用Alertmanager配置告警
- 关键应用要有分布式追踪(Jaeger、Zipkin)
没有监控和日志,出了问题就是瞎子摸象。一定要在集群搭建初期就建好监控体系。
3. etcd备份
etcd是K8s的大脑,所有数据都存在etcd里。etcd挂了或者数据丢了,整个集群就完了。
建议:
- 定期备份etcd(至少每天一次)
- 备份要存到集群外部(比如对象存储)
- 定期做恢复演练,确保备份可用
- 生产环境etcd至少3节点,保证高可用
我见过有人etcd没备份,磁盘坏了,整个集群数据丢失,只能重建。一定要重视etcd备份。
七、实战经验和建议
最后分享一些实战经验。
1. 不要追新版本
K8s更新快,但不要急着升最新版本。新版本可能有bug,生态工具(Ingress Controller、CSI插件、监控)可能还没适配。建议比最新版本晚1-2个版本,比如最新是1.23,生产用1.21或1.22。
2. 用声明式管理
所有资源用YAML文件管理,提交到Git,用kubectl apply部署。不要用kubectl run、kubectl edit这种命令式操作,不可追溯,容易出错。
可以用Helm或Kustomize管理应用配置,用ArgoCD或Flux做GitOps,自动同步。
3. 测试环境和生产环境一致
测试环境要和生产环境版本一致、配置一致,这样升级前在测试环境验证过,生产才不会出问题。不要测试环境1.20,生产环境1.23,出了问题没法复现。
4. 做好文档
K8s集群复杂,一定要做好文档:集群架构、节点信息、网络配置、存储配置、升级记录、故障处理手册。人员变动的时候,文档能帮新人快速上手。
5. 持续学习
K8s生态发展很快,新工具、新概念层出不穷。要持续学习,关注官方博客、社区动态,参加技术分享。但也要注意,不要盲目追新,适合自己的才是最好的。
八、写在最后
K8s是一个强大但复杂的系统。用好了能大大提升研发效率和系统稳定性,用不好就是各种坑和故障。
本文总结了我在K8s使用和升级过程中踩过的坑,包括版本升级、存储、网络、安全、性能、运维等方面。这些坑很多人都踩过,希望我的经验能帮大家少走弯路。
K8s 1.25虽然还没发布,但根据路线图,会有一些重要变化(PSP移除、Pod Security Admission稳定等)。提前了解,做好准备,升级的时候才不会手忙脚乱。
最后,记住一句话:K8s的问题,80%是配置问题,10%是网络问题,10%是真的bug。遇到问题不要慌,先看日志,再查配置,最后怀疑bug。
2022年了,云原生还在快速发展,K8s已经成为事实标准。掌握K8s,是每个后端和运维工程师的必修课。
希望这篇文章对你有帮助。如果你有其他踩坑经验,欢迎在评论区交流。祝大家的集群永远稳定,永不宕机。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录