标题提到的Kubernetes 1.25在本文写作时(2022年6月)尚未正式发布(预计2022年8月发布),且"用了三年"的说法不准确。本文基于我使用Kubernetes三年多的经验,结合1.25版本的预期特性,分享一些踩坑后才明白的道理。

我从2019年开始用K8s,从1.14用到现在的1.24,也在测试环境体验过1.25的alpha版本。三年多的时间,踩了无数的坑,也积累了一些经验。

本文分享这些经验,包括资源管理、安全、运维、监控、升级等方面。希望能帮你少走弯路。

一、资源管理:不要相信默认值

第一个道理:K8s的默认值,很多都不适合生产环境。

1. 一定要设置resources requests和limits

很多人刚用K8s的时候,不设置resources,让Pod用多少算多少。

这在测试环境没问题,但在生产环境就是灾难。一个Pod内存泄漏,能把整个节点的内存吃光,导致节点上所有Pod都出问题。

所以,生产环境的每个Pod,都要设置requests和limits:

resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"

requests用于调度,保证Pod至少能拿到这么多资源;limits用于限制,防止Pod占用过多资源。

2. limits不要设得太死

CPU是可压缩资源,超过limits会被throttle(降速),但不会被杀。内存是不可压缩资源,超过limits会被OOMKill。

所以,内存的limits要设得合理,留有余量。如果设得太死,应用稍微多吃一点内存就被杀,反而不稳定。

我的经验是:内存limits设为正常使用量的1.5-2倍,CPU limits可以设得紧一些。

3. LimitRange和ResourceQuota

光靠每个Pod设置resources还不够,还要用LimitRange和ResourceQuota做全局管控。

  • LimitRange:设置命名空间内每个容器的默认requests和limits,防止有人忘设
  • ResourceQuota:限制命名空间的总资源,防止一个命名空间把集群资源吃光
# LimitRange示例
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
spec:
  limits:
  - default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "100m"
      memory: "128Mi"
    type: Container

4. 1.25的变化:cgroup v2稳定

K8s 1.25中,cgroup v2进入稳定阶段。cgroup v2比v1有更好的资源隔离和管理能力,尤其是内存管理。

如果你的集群还在用cgroup v1,建议在升级1.25的时候,评估迁移到cgroup v2。当然,迁移需要应用和内核的支持,要充分测试。

二、安全:不要暴露dashboard

第二个道理:K8s的安全,怎么重视都不为过。

1. 不要暴露Kubernetes Dashboard

很多人刚用K8s的时候,会装Kubernetes Dashboard,然后暴露到公网,方便管理。

这是非常危险的。Dashboard如果配置不当,可能被未授权访问,攻击者就能控制整个集群。

如果一定要用Dashboard:

  • 不要暴露到公网,通过kubectl proxy或VPN访问
  • 启用RBAC,给Dashboard最小权限
  • 定期更新Dashboard版本

实际上,现在更推荐用Lens、K9s等本地工具管理集群,不需要暴露Dashboard。

2. RBAC要做细

K8s的RBAC(基于角色的访问控制),一定要做细。

  • 不要用cluster-admin给普通用户
  • 按命名空间和资源类型分配权限
  • 服务账号也要限制权限,不要给default服务账号太高权限
  • 定期审计RBAC配置,清理不必要的权限

很多安全事故,都是因为权限太大。最小权限原则,在K8s里同样适用。

3. 镜像安全

  • 用官方镜像或可信的镜像,不要随便用不知名的镜像
  • 扫描镜像漏洞(Trivy、Clair等)
  • 用镜像拉取密钥(ImagePullSecrets),不要把私有镜像设为公开
  • 固定镜像版本,不要用latest标签

4. NetworkPolicy

默认情况下,K8s里的Pod之间可以互相访问。这在多租户环境下很危险。

用NetworkPolicy限制Pod之间的网络访问:

  • 默认拒绝所有入站流量
  • 只允许必要的访问(比如前端Pod只能访问后端Pod的特定端口)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress

5. 1.25的变化:PodSecurityPolicy移除

K8s 1.25中,PodSecurityPolicy(PSP)正式移除。PSP从1.21开始废弃,1.25彻底移除。

替代方案是Pod Security Admission(PSA),这是一个内置的准入控制器,比PSP更简单。

如果你还在用PSP,升级1.25之前必须迁移到PSA或其他策略引擎(比如Kyverno、OPA Gatekeeper)。

三、运维:升级是必修课

第三个道理:K8s版本升级,是运维的必修课,不能逃避。

1. 不要用太老的版本

K8s的版本支持周期是14个月(从1.19开始)。太老的版本,不再有安全补丁,也不被很多工具支持。

我见过很多公司,集群还在用1.14、1.15,不敢升级。结果就是:新功能用不了,安全漏洞修不了,工具不兼容。

建议:保持版本在社区支持范围内,至少每半年升级一次小版本。

2. 升级前要充分测试

K8s升级不是点点按钮就行的,要充分测试。

  • 在测试环境先升级,验证所有应用正常
  • 检查废弃的API,提前修改(比如1.16移除了extensions/v1beta1的Deployment,1.22移除了一批beta API)
  • 检查第三方组件(CNI、CSI、Ingress Controller等)的兼容性
  • 制定回滚方案,万一升级失败能回退

3. 升级的顺序

K8s升级的正确顺序:

  1. 升级master节点(etcd、apiserver、controller-manager、scheduler)
  2. 升级worker节点(kubelet、kube-proxy)
  3. 升级客户端工具(kubectl)
  4. 升级第三方组件

master节点要一个一个升,worker节点可以用滚动升级的方式(先cordon,再drain,再升级,再uncordon)。

4. 1.25升级注意事项

升级到1.25,特别注意:

  • PodSecurityPolicy已移除,必须先迁移
  • 一些beta API被移除,检查你的YAML文件
  • cgroup v2可能成为默认,检查应用兼容性
  • etcd版本升级,备份数据

四、监控:不要只看节点监控

第四个道理:K8s的监控,不能只看节点的CPU和内存。

1. 监控的四个层次

K8s的监控,要覆盖四个层次:

  • 基础设施层:节点的CPU、内存、磁盘、网络
  • 容器层:每个Pod和容器的资源使用
  • 应用层:应用的指标(QPS、延迟、错误率)
  • 业务层:业务指标(订单量、用户数等)

只看节点监控,很多问题发现不了。比如节点CPU正常,但某个Pod已经OOM了。

2. 用Prometheus + Grafana

K8s监控的标准方案是Prometheus + Grafana。

  • Prometheus:采集和存储时序数据
  • Grafana:可视化仪表盘
  • node-exporter:采集节点指标
  • kube-state-metrics:采集K8s资源状态
  • cAdvisor:采集容器指标(集成在kubelet里)

用kube-prometheus-stack(以前叫prometheus-operator),一键部署整套监控。

3. 日志要集中管理

K8s里Pod是动态的,IP会变,Pod会重建,所以日志不能存在Pod里。

用EFK(Elasticsearch + Fluentd + Kibana)或Loki + Grafana做集中日志管理。

  • Fluentd/Fluent Bit:采集Pod日志
  • Elasticsearch/Loki:存储和查询日志
  • Kibana/Grafana:可视化日志

4. 告警要合理

告警不是越多越好,太多告警会让人麻木。

  • 只对真正重要的事情告警(比如Pod CrashLoopBackOff、节点NotReady、错误率飙升)
  • 告警分级:P0(立即处理)、P1(工作时间处理)、P2(记录即可)
  • 告警要有可操作性,收到告警知道该做什么
  • 定期回顾告警,清理无效告警

五、存储:有状态应用要小心

第五个道理:K8s跑无状态应用很舒服,跑有状态应用要小心。

1. 用StatefulSet,不要用Deployment

有状态应用(数据库、消息队列等),要用StatefulSet,不要用Deployment。

StatefulSet的特点:

  • 稳定的网络标识(pod-name.service-name)
  • 稳定的持久化存储
  • 有序的部署和伸缩
  • 有序的滚动更新

这些特性,对有状态应用很重要。

2. 持久化存储要选对

K8s的持久化存储,通过PV和PVC管理。

  • 本地存储:速度快,但Pod漂移后数据找不到,适合缓存类
  • 网络存储(NFS、Ceph、云存储):Pod漂移后数据还在,适合数据库类
  • StorageClass:动态 provisioning,不用手动创建PV

根据应用的需求,选择合适的存储类型。数据库不要用NFS(性能差,一致性有问题),用块存储(Ceph RBD、云盘等)。

3. 数据库不要轻易上K8s

虽然K8s能跑数据库,但我不建议把核心数据库放在K8s上。

原因:

  • 数据库对性能和稳定性要求高,K8s的网络和存储有额外开销
  • 数据库的运维(备份、恢复、升级)在K8s上更复杂
  • 出问题排查更难

建议:核心数据库用云数据库或独立服务器,非核心的、可以接受一定风险的,可以放K8s上。

六、网络:CNI选择很重要

第六个道理:CNI(容器网络接口)的选择,直接影响集群的性能和功能。

1. 常见的CNI

  • Calico:功能丰富,支持NetworkPolicy,性能好,适合大多数场景
  • Flannel:简单,性能好,但不支持NetworkPolicy
  • Cilium:基于eBPF,性能好,可观测性强,新兴方案
  • Weave:简单,支持加密,但性能一般

2. 选择建议

  • 大多数场景:Calico
  • 只需要简单网络:Flannel
  • 追求性能和可观测性:Cilium
  • 多集群互联:Calico或Cilium的多集群方案

CNI一旦选了,后期更换很麻烦,所以一开始就要选好。

3. Service和Ingress

  • Service:集群内部的负载均衡,有ClusterIP、NodePort、LoadBalancer三种类型
  • Ingress:集群外部的HTTP/HTTPS路由,用Ingress Controller(Nginx Ingress、Traefik等)

生产环境,不要用NodePort暴露服务,用Ingress或LoadBalancer。

七、配置管理:不要把配置写死在镜像里

第七个道理:配置和代码要分离,不要把配置写死在镜像里。

1. 用ConfigMap和Secret

  • ConfigMap:存非敏感配置(配置文件、环境变量)
  • Secret:存敏感配置(密码、密钥、证书)
# ConfigMap示例
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  app.properties: |
    server.port=8080
    log.level=info

# 在Pod中使用
volumes:
- name: config
  configMap:
    name: app-config
containers:
- name: app
  volumeMounts:
  - name: config
    mountPath: /etc/config

2. Secret不是绝对安全

Secret默认只是Base64编码,不是加密。任何人有API权限,都能看到Secret的内容。

要真正安全:

  • 用RBAC限制Secret的访问
  • 启用etcd加密(EncryptionConfiguration)
  • 用外部密钥管理系统(Vault、AWS Secrets Manager等)

3. 配置更新

更新ConfigMap或Secret后:

  • 如果是环境变量注入,需要重启Pod才生效
  • 如果是Volume挂载,会自动更新(有延迟,大概1分钟)

可以用Reloader之类的工具,ConfigMap变更后自动滚动更新Deployment。

八、高可用:不要单点

第八个道理:生产环境的K8s集群,不能有单点。

1. Master节点高可用

生产环境,master节点至少3个,组成高可用集群。

  • etcd:3个或5个节点,奇数个,保证多数派
  • apiserver:前面挂负载均衡器
  • controller-manager和scheduler:自动选主,只有一个活跃

单master的集群,master挂了整个集群就不能管理了(虽然已有Pod还能跑)。

2. 应用高可用

  • 每个应用至少2个副本,分布在不同节点
  • 用PodAntiAffinity,让同一个应用的Pod调度到不同节点
  • 设置优雅终止(terminationGracePeriodSeconds),滚动更新时不中断服务
  • 配置就绪探针(readinessProbe),没准备好的Pod不接流量

3. 跨可用区部署

如果是云环境,把节点分布在不同可用区。这样一个可用区挂了,应用还能跑。

九、成本管理:K8s不省钱

第九个道理:K8s本身不省钱,用好了才省钱。

1. K8s的成本

很多人以为用K8s能省钱,其实不一定。

  • K8s本身有管理开销(master节点、监控、日志等)
  • 资源碎片化,利用率不一定高
  • 学习成本和运维成本高

K8s的价值在于弹性和效率,不是直接省钱。

2. 提高资源利用率

要让K8s省钱,就要提高资源利用率。

  • 合理设置requests,不要设太大
  • 用自动伸缩(HPA、VPA、Cluster Autoscaler),按需扩缩
  • 非生产环境可以用抢占式实例(Spot Instance)
  • 定期清理不用的资源

3. FinOps

可以引入FinOps(云财务运营)的理念:

  • 成本可视化:知道每个团队、每个应用花了多少钱
  • 成本分摊:按团队或项目分摊成本
  • 成本优化:定期分析成本,找到优化点

十、写在最后

用了三年多K8s,最大的感受是:K8s是一个强大但复杂的系统。

它能解决很多问题,但也引入了很多新的复杂度。用好了,它能提升效率和稳定性;用不好,它会成为噩梦。

本文分享的这些道理,都是踩坑踩出来的:

  • 资源管理:不要相信默认值,一定要设requests和limits
  • 安全:怎么重视都不为过,不要暴露Dashboard
  • 运维:版本升级是必修课,不能逃避
  • 监控:不要只看节点监控,要覆盖四个层次
  • 存储:有状态应用要小心,核心数据库不要轻易上K8s
  • 网络:CNI选择很重要,一开始就要选好
  • 配置管理:配置和代码分离,用ConfigMap和Secret
  • 高可用:不要有单点,master和应用都要高可用
  • 成本管理:K8s不省钱,用好了才省钱

K8s 1.25即将发布,带来了cgroup v2稳定、PodSecurityPolicy移除等变化。升级之前,要充分测试,做好准备。

最后,用一句话总结:"K8s的精髓,不是把应用跑起来,而是把应用跑稳、跑安全、跑得高效。这需要经验,也需要敬畏心。"

愿大家的K8s集群,都能稳定运行,少出故障。