Skip to content

第15章 故障排查方法论:从入门到精通 ​

K8s很强大,但也很复杂——出问题是难免的。出了问题怎么办?怎么快速定位和解决?

很多新手遇到K8s问题就慌——不知道从哪查,不知道怎么下手。其实故障排查是有方法论的——按步骤来,一步步排查,大部分问题都能解决。

这一章我们就来讲讲K8s故障排查的方法论——常见的问题有哪些?怎么排查?用什么工具?

15.1 故障排查的基本思路 ​

首先,故障排查要有思路——不能瞎猜,瞎试。

15.1.1 从外到内,从上到下 ​

排查问题的基本思路——从外到内,从上到下,逐层排查。

什么意思?比如用户反映"访问不了服务":

  1. 先看最外层——DNS能不能解析?网络通不通?
  2. 再看入口——Ingress正常吗?Ingress Controller有没有问题?
  3. 再看Service——Service正常吗?Endpoint对不对?
  4. 再看Pod——Pod正常吗?有没有Running?日志有没有报错?
  5. 再看应用——应用本身有没有问题?日志里有没有错误?

从用户能看到的最外层,一步步往里查,直到找到根因。

不要一上来就去查应用代码——先把外层的问题排除了,再查内层的。

15.1.2 先看状态,再看日志 ​

排查的时候,先看状态——Pod是什么状态?Deployment是什么状态?节点是什么状态?

状态能告诉你很多信息——比如Pod是Pending,那就是调度的问题;Pod是CrashLoopBackOff,那就是应用启动失败;Pod是Running但访问不了,那可能是探针、Service、网络的问题。

先看状态,确定大概是哪一层的问题,再去看对应的日志。

不要一上来就翻日志——日志太多了,不知道看哪个的话,效率很低。

15.1.3 对比法:好的跟坏的对比 ​

不知道为什么坏了?——找个好的对比一下。

比如:

  • 这个Pod有问题,其他Pod正常吗?
  • 这个节点有问题,其他节点正常吗?
  • 这个服务有问题,其他服务正常吗?
  • 之前是好的吗?什么时候开始坏的?改了什么?

通过对比,你能快速缩小范围——是共性问题还是个性问题?是最近改了什么导致的吗?

很多时候,一对比,问题就清楚了——"哦,只有这个节点有问题,那就是节点的问题"。

15.1.4 复现问题 ​

如果问题能复现——那最好了。能复现的问题,都好查。

复现的时候,尽量简化——把无关的因素去掉,用最简单的方式复现。这样更容易定位根因。

如果不能复现——那就要看监控、看日志,找线索。

15.2 常见故障分类与排查步骤 ​

K8s常见的故障,大概可以分几类——Pod问题、节点问题、网络问题、存储问题、控制平面问题。

我们一个个来讲,每类问题怎么排查。

15.3 Pod类故障:最常见的问题 ​

Pod问题是最常见的——Pod起不来、Pod一直重启、Pod访问不了……

15.3.1 Pod一直Pending ​

Pod一直处于Pending状态——什么意思?就是调度不上去,还没分配节点。

为什么Pending?常见原因:

  1. 资源不够:所有节点的资源都不够了——CPU、内存不够,调度不上去。

    • 怎么查:kubectl describe pod <pod名>,看Events里有没有"Insufficient cpu"、"Insufficient memory"之类的。
    • 解决:扩容节点,或者减少Pod的资源requests,或者删一些没用的Pod。
  2. 节点选择器/亲和性匹配不到节点:Pod的nodeSelector、节点亲和性、Pod亲和性,没有节点满足。

    • 怎么查:describe pod看Events,或者看调度器日志。
    • 解决:调整选择器,或者给节点打上对应的标签。
  3. 污点不能容忍:节点有污点,Pod没有对应的容忍。

    • 怎么查:describe pod看Events。
    • 解决:给Pod加上容忍,或者去掉节点的污点。
  4. 没有可用的PV/PVC:Pod要挂载PVC,但PVC是Pending的,没有可用的PV。

    • 怎么查:看PVC的状态,describe pvc看Events。
    • 解决:创建PV,或者检查StorageClass、动态供给是不是正常。
  5. 节点不够了:所有节点都满了,或者节点都不可用。

    • 怎么查:kubectl get nodes,看节点状态。
    • 解决:加节点,或者修复有问题的节点。

Pending的问题,一般kubectl describe一下,看Events,就能知道原因。

15.3.2 Pod CrashLoopBackOff ​

Pod状态是CrashLoopBackOff——什么意思?就是容器启动失败,一直重启,越重启间隔越长。

为什么会CrashLoopBackOff?

  1. 应用启动失败:应用本身有问题,启动就退出了。

    • 怎么查:看容器日志——kubectl logs <pod名>,或者kubectl logs --previous看上一次启动的日志。
    • 解决:修复应用问题。
  2. 配置错误:配置文件错了、环境变量错了、Secret/ConfigMap不存在。

    • 怎么查:看日志,看describe pod的Events。
    • 解决:修正配置。
  3. 健康检查失败:存活探针一直失败,容器被杀死重启。

    • 怎么查:describe pod看Events,有没有"Liveness probe failed"。
    • 解决:修复应用,或者调整探针参数(初始延迟、超时时间等)。
  4. OOMKilled:内存不够,被OOM Kill了。

    • 怎么查:describe pod看容器的Last State,Reason是不是OOMKilled。
    • 解决:增加内存limits,或者优化应用内存使用。

CrashLoopBackOff的问题,主要看日志——看应用为什么启动失败。

15.3.3 Pod Running但访问不了 ​

Pod是Running的,但访问不了——怎么回事?

  1. 就绪探针失败:就绪探针没通过,Pod没加入Service后端,所以访问不到。

    • 怎么查:看Service的Endpoint——kubectl get endpoints <service名>,看有没有这个Pod的IP。没有的话就是就绪探针没通过。
    • 解决:修复应用,或者调整就绪探针。
  2. 端口不对:容器的端口跟Service的端口不匹配,或者应用监听的地址不对(比如监听了127.0.0.1,不是0.0.0.0)。

    • 怎么查:进容器里curl一下localhost,看能不能访问;看应用监听的地址。
    • 解决:改应用监听地址,或者改Service的端口。
  3. 网络问题:网络不通——CNI插件有问题,或者网络策略挡住了。

    • 怎么查:从其他Pod里curl这个Pod的IP,看能不能通;看NetworkPolicy。
    • 解决:修复网络插件,或者调整网络策略。
  4. 应用本身有问题:应用启动了,但服务不正常——比如死锁了、数据库连不上了。

    • 怎么查:看应用日志,进容器里本地测试。
    • 解决:修复应用。

Running但访问不了,先看Endpoint有没有——有就说明Service已经认它了,问题在网络或者应用本身;没有就说明就绪探针没通过,或者标签不对。

15.4 节点类故障 ​

节点出问题了——节点NotReady、节点资源不够、节点上的Pod都有问题……

15.4.1 节点NotReady ​

节点状态是NotReady——什么意思?就是节点不正常了,kubelet上报心跳有问题。

为什么NotReady?

  1. 节点宕机了:节点关机了、死机了、网络断了。

    • 怎么查:ping节点IP,看能不能通;登录节点看看。
    • 解决:修复节点,或者把节点删掉,重建。
  2. kubelet挂了:节点上的kubelet进程挂了,或者没启动。

    • 怎么查:登录节点,看kubelet的状态——systemctl status kubelet,看kubelet日志。
    • 解决:重启kubelet,或者修复kubelet的问题。
  3. 节点资源耗尽:内存满了、磁盘满了、PID用完了——kubelet没法正常工作。

    • 怎么查:登录节点,看内存、磁盘、进程数——free、df、ps。
    • 解决:释放资源,清理磁盘,或者驱逐一些Pod。
  4. 容器运行时挂了:containerd/Docker挂了,kubelet没法管理容器。

    • 怎么查:看containerd/docker的状态和日志。
    • 解决:重启容器运行时。
  5. 证书过期:kubelet的证书过期了,跟apiserver认证失败。

    • 怎么查:看kubelet日志,有没有证书相关的错误。
    • 解决:更新证书。

节点NotReady,先看节点能不能连上——能连上就登录上去看kubelet和容器运行时的状态和日志。

15.4.2 节点资源不足 ​

节点资源不够了——CPU高、内存高、磁盘满了。

怎么查:

  • 看节点的资源使用率——kubectl top node,或者监控里看
  • 看节点上有哪些Pod——kubectl get pods -o wide --field-selector spec.nodeName=<节点名>
  • 看是哪个Pod占的资源多——kubectl top pod

怎么解决:

  • 驱逐一些不重要的Pod
  • 把一些Pod调度到其他节点
  • 扩容节点
  • 优化应用的资源使用

磁盘满了是常见问题——一般是容器日志、镜像、容器的可写层占的空间。可以清理没用的镜像、清理日志、限制容器日志大小。

15.5 网络类故障 ​

网络问题是最头疼的——ping不通、访问不了、超时……

15.5.1 Pod之间不通 ​

Pod之间网络不通——怎么排查?

  1. 先查Pod IP对不对:Pod有没有IP?IP是不是正确的?

    • kubectl get pod -o wide看Pod IP
    • 进Pod里看IP——ip addr
  2. 同一个节点上的Pod通不通:先试同一个节点上的两个Pod能不能通。

    • 通的话,说明节点内部网络没问题,问题在跨节点
    • 不通的话,说明节点内部的网络有问题——网桥、veth、iptables
  3. 跨节点的Pod通不通:再试不同节点上的Pod能不能通。

    • 不通的话,问题在跨节点网络——CNI插件、路由、隧道封装
    • 看CNI插件的日志——Calico、Flannel的日志
    • 看节点上的路由表、iptables规则
    • 抓包看——tcpdump,看包到哪了
  4. 看网络策略:有没有NetworkPolicy挡住了?

    • kubectl get networkpolicy看有没有网络策略
    • 有的话,检查策略是不是把流量挡住了

网络问题排查比较麻烦——需要一步步来,从近到远,从简单到复杂,逐层排查。抓包是排查网络问题的利器——tcpdump抓包,看包发出去了没有,到哪了,回来没有。

15.5.2 Service访问不了 ​

Service访问不了——ClusterIP访问不通。

怎么排查:

  1. 先看Endpoint对不对:Service有没有对应的后端Pod?

    • kubectl get endpoints <service名>
    • 没有Endpoint的话,说明标签没匹配上,或者Pod的就绪探针没通过
  2. 直接访问Pod IP通不通:先跳过Service,直接访问Pod的IP + 端口,看通不通。

    • 不通的话,是Pod或者网络的问题
    • 通的话,问题在Service层面
  3. 看kube-proxy:kube-proxy正常吗?iptables/IPVS规则对不对?

    • 看kube-proxy的日志有没有报错
    • 看iptables规则——iptables -t nat -L,看有没有这个Service的规则
    • IPVS模式的话,ipvsadm -Ln看
  4. DNS对不对:如果是通过域名访问的,先看DNS解析对不对。

    • 进Pod里nslookup/dig一下Service域名,看解析出来的IP对不对
    • 不对的话,是CoreDNS的问题

Service问题,先查Endpoint——很多Service问题都是Endpoint不对导致的。

15.5.3 Ingress访问不了 ​

Ingress访问不了——从外部访问不到服务。

怎么排查:

  1. 先看Ingress规则对不对:域名、路径、后端Service对不对?

    • kubectl describe ingress <ingress名>
  2. Ingress Controller正常吗:Ingress Controller的Pod正常吗?日志有没有报错?

    • 看Ingress Controller的Pod状态
    • 看日志,有没有加载Ingress规则的错误
  3. 直接访问Ingress Controller的IP通不通:跳过Ingress规则,直接访问Ingress Controller的IP,看通不通。

    • 不通的话,是Ingress Controller本身或者前面负载均衡的问题
    • 通的话,问题在Ingress规则
  4. Service通不通:从Ingress Controller里,能不能访问到后端的Service?

    • 通的话,问题在Ingress规则
    • 不通的话,问题在Service或者网络

Ingress问题,从外到内一层层查——先看入口通不通,再看规则对不对,再看后端Service通不通。

15.6 存储类故障 ​

存储问题——PVC挂载不上、Pod启动不了、读写慢……

15.6.1 PVC一直Pending ​

PVC是Pending状态——什么意思?就是没有绑定到PV。

为什么?

  1. 没有合适的PV:没有满足条件的PV——容量不够、访问模式不对、StorageClass不对。

    • 怎么查:kubectl describe pvc <pvc名>看Events;kubectl get pv看有哪些PV。
    • 解决:创建合适的PV,或者用动态供给。
  2. 动态供给失败:用了StorageClass,但动态创建PV失败了。

    • 怎么查:describe pvc看Events;看StorageClass的Provisioner日志。
    • 解决:修复存储后端的问题,或者调整StorageClass配置。
  3. StorageClass不存在:PVC指定的StorageClass不存在。

    • 怎么查:kubectl get sc看有没有这个StorageClass。
    • 解决:创建StorageClass,或者改PVC的StorageClass。

15.6.2 Pod挂载Volume失败 ​

Pod启动的时候,挂载Volume失败,一直起不来。

为什么?

  1. PV不存在或者已经被用了:PV被删了,或者已经绑定给别的PVC了。

    • 怎么查:describe pod看Events;看PV状态。
    • 解决:创建PV,或者等PV释放。
  2. 存储后端有问题:存储挂了、网络不通、认证失败。

    • 怎么查:describe pod看Events;看存储插件的日志。
    • 解决:修复存储后端。
  3. 挂载参数不对:挂载选项错了、路径不对。

    • 怎么查:看Events里的错误信息。
    • 解决:修正挂载参数。

存储问题,先看PVC和PV的状态,再看Events里的错误信息——一般错误信息会告诉你为什么挂载失败。

15.7 控制平面故障 ​

控制平面出问题了——apiserver访问不了、调度不工作、控制器不工作……

控制平面问题比较严重——整个集群都受影响。

15.7.1 apiserver访问不了 ​

kubectl连不上apiserver——怎么回事?

  1. apiserver挂了:apiserver进程挂了,或者没启动。

    • 怎么查:登录Master节点,看apiserver的状态和日志;看负载均衡后面的apiserver是不是都挂了。
    • 解决:重启apiserver,或者修复问题。
  2. etcd挂了:etcd集群不正常,apiserver没法读写etcd。

    • 怎么查:看etcd的状态,etcdctl endpoint health;看apiserver日志有没有etcd相关的错误。
    • 解决:修复etcd集群。
  3. 证书问题:客户端证书过期、不对。

    • 怎么查:看错误信息有没有证书相关的。
    • 解决:更新证书。
  4. 网络问题:跟apiserver之间网络不通。

    • 怎么查:ping、telnet apiserver的地址和端口。
    • 解决:修复网络。

apiserver访问不了,先看是所有节点都访问不了,还是只有你这台访问不了——只有你这台的话,是你这边的网络或者证书问题;都访问不了的话,就是apiserver或者etcd的问题。

15.7.2 调度器不工作 ​

Pod一直Pending,调度器不调度——怎么回事?

  1. 调度器挂了:scheduler进程挂了。

    • 怎么查:看scheduler的状态和日志;看scheduler的Leader是不是正常。
    • 解决:重启scheduler。
  2. 调度器选主有问题:多个scheduler,没有选出Leader。

    • 怎么查:看scheduler日志,有没有选主相关的错误;看kube-system命名空间里的scheduler Lease。
    • 解决:修复选主问题。
  3. apiserver访问不了:调度器连不上apiserver。

    • 怎么查:看scheduler日志有没有apiserver相关的错误。
    • 解决:修复apiserver或者网络。

15.7.3 控制器不工作 ​

Deployment创建了,但没创建ReplicaSet;Service创建了,但没Endpoint——控制器不工作。

跟调度器类似——

  1. controller-manager挂了
  2. 选主有问题
  3. 连不上apiserver

排查思路也类似——看controller-manager的状态和日志。

15.8 常用排查工具 ​

工欲善其事,必先利其器。排查K8s问题,有哪些好用的工具?

15.8.1 kubectl:最基础也是最重要的 ​

kubectl是最基础的工具,也是最重要的——用好kubectl,能排查大部分问题。

常用的排查命令:

  • kubectl get:看资源状态
  • kubectl describe:看资源详情和事件(Events)——非常重要,大部分问题describe一下就能看到原因
  • kubectl logs:看Pod日志
  • kubectl exec:进容器里执行命令
  • kubectl top:看资源使用率
  • kubectl get events:看事件
  • kubectl explain:看资源的字段说明

一定要熟练掌握这些命令——特别是describe和logs,用得最多。

15.8.2 监控与日志系统 ​

监控和日志系统是排查问题的好帮手——

  • Prometheus + Grafana:看指标,看趋势,知道什么时候出的问题,哪些指标异常
  • 日志系统(EFK/Loki):查日志,搜索错误信息

有了监控和日志,排查问题效率高很多——不用一个个去登机器、查日志。

15.8.3 网络排查工具 ​

网络问题需要专门的工具:

  • tcpdump:抓包神器——看包发出去没有,到哪了,回来没有
  • ping / traceroute / mtr:测试网络连通性和路径
  • curl / wget:测试HTTP服务
  • dig / nslookup:测试DNS
  • iptables / ipvsadm:看iptables和IPVS规则
  • ip route / ip link:看路由和网络接口

15.8.4 高级工具 ​

还有一些高级的排查工具:

  • kubectl debug:K8s 1.18+的功能——给Pod加一个调试容器,用来排查问题,不用在业务镜像里装调试工具
  • crictl:containerd的命令行工具——直接操作容器运行时,不用kubelet
  • etcdctl:etcd的命令行工具——直接查etcd里的数据
  • stern:多Pod日志 tail 工具——同时看多个Pod的日志,比kubectl logs方便
  • k9s:终端UI工具——用键盘操作,比kubectl快,查看资源很方便
  • kubectx / kubens:快速切换集群和命名空间
  • eBPF工具:比如bcc、bpftrace——用eBPF做内核级的调试,排查深层的网络、性能问题

这些工具能大大提高排查效率——建议常用的都装上。

15.9 故障排查的最佳实践 ​

最后,讲讲故障排查的最佳实践。

15.9.1 平时做好准备 ​

故障排查不是出了问题才开始——平时就要做好准备:

  1. 建好监控和日志:没有监控和日志,出了问题两眼一抹黑
  2. 做好文档:架构图、部署文档、运维手册——出了问题能快速查
  3. 定期演练:故障演练——故意搞出一些故障,练习排查,提高团队的应急能力
  4. 备份:etcd备份、数据备份——出了大问题能恢复

15.9.2 排查过程中的注意事项 ​

排查过程中要注意:

  1. 先止损,再排查:业务出问题了,先想办法恢复服务——回滚、切流量、扩容……先让用户能用,再慢慢查根因
  2. 不要乱试:不要上来就重启、就改东西——先观察,收集信息,定位问题再动手。乱试可能会把问题搞大
  3. 记录过程:排查过程中做了什么操作、改了什么,都记下来——方便事后复盘,也方便回滚
  4. 及时升级:自己搞不定的,及时找人帮忙——不要硬扛,耽误时间

15.9.3 事后复盘 ​

问题解决了,不是就完了——一定要复盘。

复盘什么?

  • 问题的根因是什么?
  • 为什么会发生?——哪里没做好?
  • 怎么防止再发生?——加监控、加告警、改进流程、优化代码
  • 排查过程中有什么可以改进的?——怎么能更快定位?

复盘是提高的最好方式——每次故障都是一次学习的机会。不要白踩坑——踩一次坑,就要把坑填上,下次不要再掉进去。

15.10 本章小结 ​

这一章我们讲了K8s故障排查的方法论。

总结一下重点:

  • 故障排查基本思路:从外到内、从上到下、先看状态再看日志、对比法
  • Pod类故障:Pending(调度问题)、CrashLoopBackOff(启动失败)、Running但访问不了(探针/端口/网络/应用)
  • 节点类故障:NotReady、资源不足
  • 网络类故障:Pod之间不通、Service访问不了、Ingress访问不了——逐层排查,抓包定位
  • 存储类故障:PVC Pending、挂载失败
  • 控制平面故障:apiserver、调度器、控制器
  • 常用工具:kubectl、监控日志系统、网络工具、各种高级工具
  • 最佳实践:平时做好准备、先止损再排查、事后复盘

故障排查是个经验活——见得多了,自然就熟练了。但掌握了方法论,就能少走弯路,更快地定位和解决问题。

基础篇、进阶篇、运维篇到这里就结束了。接下来的高级篇,我们来讲更深入、更前沿的内容——CRD与Operator、Gateway API、CNCF生态、GitOps、Serverless、服务网格……


第16章 高级资源:CRD、Operator与自定义控制器 ​

前面我们讲的都是K8s内置的资源——Pod、Deployment、Service、ConfigMap……这些是K8s自带的。

但K8s的强大之处在于——它是可扩展的。你可以自己定义新的资源类型,自己写控制器来管理它们。

这就是CRD(Custom Resource Definition,自定义资源定义)和Operator。

这一章我们就来讲讲——怎么扩展K8s,怎么用Operator来管理复杂的有状态应用。

16.1 为什么需要CRD?——K8s的扩展哲学 ​

在讲CRD之前,我们先想想:为什么需要自定义资源?K8s内置的资源不够用吗?

16.1.1 内置资源的局限性 ​

内置的资源——Deployment、StatefulSet这些——都是通用的,能应付大部分场景。

但有些场景,内置资源不够用:

  • 你要部署一个复杂的有状态应用(比如数据库集群、消息队列),StatefulSet太基础了,不够用——你还要自己处理主从切换、备份恢复、扩容缩容、升级……
  • 你有自己的业务逻辑,想把它做成K8s的资源,用kubectl来管理
  • 你想把一些运维操作自动化,做成声明式的

内置资源是通用的,但每个应用都有自己的特点——特别是有状态应用,运维很复杂,光靠StatefulSet不够。

16.1.2 K8s的扩展哲学 ​

K8s的设计哲学是什么?——K8s本身是个平台,不是个产品。

K8s提供的是基础能力——调度、网络、存储、服务发现……然后你可以在这个平台上构建自己的东西。

怎么扩展?——用跟K8s一样的方式来扩展。

K8s本身是怎么工作的?——声明式API + 控制器。你声明你想要什么状态,控制器不断调整,让实际状态达到期望状态。

那扩展的时候,也用同样的方式——你定义自己的资源类型(CRD),写自己的控制器,跟内置的资源和控制器一样工作。

这样扩展出来的东西,跟K8s原生的体验是一样的——用kubectl管理,有API,有声明式,跟生态工具(kubectl、Grafana、GitOps)都能兼容。

这就是K8s最厉害的地方——它的扩展方式,跟它本身的工作方式是一致的。你扩展出来的东西,就像原生的一样。

16.2 CRD:自定义资源定义 ​

CRD是什么?——Custom Resource Definition,自定义资源定义。

简单说,CRD就是让你自己定义新的资源类型——就像Pod、Deployment是内置的资源类型一样,你可以自己定义新的,比如MySQL、Redis、MyApp。

16.2.1 CRD是什么? ​

举个例子——内置的Deployment,你可以这样用:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  template:
    ...

有了CRD,你可以定义一个自己的资源,比如MySQL,然后这样用:

yaml
apiVersion: database.example.com/v1
kind: MySQL
metadata:
  name: my-mysql
spec:
  replicas: 3
  version: "8.0"
  storage: 100Gi
  backup:
    schedule: "0 2 * * *"

看,跟内置资源一模一样的用法——apiVersion、kind、spec……你可以自己定义spec里有什么字段。

定义了CRD之后,你就可以像操作内置资源一样操作它——kubectl get mysql、kubectl describe mysql、kubectl delete mysql……完全一样的体验。

16.2.2 CRD只是定义——还需要控制器 ​

但是——CRD只是定义了资源类型,只是个"壳"。它只是让你能创建这种资源,能存在etcd里。

但CRD本身不做任何事情——你创建了一个MySQL CRD对象,它不会自动给你部署MySQL集群。它只是存在那里而已。

要让它真正工作,你还需要控制器——一个专门的控制器,Watch你的自定义资源,然后根据资源的定义,去做实际的事情(部署集群、配置、备份……)。

CRD + 控制器 = 完整的自定义功能。

16.3 Operator:把运维专家的知识编码成软件 ​

有了CRD和控制器,就能做很多事情了。那Operator是什么?

16.3.1 Operator是什么? ​

Operator是什么?它是一种模式——用CRD + 自定义控制器,来管理特定的应用或服务。

Operator的核心理念是——把运维专家的知识和经验,编码成软件。

什么意思?比如部署和管理一个MySQL集群,需要很多专业知识——怎么部署、怎么配置主从、怎么做备份、怎么扩容、怎么升级、怎么故障恢复……这些都是DBA的知识。

Operator就是把这些知识,写成代码——做成一个控制器。你只要声明"我要一个3节点的MySQL 8.0集群",Operator就自动帮你部署好、配置好、做好备份、做好监控……出了问题自动修复。

你不用懂MySQL运维——Operator懂。你只要会用K8s,会写YAML,就能管理复杂的有状态应用。

这就是Operator的价值——把复杂应用的运维自动化、产品化。

16.3.2 Operator能做什么? ​

Operator能做什么?基本上运维能做的事情,Operator都能做:

  • 部署:自动部署应用集群,配置好所有东西
  • 配置:自动配置应用,调整参数
  • 扩容缩容:一键扩容缩容,自动处理数据均衡
  • 升级:滚动升级应用版本,保证不中断服务
  • 备份恢复:自动备份,支持一键恢复
  • 故障自愈:节点挂了自动重建,主库挂了自动切换
  • 监控告警:自动配置监控和告警
  • 安全:自动配置证书、权限、加密
  • ……

基本上,你能想到的运维操作,Operator都能自动化。

16.3.3 Operator的成熟度 ​

Operator有不同的成熟度等级——从简单到复杂:

Level 1:基本安装

  • 能自动安装和部署
  • 最简单的Operator

Level 2:无缝升级

  • 支持应用版本升级
  • 支持配置变更

Level 3:全生命周期

  • 支持备份恢复
  • 支持故障自愈
  • 完整的应用生命周期管理

Level 4:深度洞察

  • 内置监控、告警、日志
  • 能分析应用状态
  • 提供事件和指标

Level 5:自动优化

  • 能根据负载自动调优
  • 自动优化性能、成本
  • 最高级的Operator

当然,不是所有Operator都要做到Level 5——根据应用的复杂度和需求来。但成熟的Operator,一般至少要到Level 3。

16.4 常见的Operator有哪些? ​

现在Operator生态已经非常丰富了——基本上你能想到的主流应用,都有对应的Operator。

16.4.1 数据库类 ​

数据库是Operator最常用的场景——因为数据库运维最复杂,最需要自动化。

  • PostgreSQL Operator:Crunchy Data PostgreSQL Operator、Zalando Postgres Operator
  • MySQL Operator:Oracle MySQL Operator、Percona XtraDB Cluster Operator
  • MongoDB Operator:MongoDB官方Operator、Percona MongoDB Operator
  • Redis Operator:Redis Operator、Redis Cluster Operator
  • Elasticsearch Operator:Elastic官方的ECK Operator
  • Cassandra Operator:Cassandra Operator

16.4.2 消息队列类 ​

  • Kafka Operator:Strimzi Kafka Operator、Confluent Operator
  • RabbitMQ Operator:RabbitMQ Cluster Operator
  • RocketMQ Operator

16.4.3 中间件类 ​

  • Nginx Ingress Operator
  • Prometheus Operator:Prometheus官方的,管理Prometheus、Alertmanager
  • Etcd Operator
  • MinIO Operator:对象存储

16.4.4 平台类 ​

  • Istio Operator:管理Istio服务网格
  • Knative Operator:管理Knative Serverless
  • Argo CD Operator:管理Argo CD

16.4.5 Operator Hub ​

哪里找Operator?——Operator Hub(operatorhub.io),这是Red Hat搞的Operator仓库,上面有各种各样的Operator,你可以搜索、下载、安装。

还有Operator Lifecycle Manager(OLM)——用来管理Operator的生命周期,安装、升级、卸载……

生产环境用Operator的话,建议用OLM来管理——方便,规范。

16.5 怎么开发Operator?——Operator SDK ​

如果你想自己写Operator,怎么写?

可以用Operator SDK——Red Hat开源的Operator开发框架,帮你快速生成Operator的脚手架,你只要写业务逻辑就行。

16.5.1 Operator SDK支持的模式 ​

Operator SDK支持几种开发模式:

1. Go Operator

  • 用Go语言写Operator
  • 功能最强大,最灵活
  • 适合复杂的Operator
  • 性能最好
  • 学习曲线稍陡

2. Ansible Operator

  • 用Ansible Playbook来写Operator逻辑
  • 适合熟悉Ansible的人
  • 不用写代码,写Playbook就行
  • 适合中等复杂度的Operator

3. Helm Operator

  • 用Helm Chart来部署应用
  • 最简单,把Helm Chart包成Operator
  • 适合简单的、无状态的应用
  • 功能有限,只能做部署和升级

根据你的需求和技术栈选——简单的用Helm,中等的用Ansible,复杂的用Go。

16.5.2 Operator开发的基本流程 ​

开发一个Operator,大概的流程:

  1. 定义CRD:定义你的自定义资源有哪些字段——spec里有什么,status里有什么
  2. 生成脚手架:用Operator SDK生成项目结构
  3. 写Reconcile逻辑:写控制器的核心逻辑——观察当前状态,跟期望状态对比,然后调整
  4. 测试:本地测试,在集群里测试
  5. 打包发布:打包成镜像,发布到Operator Hub或者自己的仓库

核心就是Reconcile(调和)逻辑——跟K8s内置的控制器一样,控制循环模式,不断地把当前状态调整到期望状态。

16.5.3 controller-runtime ​

Go Operator的底层是用的controller-runtime库——K8s SIG官方的控制器开发库,封装了Informer、队列、控制循环这些通用逻辑,你只要写业务逻辑就行。

controller-runtime提供了:

  • 资源的缓存和Watch
  • 工作队列
  • 控制循环框架
  • 客户端工具
  • 各种工具函数

用controller-runtime开发控制器,比自己从0写方便多了——大部分通用的东西都封装好了,你只要写Reconcile函数。

16.6 Operator vs Helm:怎么选? ​

很多人搞不清——部署应用,用Helm还是用Operator?

这两个不是替代关系,是不同层次的东西——但确实经常被拿来比较。我们来对比一下。

16.6.1 Helm是什么? ​

简单回顾一下——Helm是K8s的包管理器,你可以把应用的YAML打包成Chart,然后一键安装、升级、卸载。

Helm的本质是——模板 + 包管理。它帮你把YAML模板化,打包好,方便部署和管理。但Helm本身不做运行时的管理——部署完了就完了,应用运行的时候出了问题,Helm不管。

16.6.2 Operator是什么? ​

Operator呢——它不仅管部署,还管整个生命周期——运行时的监控、故障自愈、备份恢复、扩容升级……它是一直运行着的,不断地管理你的应用。

简单说:

  • Helm是"一次性"的——帮你部署,部署完就完了
  • Operator是"持续的"——部署完了还一直在,持续管理应用的整个生命周期

16.6.3 怎么选? ​

  • 简单的、无状态的应用 → 用Helm就够了——部署完了不用怎么管,Deployment自己就能自愈
  • 复杂的、有状态的应用 → 用Operator——需要复杂的运维操作,Operator能自动化
  • 快速验证、测试环境 → Helm更简单、更灵活
  • 生产环境、复杂应用 → Operator更强大、更自动化

很多时候两者是配合的——Operator内部也可能用Helm来部署应用,或者Helm Chart里包含了CRD和Operator。

没有最好的,只有最合适的——根据你的应用复杂度和需求来选。

16.7 扩展知识:K8s API的扩展机制 ​

讲到CRD,我们扩展讲讲K8s的API扩展机制——除了CRD,还有哪些扩展API的方式?

16.7.1 CRD vs API Aggregation ​

K8s扩展API主要有两种方式:

1. CRD(Custom Resource Definition)

  • 最简单的方式
  • 你只要定义资源的结构,apiserver帮你处理存储、验证、REST API
  • 不用自己写apiserver
  • 功能有限——只能定义资源,不能自定义逻辑
  • 大部分场景用CRD就够了

2. API Aggregation(API聚合)

  • 你自己写一个apiserver,实现自定义的API
  • 然后注册到主apiserver上,用户访问主apiserver,会被转发到你的apiserver
  • 功能更强大——你可以自定义API的行为,做任何你想做的
  • 但更复杂——你要自己写apiserver,处理存储、认证、授权等等
  • 只有CRD满足不了的时候才用

CRD是最简单的API扩展方式,也是最常用的——90%以上的场景,用CRD就够了。API Aggregation是给高级场景用的,比如你需要自定义API逻辑、需要子资源、需要特殊的验证等等。

16.7.2 准入控制Webhook:扩展验证和修改 ​

前面讲准入控制的时候提到了Admission Webhook——这也是一种扩展方式。

你可以写Webhook,在资源创建/更新的时候,做:

  • 修改(Mutating):自动给资源加默认值、加标签、注入Sidecar……
  • 验证(Validating):验证资源合不合规,不合规就拒绝

这也是K8s扩展的重要方式——很多功能都是通过Webhook实现的,比如Istio的Sidecar注入、OPA Gatekeeper的策略检查。

16.7.3 调度器扩展 ​

调度器也可以扩展——你可以写调度插件,自定义调度逻辑。

调度器框架提供了很多扩展点,你可以在不同阶段插入自己的逻辑——预选、优选、预留、绑定……

如果你有特殊的调度需求,可以自己写调度插件。

16.7.4 CNI/CSI/CRI…… ​

还有各种接口扩展——CNI(网络)、CSI(存储)、CRI(容器运行时)……这些都是标准接口,你可以实现自己的插件,扩展K8s的能力。

你看,K8s到处都是可扩展的——API、准入控制、调度、网络、存储、容器运行时……每个地方都有扩展点。

这就是K8s为什么这么强大——它本身是个平台,提供基础能力和扩展点,你可以在上面构建各种各样的东西。生态这么丰富,就是因为它好扩展。

16.8 本章小结 ​

这一章我们讲了CRD和Operator——K8s的高级扩展能力。

总结一下重点:

  • CRD(自定义资源定义):让你可以定义自己的资源类型,跟内置资源一样用
  • CRD只是定义,还需要控制器才能真正工作
  • Operator模式:用CRD + 自定义控制器,管理特定应用的全生命周期
  • Operator的核心理念:把运维专家的知识编码成软件,自动化运维
  • Operator的成熟度等级:从基本安装到自动优化,共5级
  • 常见的Operator:数据库、消息队列、中间件……主流应用都有
  • Operator SDK:开发Operator的框架,支持Go、Ansible、Helm三种模式
  • Operator vs Helm:Helm是一次性部署,Operator是全生命周期管理
  • K8s的扩展机制:CRD、API聚合、准入Webhook、调度器扩展、各种接口……

CRD和Operator是K8s最强大的特性之一——它们让K8s从一个容器编排平台,变成了一个通用的云原生平台。你可以在上面构建任何你想要的东西,而且跟K8s原生的体验一致。

理解了Operator,你就理解了为什么K8s的生态这么繁荣——因为大家都在用同样的方式扩展,生态就能很好地融合在一起。

下一章,我们来讲Gateway API——下一代流量治理标准。


第17章 Gateway API:下一代流量治理标准 ​

前面讲Service和Ingress的时候,我们提到了Ingress的很多不足——功能有限、不同实现不兼容、扩展靠注解(Annotation)很乱……

那Ingress的问题怎么解决?——答案是Gateway API。

Gateway API是K8s SIG Network推出的下一代流量治理API,用来替代Ingress。它更强大、更灵活、更标准化。

这一章我们就来讲讲Gateway API——它是什么,为什么需要它,跟Ingress比好在哪。

17.1 为什么需要Gateway API?——Ingress的痛点 ​

在讲Gateway API之前,我们先回顾一下Ingress的痛点——为什么需要一个新的东西来替代它?

17.1.1 Ingress的功能太有限 ​

Ingress的功能非常基础——只能做简单的HTTP路由(按域名和路径转发)、SSL终止。

稍微复杂一点的需求,Ingress就搞不定了——比如:

  • 流量切分/金丝雀发布
  • 流量镜像
  • 基于Header的路由
  • 基于Cookie的会话保持
  • 权重路由
  • 限流、熔断
  • TCP/UDP路由
  • ……

这些功能,Ingress原生API都不支持。

17.1.2 扩展靠Annotation,很乱 ​

那Ingress怎么实现这些高级功能?——靠Annotation(注解)。

每个Ingress Controller实现,都有自己的一套Annotation——比如Nginx Ingress有几十上百个Annotation,Traefik有自己的,HAProxy又有自己的。

Annotation有什么问题?

  • 不标准:每个实现的Annotation都不一样,你换个Ingress Controller,所有Annotation都要改
  • 不类型安全:Annotation就是字符串,写错了也不知道,要运行时才发现
  • 很乱:Annotation太多了,一个Ingress上面挂几十个Annotation,看着就头疼
  • 功能受限:复杂的逻辑用Annotation很难表达
  • 不优雅:Annotation本来是用来加元数据的,不是用来写配置的

可以说,Ingress + Annotation就是个"补丁摞补丁"的方案——能用,但不好用。

17.1.3 角色不分,权限不好管 ​

Ingress还有个问题——角色不分。

谁管理Ingress?——是集群管理员?还是应用开发者?

实际上,流量入口的管理,涉及到不同的角色:

  • 集群管理员/基础设施团队:管理网关本身——部署、证书、域名、全局策略
  • 应用开发者/团队:管理自己应用的路由——路径转发、流量切分、自己的配置

但Ingress没有角色的概念——一个Ingress资源,谁都能改,权限不好控制。你给了开发者Ingress的权限,他就能改所有东西,包括全局配置,不安全。

17.1.4 只支持HTTP,不支持其他协议 ​

Ingress只支持HTTP/HTTPS——TCP、UDP、TLS Passthrough这些,Ingress原生都不支持,或者要靠Annotation。

现在的应用,协议越来越多——gRPC、WebSocket、TCP服务、UDP服务……Ingress应付不过来了。

17.1.5 总结:Ingress的问题 ​

总结一下Ingress的问题:

  • 功能太有限,高级功能靠Annotation
  • Annotation不标准、不统一,不同实现不兼容
  • 没有角色分离,权限不好管理
  • 只支持HTTP,其他协议支持差
  • 表达能力不够,复杂路由搞不定

这些问题,靠在Ingress上打补丁已经解决不了了——需要一个全新的、设计更好的API。

这就是Gateway API诞生的背景。

17.2 Gateway API是什么? ​

Gateway API是什么?它是K8s SIG Network推出的下一代流量治理API,是Ingress的继任者。

Gateway API的目标是——提供一个更强大、更灵活、更标准化、可扩展的流量治理API。

17.2.1 Gateway API的核心设计理念 ​

Gateway API的设计理念是什么?

1. 角色分离(Role-Oriented)

  • 不同的角色,管理不同的资源
  • 集群管理员管GatewayClass和Gateway
  • 应用开发者管HTTPRoute、TCPRoute这些路由资源
  • 权限分离,各司其职

2. 表达能力强(Expressive)

  • 原生支持很多高级功能——权重路由、Header匹配、流量镜像、限流……
  • 不用靠Annotation,原生API就支持
  • 类型安全,有明确的字段定义

3. 可扩展(Extensible)

  • 分层设计,核心API是标准的
  • 可以扩展——特定实现可以有自己的扩展
  • 策略附件(Policy Attachment)模式,附加策略

4. 多协议支持

  • 不仅支持HTTP,还支持TCP、UDP、TLS、gRPC……
  • 不同协议有不同的Route类型

5. 多网关实现

  • 跟Ingress一样,Gateway API只是标准,有多种实现
  • 只要实现了Gateway API的规范,就能用
  • 用户可以换实现,API不用改——因为是标准的

17.2.2 Gateway API的资源模型 ​

Gateway API有哪些核心资源?

1. GatewayClass

  • 网关类——定义网关的类型,由哪个控制器实现
  • 类似StorageClass——集群级资源,集群管理员管理
  • 一个集群可以有多个GatewayClass,对应不同的网关实现

2. Gateway

  • 网关实例——具体的一个网关,有自己的IP、端口、监听器
  • 由GatewayClass创建,类似PV由StorageClass创建
  • 一般是集群管理员或者基础设施团队管理
  • 一个Gateway可以有多个监听器(Listener),监听不同的端口、不同的协议

3. Route(路由)

  • 路由规则——定义流量怎么转发,怎么处理
  • 有多种类型:HTTPRoute、TCPRoute、UDPRoute、TLSRoute、GRPCRoute……
  • 一般是应用开发者管理——每个应用自己管理自己的路由
  • Route绑定到Gateway上——一个Gateway可以绑定多个Route,一个Route也可以绑定多个Gateway

简单说:

  • GatewayClass = 网关类型(用什么实现)
  • Gateway = 网关实例(一个具体的网关)
  • Route = 路由规则(流量怎么转)

三层结构,角色分离——非常清晰。

17.3 Gateway API vs Ingress:对比分析 ​

Gateway API跟Ingress比,到底好在哪?我们来详细对比一下。

17.3.1 功能对比 ​

功能IngressGateway API
基础HTTP路由支持支持
基于路径的路由支持支持
基于Host的路由支持支持
SSL终止支持支持
基于Header的路由靠Annotation原生支持
基于Query参数的路由靠Annotation原生支持
权重路由/流量切分靠Annotation原生支持
流量镜像靠Annotation原生支持
重写/重定向靠Annotation原生支持
限流靠Annotation原生支持(策略)
熔断靠Annotation原生支持(策略)
会话保持靠Annotation原生支持
TCP路由不支持/靠Annotation原生支持(TCPRoute)
UDP路由不支持原生支持(UDPRoute)
TLS Passthrough靠Annotation原生支持(TLSRoute)
gRPC路由靠Annotation原生支持(GRPCRoute)
角色分离没有有(GatewayClass/Gateway/Route)
类型安全否(Annotation是字符串)是(强类型API)
可扩展性差(靠Annotation)好(策略附件模式)

看,Gateway API原生支持的功能,比Ingress多太多了——而且都是标准的,所有实现都支持。

17.3.2 角色分离对比 ​

Ingress是单层的——只有Ingress一个资源,谁都能改,权限不好管。

Gateway API是三层的——GatewayClass、Gateway、Route,分别对应不同的角色:

  • 平台工程师/集群管理员 → 管GatewayClass和Gateway
  • 应用开发者 → 管自己的Route

这样权限就好控制了——开发者只能改自己应用的路由,改不了网关的全局配置,安全多了。

而且,一个Gateway可以被多个团队共享——基础设施团队部署好一个Gateway,各个团队的应用都把自己的Route绑到上面,互不干扰。

这在多团队、多租户的场景下,特别有用。

17.3.3 可扩展性对比 ​

Ingress的扩展靠Annotation——乱、不标准、不类型安全。

Gateway API的扩展靠**策略附件(Policy Attachment)**模式——策略是独立的资源,可以附加到Gateway、Route等资源上。

比如你要加一个限流策略——你创建一个RateLimitPolicy资源,然后把它附加到某个HTTPRoute上,或者某个Gateway上。

这种方式的好处:

  • 标准——策略是独立的资源,有明确的结构
  • 灵活——可以附加到不同层级(Gateway、Route、Backend)
  • 可组合——多个策略可以组合使用
  • 不污染核心API——核心API保持简洁,扩展功能用策略附件

比Annotation优雅多了。

17.3.4 多协议支持 ​

Ingress只支持HTTP——其他协议都要靠Annotation,而且每个实现不一样。

Gateway API原生支持多种协议:

  • HTTPRoute:HTTP/HTTPS路由
  • GRPCRoute:gRPC路由
  • TCPRoute:TCP路由
  • UDPRoute:UDP路由
  • TLSRoute:TLS Passthrough路由

不同协议有专门的Route类型,语义清晰,用法统一。

现在微服务、云原生应用,协议越来越多——只支持HTTP已经不够用了。Gateway API的多协议支持,正好满足这个需求。

17.4 Gateway API的核心概念 ​

我们来深入了解一下Gateway API的核心概念。

17.4.1 GatewayClass:网关类 ​

GatewayClass是什么?——它定义了网关的类型,由哪个控制器实现。

类似StorageClass——你创建PVC的时候,指定StorageClass,就知道用哪个存储后端来创建PV。

GatewayClass也一样——你创建Gateway的时候,指定GatewayClass,就知道用哪个网关控制器来实现这个Gateway。

GatewayClass是集群级资源,一般由集群管理员管理。一个集群可以有多个GatewayClass,比如:

  • 一个Nginx的GatewayClass
  • 一个Istio的GatewayClass
  • 一个Traefik的GatewayClass

你想用哪个实现,就指定对应的GatewayClass。

17.4.2 Gateway:网关实例 ​

Gateway是什么?——它是一个具体的网关实例。

Gateway定义了:

  • 用哪个GatewayClass(什么实现)
  • 有哪些监听器(Listener)——监听什么端口、什么协议、什么域名
  • 网关的网络配置——IP、端口、类型(类似Service的ClusterIP/NodePort/LoadBalancer)

Gateway一般由基础设施团队管理——他们负责部署和维护网关实例,配置全局的东西。

一个Gateway可以有多个Listener——比如:

  • 一个80端口的HTTP监听器
  • 一个443端口的HTTPS监听器
  • 一个8080端口的TCP监听器

每个Listener可以有自己的配置——协议、端口、主机名、TLS配置。

17.4.3 Route:路由规则 ​

Route是什么?——它定义了具体的路由规则,流量怎么匹配、怎么转发、怎么处理。

Route有多种类型,对应不同的协议:

  • HTTPRoute:HTTP路由——最常用的
  • GRPCRoute:gRPC路由
  • TCPRoute:TCP路由
  • UDPRoute:UDP路由
  • TLSRoute:TLS路由(Passthrough模式)

我们以HTTPRoute为例,看看它能做什么:

HTTPRoute可以定义:

  • 匹配规则:按什么匹配——Host、路径、Header、Query参数、方法……
  • 后端转发:转发到哪个后端Service,权重多少——可以多后端权重分流
  • 过滤器:对请求做什么处理——重写、重定向、Header修改、限流、镜像……
  • 超时、重试:配置超时时间、重试策略

这些功能,Ingress都要靠Annotation,Gateway API原生就支持。

Route一般由应用开发者管理——每个应用团队,自己管理自己应用的路由规则,跟自己的应用代码放在一起。

17.4.4 绑定模型:Route怎么绑到Gateway上? ​

Route怎么跟Gateway关联?——通过绑定(Binding)。

绑定的规则:

  • Route里指定要绑定到哪些Gateway(通过selector,或者直接指定Gateway名字)
  • Gateway里可以配置允许哪些Route绑定过来(通过命名空间选择、标签选择)

这样是双向的——Route想绑过来,Gateway也得同意才行。这样权限就好控制了——Gateway管理员可以控制谁能绑到我的网关上。

一个Route可以绑定到多个Gateway——比如你的路由,同时绑到公网的Gateway和内网的Gateway上。

一个Gateway可以绑定多个Route——很多应用的路由都绑到同一个Gateway上,共享这个网关实例。

这种绑定模型,非常灵活,也很安全。

17.4.5 策略附件:扩展功能 ​

前面提到了策略附件(Policy Attachment)——这是Gateway API的扩展机制。

核心API只定义基础功能——高级功能、特定实现的功能,通过策略附件来实现。

策略附件是什么样的?——策略是独立的CRD资源,你创建一个策略资源,然后通过targetRef指定它作用在哪个资源上。

比如:

  • 限流策略 → 作用在某个HTTPRoute上
  • 认证策略 → 作用在某个Gateway上
  • 重试策略 → 作用在某个后端上

策略可以作用在不同层级——Gateway、Listener、Route、Backend……层级越低,优先级越高。

这种方式的好处是——核心API保持简洁稳定,扩展功能通过策略来实现,互不干扰。而且策略是标准的资源,不是Annotation,类型安全,有明确的结构。

17.5 Gateway API的实现 ​

跟Ingress一样,Gateway API只是标准——具体的实现,有很多种。

17.5.1 主流的Gateway API实现 ​

现在支持Gateway API的实现已经很多了:

1. Envoy Gateway

  • 基于Envoy的Gateway API实现
  • Envoy官方搞的,专门为Gateway API设计
  • 功能强大,性能好
  • 比较新,但发展很快

2. Istio

  • 服务网格Istio也支持Gateway API
  • 用Istio的话,可以用Gateway API来管理入口网关
  • 功能非常强大,服务网格的能力都能用

3. Traefik

  • Traefik也支持Gateway API
  • 简单易用,云原生

4. Nginx Gateway Fabric

  • Nginx官方的Gateway API实现
  • 基于Nginx,稳定可靠

5. HAProxy

  • HAProxy也有Gateway API实现
  • 性能好,功能强

6. 云厂商的实现

  • 各大云厂商也都支持Gateway API——阿里云、腾讯云、AWS、GCP……
  • 跟云厂商的负载均衡集成

现在主流的网关/Ingress Controller,基本都在往Gateway API迁移——未来Gateway API会成为标准。

17.5.2 Gateway API的现状 ​

Gateway API现在是什么状态?

  • 已经GA(正式发布)了吗?——核心API已经GA了,部分还在beta
  • 生产能用吗?——可以了,很多公司已经在生产环境用了
  • 会替代Ingress吗?——会的,Gateway API就是Ingress的继任者,未来会逐步替代Ingress

现在是过渡期——Ingress还在用,但新项目建议直接上Gateway API,老项目可以慢慢迁移。

17.6 扩展知识:从Ingress到Gateway API的演进 ​

最后,我们聊聊K8s流量治理的演进历史——从Service到Ingress到Gateway API,是怎么一步步发展过来的。

17.6.1 第一代:Service + NodePort/LoadBalancer ​

最早的时候,K8s暴露服务靠Service——NodePort或者LoadBalancer类型。

但Service是四层的——只能做端口转发,不能做七层路由。你要按域名、路径分流,Service做不到。

而且每个服务一个LoadBalancer,太浪费了——你有100个服务,就要100个LB,成本很高。

17.6.2 第二代:Ingress ​

然后就有了Ingress——七层路由,一个入口,多个服务共享,按域名和路径分流。

Ingress解决了七层路由的问题——但前面讲了,Ingress有很多问题:功能有限、靠Annotation扩展、不标准、角色不分……

Ingress是个"够用但不好用"的方案——能解决基本问题,但复杂场景就力不从心了。

17.6.3 第三代:Gateway API ​

现在是第三代——Gateway API。

Gateway API吸取了Ingress的教训,重新设计了API:

  • 功能更强大——原生支持很多高级功能
  • 更标准——所有实现统一API,不用靠Annotation
  • 角色分离——适合多团队、多租户
  • 多协议——不只是HTTP
  • 可扩展——策略附件模式,优雅地扩展

Gateway API是面向未来的设计——它考虑了现在的需求,也考虑了未来的发展。

17.6.4 未来的方向 ​

未来流量治理会怎么发展?

  • Gateway API成为标准:Ingress逐步被替代,Gateway API成为主流
  • 服务网格融合:Gateway API跟服务网格(Istio、Cilium)融合,入口网格和服务网格统一API
  • 更高级的流量治理:灰度发布、限流、熔断、安全……这些都通过标准API来做
  • 南北向 + 东西向统一:入口流量(南北向)和服务之间的流量(东西向),用统一的API来管理

Gateway API只是个开始——未来的流量治理,会更强大、更标准、更统一。

17.7 本章小结 ​

这一章我们讲了Gateway API——下一代流量治理标准。

总结一下重点:

  • Ingress的痛点:功能有限、靠Annotation扩展、不标准、角色不分、只支持HTTP
  • Gateway API是Ingress的继任者,更强大、更灵活、更标准化
  • Gateway API的核心设计:角色分离、表达能力强、可扩展、多协议支持
  • 核心资源:GatewayClass(网关类型)、Gateway(网关实例)、Route(路由规则)——三层结构
  • Route有多种类型:HTTPRoute、TCPRoute、UDPRoute、TLSRoute、GRPCRoute……
  • 绑定模型:Route绑定到Gateway,双向控制,灵活又安全
  • 策略附件:Gateway API的扩展机制,比Annotation优雅多了
  • 主流实现:Envoy Gateway、Istio、Traefik、Nginx、云厂商……
  • 演进历史:Service → Ingress → Gateway API,一代比一代强

Gateway API是K8s流量治理的未来——新项目建议直接用Gateway API,老项目也可以考虑逐步迁移。它解决了Ingress的很多痛点,提供了更强大、更标准的流量治理能力。

下一章,我们来讲K8s生态全景——CNCF项目地图,看看云原生世界都有哪些好玩的东西。


第18章 K8s生态全景:CNCF项目地图 ​

K8s不是一个孤立的东西——它有一个庞大的生态系统。围绕K8s,有各种各样的项目和工具,覆盖了云原生的方方面面。

这些项目,很多都在**CNCF(Cloud Native Computing Foundation,云原生计算基金会)**里。CNCF是Linux基金会旗下的一个组织,专门管理云原生相关的开源项目。

这一章我们就来逛一逛云原生的生态——CNCF都有哪些项目?分别是做什么的?怎么分类的?

18.1 CNCF是什么? ​

首先,CNCF是什么?

CNCF(Cloud Native Computing Foundation)——云原生计算基金会,是Linux基金会旗下的一个非营利组织,成立于2015年,K8s就是CNCF的第一个项目。

CNCF的使命是什么?——推动云原生技术的发展和普及。

CNCF做什么?

  • 托管云原生相关的开源项目
  • 制定标准和规范
  • 推动社区发展
  • 举办会议(比如KubeCon)
  • 认证(CKA/CKAD/CKS认证、K8s一致性认证)

简单说,CNCF就是云原生世界的"官方组织"——云原生的标准、项目、生态,很多都是CNCF主导的。

18.1.1 CNCF项目的成熟度等级 ​

CNCF的项目,按成熟度分三个等级:

1. Graduated(毕业)

  • 最高等级
  • 项目已经成熟,被广泛使用,社区健康,采用率高
  • 比如Kubernetes、Prometheus、Envoy、CoreDNS、Containerd、Helm、Argo CD……
  • 毕业项目,生产环境用比较放心

2. Incubating(孵化中)

  • 中间等级
  • 项目正在发展中,有一定的采用率,社区在成长
  • 比如Cilium、Istio、Knative、OpenTelemetry、Kyverno、Loki……
  • 已经比较成熟了,很多也可以生产用了

3. Sandbox(沙箱)

  • 最低等级
  • 早期项目,还在探索阶段
  • 比如很多新的、创新的项目
  • 不建议生产环境用,除非你很了解,愿意踩坑

从Sandbox → Incubating → Graduated,是项目的成长路径——越成熟的项目,等级越高。

选项目的时候,可以参考这个等级——生产环境优先选毕业项目,其次孵化项目,沙箱项目谨慎用。

18.1.2 CNCF全景图 ​

CNCF有个很有名的东西——CNCF Cloud Native Landscape(云原生全景图)。

它是一张大图,把所有云原生相关的项目,按类别分类,放在一张图里——非常壮观,几百个项目。

这张图在哪?——landscape.cncf.io,你可以去看看,非常震撼。

但项目太多了,几百个,新手一看就晕——这都是啥?我该用哪个?

没关系,我们按类别来梳理——把主要的类别和项目讲清楚,你就有个整体印象了。

18.2 生态分类:云原生的几层楼 ​

云原生生态,大概可以分成几层——从底层到上层:

  1. 运行时层:容器运行时、容器镜像、存储……
  2. 编排与管理层:K8s本身、调度、集群管理……
  3. 应用定义与开发层:应用部署、开发工具、框架……
  4. 可观测性与分析层:监控、日志、链路追踪……
  5. 平台层:PaaS、Serverless、服务网格……
  6. 安全与合规层:安全、密钥、策略……

我们一层层来讲,每层有哪些代表性项目。

18.3 运行时层:最底层的基础 ​

最底层是运行时层——容器运行时、存储、网络这些基础的东西。

18.3.1 容器运行时 ​

容器运行时,就是跑容器的东西:

  • containerd:毕业项目,Docker现在底层用的就是它,K8s的CRI默认实现,最主流的容器运行时
  • CRI-O:孵化项目,Red Hat搞的,专门为K8s设计的CRI实现,轻量
  • runc:毕业项目,OCI运行时规范的参考实现,最底层的容器运行时,containerd、CRI-O底层都用它
  • gVisor:沙箱项目,Google搞的,用户态内核,容器更安全,适合不可信工作负载
  • Kata Containers:孵化项目,轻量虚拟机做容器,安全隔离性好,兼顾虚拟机的安全和容器的轻量

18.3.2 容器镜像与注册表 ​

镜像相关的:

  • Harbor:毕业项目,开源的镜像仓库,企业级的,功能丰富——权限、复制、扫描、签名……很多企业都在用
  • Dragonfly:孵化项目,镜像分发加速,P2P下载,大镜像、多节点拉镜像的时候快很多
  • Buildpacks:沙箱项目,自动构建镜像,不用写Dockerfile——Heroku那种风格
  • Kaniko:沙箱项目,在容器里构建镜像,不用Docker daemon——适合CI/CD场景
  • Skopeo:沙箱项目,镜像操作工具——复制、检查、转换镜像,不用拉到本地

18.3.3 存储 ​

存储相关的,前面讲存储的时候提到过一些:

  • Rook:毕业项目,K8s上的存储编排Operator——把Ceph、EdgeFS这些分布式存储,做成K8s原生的,用Operator管理
  • Ceph:虽然不在CNCF里,但Rook是,Ceph是最主流的分布式存储之一
  • MinIO:对象存储,兼容S3,轻量好用,很多K8s集群里用它做对象存储
  • Longhorn:沙箱项目,Rancher搞的,K8s原生的分布式块存储,简单易用
  • OpenEBS:沙箱项目,容器化的存储,基于容器的分布式存储

18.3.4 网络 ​

网络相关的,前面讲网络的时候也提到过:

  • Cilium:孵化项目,基于eBPF的网络插件,功能强大,性能好,未来方向
  • Calico:毕业项目,最主流的网络插件之一,功能全,生产环境用得多
  • Flannel:最简单的网络插件,适合测试和简单场景
  • Contour:孵化项目,基于Envoy的Ingress Controller
  • Istio:孵化项目,服务网格,这个我们后面单独讲

18.4 编排与管理层:K8s和集群管理 ​

再往上一层,是编排与管理层——核心就是K8s,还有围绕K8s的集群管理、调度这些。

18.4.1 编排与调度 ​

核心当然是:

  • Kubernetes:毕业项目,这个就不用多说了,整个云原生的核心

还有一些调度相关的:

  • Volcano:沙箱项目,批量计算调度器——专门为AI、大数据、高性能计算场景设计的调度器,支持GPU调度、队列、优先级、抢占这些
  • Karmada:沙箱项目,多集群调度——把Pod调度到多个K8s集群,多云、混合云场景
  • Argo Workflows:毕业项目,工作流引擎——在K8s上跑工作流,DAG任务,常用于CI/CD、数据处理

18.4.2 集群管理 ​

集群管理相关的——部署和管理多个K8s集群:

  • kubeadm:K8s官方的集群部署工具,这个我们讲过
  • Rancher:虽然不在CNCF里,但很有名,K8s集群管理平台,管理多个集群
  • kOps:Kubernetes Operations,云上部署K8s集群的工具
  • Kubespray:基于Ansible的集群部署工具
  • Cluster API:孵化项目,用K8s的方式来管理集群——声明式地创建、升级、删除集群,把集群本身也当成K8s资源来管理
  • k3s:轻量级K8s,Rancher搞的,适合边缘、IoT、开发测试

18.4.3 多集群与联邦 ​

多集群管理是现在的热点——集群越来越多,怎么管多个集群?

  • Karmada:前面提到了,多集群调度和管理
  • Cluster API:声明式集群管理
  • Federation v2:K8s联邦,多集群统一管理,不过现在发展一般
  • Argo CD:GitOps工具,也支持多集群部署

18.5 应用定义与开发层:部署和开发应用 ​

再往上,是应用定义与开发层——怎么在K8s上部署和开发应用。

18.5.1 应用部署与包管理 ​

部署应用的工具:

  • Helm:毕业项目,K8s的包管理器,这个我们讲过,最主流的应用部署工具
  • Kustomize:毕业项目,K8s原生的配置管理工具——无模板,用patch的方式定制配置,现在kubectl内置了
  • Operator Framework:孵化项目,Operator开发框架,我们上一章讲过
  • Carvel:沙箱项目,VMware搞的一套工具集,应用部署和配置管理
  • Open Application Model(OAM):沙箱项目,应用模型标准——定义统一的应用描述模型,跟具体平台无关

18.5.2 CI/CD与持续交付 ​

CI/CD相关的:

  • Argo CD:毕业项目,GitOps工具,我们后面会专门讲
  • Flux:孵化项目,另一个GitOps工具
  • Argo Workflows:前面提到了,工作流引擎,也可以用来做CI/CD
  • Tekton:孵化项目,云原生CI/CD框架——K8s原生的CI/CD,Pipeline as Code
  • Jenkins X:沙箱项目,Jenkins的云原生版本,基于K8s的CI/CD

18.5.3 应用定义与服务网格 ​

服务网格也算在这一层?——或者算平台层。不管,放哪都行:

  • Istio:孵化项目,最主流的服务网格,我们后面专门讲
  • Linkerd:毕业项目,轻量级服务网格,比Istio简单,性能好
  • Envoy:毕业项目,高性能代理,Istio、很多Ingress Controller底层都用它

18.5.4 Serverless ​

Serverless相关的:

  • Knative:孵化项目,K8s上的Serverless平台,我们后面专门讲
  • OpenFaaS:Serverless框架,简单易用
  • KEDA:沙箱项目,K8s事件驱动自动伸缩——基于事件的自动扩缩容,支持很多事件源

18.6 可观测性与分析层:监控日志链路追踪 ​

可观测性这一层,我们前面也讲过一些:

18.6.1 监控(Metrics) ​

  • Prometheus:毕业项目,云原生监控的事实标准,这个不用多说
  • Thanos:孵化项目,Prometheus的高可用和长期存储方案——把多个Prometheus聚在一起,支持全局查询、长期存储
  • Cortex:孵化项目,另一个Prometheus水平扩展方案,多租户
  • Grafana:虽然不在CNCF里,但跟Prometheus是黄金搭档,可视化Dashboard
  • VictoriaMetrics:不在CNCF里,但很火,高性能时序数据库,可以替代Prometheus

18.6.2 日志(Logging) ​

  • Fluentd:毕业项目,日志采集器,EFK里的F
  • Fluent Bit:毕业项目,轻量级日志采集器,比Fluentd更轻,性能更好
  • Loki:孵化项目,Grafana Labs的日志系统,轻量,跟Grafana集成好
  • OpenSearch:不在CNCF里,Elasticsearch的开源分支,日志存储和搜索

18.6.3 链路追踪(Tracing) ​

  • Jaeger:毕业项目,Uber开源的链路追踪系统,最主流的之一
  • Zipkin:孵化项目,Twitter开源的,老牌链路追踪
  • OpenTelemetry:孵化项目,统一的可观测性标准,指标、日志、链路追踪统一,这个我们讲过
  • Tempo:Grafana Labs的链路追踪系统,跟Loki、Prometheus、Grafana一套的

18.6.4 混沌工程 ​

混沌工程——故意搞破坏,测试系统的韧性:

  • Chaos Mesh:孵化项目,PingCAP搞的,K8s上的混沌工程平台——注入各种故障,测试系统能不能扛住
  • Litmus:沙箱项目,另一个混沌工程工具
  • Chaos Monkey:Netflix搞的,混沌工程的鼻祖,专门杀实例

18.7 安全与合规层:安全是头等大事 ​

安全这一层也很重要——云原生安全是个大话题。

18.7.1 镜像与供应链安全 ​

  • Trivy:沙箱项目,Aqua Security的镜像漏洞扫描工具,简单好用,很火
  • Harbor:前面提到了,镜像仓库,也内置了镜像扫描
  • Sigstore:沙箱项目,软件供应链安全——给软件签名、验证,防止篡改
  • Cosign:Sigstore的一部分,容器镜像签名工具
  • Notary:沙箱项目,Docker的镜像签名项目,现在归CNCF了
  • Falco:孵化项目,运行时安全监控——监控系统调用,检测异常行为,比如容器被攻破了

18.7.2 密钥管理 ​

  • Vault:HashiCorp的,不在CNCF里,但很常用,密钥管理工具
  • Sealed Secrets:沙箱项目,加密的Secret——可以把加密的Secret放到Git里,不用担心泄露
  • External Secrets Operator:沙箱项目,把外部密钥管理系统(Vault、AWS Secrets Manager等)的密钥同步到K8s Secret里

18.7.3 策略与合规 ​

  • OPA / Gatekeeper:毕业项目,策略引擎,我们讲安全的时候提到过,做准入控制
  • Kyverno:孵化项目,另一个K8s策略引擎,专门为K8s设计,用YAML写策略,比OPA简单
  • Open Policy Agent(OPA):通用的策略引擎,Gatekeeper就是基于OPA的

18.8 平台层:PaaS与Serverless ​

最上层是平台层——在K8s之上,构建更高层的平台。

18.8.1 PaaS与应用平台 ​

  • OpenShift:Red Hat的企业级K8s平台,功能很全,企业用得多
  • Rancher:前面提到了,K8s管理平台
  • KubeSphere:青云搞的,开源的容器平台,国内很火
  • Dapr:孵化项目,分布式应用运行时——给应用提供各种能力(服务调用、状态管理、发布订阅……),应用不用自己实现,用Dapr就行

18.8.2 Serverless ​

  • Knative:后面专门讲
  • OpenFaaS:前面提到了
  • KEDA:事件驱动伸缩

18.9 怎么选?——选型建议 ​

项目太多了,怎么选?我给你一些选型建议:

18.9.1 优先选毕业项目 ​

生产环境优先选毕业项目——成熟、稳定、社区活跃、踩坑的人多,遇到问题好解决。

孵化项目,如果是比较热门的,也可以考虑——比如Cilium、Istio、OpenTelemetry这些,虽然还没毕业,但已经很成熟了,很多公司生产环境都在用。

沙箱项目,生产环境谨慎用——除非你很了解,愿意踩坑,或者有团队能维护。

18.9.2 选主流的,社区活跃的 ​

选项目的时候,看几个指标:

  • GitHub stars多不多
  • 社区活不活跃——issue、PR多不多,更新快不快
  • 用的人多不多——有没有大公司在用
  • 文档全不全
  • 有没有商业支持

主流的、用的人多的项目,遇到问题容易找到解决方案,也不容易死。

18.9.3 不要追求技术时髦 ​

不要什么新就用什么——技术选型要稳,要选成熟的、团队能hold住的。

比如你团队就几个人,对K8s还不是很熟,就别一上来就上服务网格、Serverless、各种花里胡哨的东西——先把基础打好,把K8s本身用好,把监控日志搞好。

技术是为业务服务的——不是越新越好,适合的才是最好的。

18.9.4 从核心开始,逐步扩展 ​

怎么学习和引入云原生技术?——从核心开始,逐步扩展:

  1. 先搞定核心:K8s本身 + Docker/containerd + 网络 + 存储——这是基础
  2. 再搞可观测性:Prometheus + Grafana + 日志系统——能监控、能排查问题
  3. 然后是CI/CD和应用部署:Helm + GitOps(Argo CD/Flux)——部署自动化
  4. 再然后是安全:RBAC、Pod安全、镜像扫描、策略——把安全补上
  5. 最后才是高级的:服务网格、Serverless、混沌工程……这些是锦上添花的

不要一上来就全套上——先把基础打牢,再一步步往上加。

18.10 扩展知识:云原生的定义 ​

讲到CNCF和云原生,我们顺便讲讲——到底什么是"云原生"?

很多人天天说云原生,但云原生到底是什么?好像什么都能往里面装。

18.10.1 CNCF对云原生的定义 ​

CNCF对云原生的官方定义是:

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。

这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。

简单说,云原生就是——一套在云环境里构建和运行应用的方法论和技术体系。

18.10.2 云原生的核心要素 ​

云原生的核心要素是什么?——大概有这么几个:

  1. 容器化:应用打包成容器,这是基础
  2. 动态编排:用K8s之类的编排系统,动态调度、自动伸缩、自愈
  3. 微服务:应用拆成微服务,松耦合,独立部署
  4. 声明式API:声明你想要什么,不是告诉系统怎么做——K8s的核心思想
  5. 不可变基础设施:基础设施是不可变的,要改就重新构建,不要在运行的系统上改
  6. DevOps / 持续交付:自动化的CI/CD,快速迭代,频繁发布
  7. 可观测性:监控、日志、链路追踪,系统状态可观测
  8. 服务网格(可选):服务之间的通信、安全、可观测性,下沉到基础设施

这些要素,合在一起,就是云原生。

18.10.3 云原生不是目的,是手段 ​

最后要强调一点——云原生不是目的,是手段。

不要为了云原生而云原生——不是说你用了K8s、用了微服务,你就是云原生了,就厉害了。

云原生的目的是什么?——让系统更可靠、更弹性、更易维护,让研发效率更高。

如果用了一堆云原生技术,结果系统更复杂了、更不稳定了、效率更低了——那就是本末倒置了。

技术是为业务服务的——适合你的,才是最好的。

18.11 本章小结 ​

这一章我们逛了逛K8s和云原生的生态全景。

总结一下重点:

  • CNCF是云原生的"官方组织",托管了大量云原生项目
  • CNCF项目分三个等级:Sandbox(沙箱)、Incubating(孵化)、Graduated(毕业)——越成熟等级越高
  • 云原生生态大概分几层:运行时层、编排管理层、应用定义开发层、可观测性层、安全层、平台层
  • 每层都有很多项目,覆盖了云原生的方方面面
  • 选型建议:优先选毕业项目、选主流的、不要追求技术时髦、从核心开始逐步扩展
  • 云原生是一套方法论和技术体系,核心是容器、微服务、声明式API、DevOps、可观测性
  • 云原生不是目的,是手段——技术是为业务服务的

云原生生态非常庞大——这一章只是带你逛了一圈,有个整体印象。具体用哪些,还是要根据你的需求和团队情况来选。

下一章,我们来讲GitOps与持续交付——Argo CD与Flux,看看云原生时代怎么部署应用。


第19章 GitOps与持续交付:Argo CD与Flux ​

前面讲应用生命周期的时候,我们提到了GitOps——这是现在云原生应用交付的主流方式。

这一章我们就来深入讲讲GitOps——它到底是什么?为什么这么火?怎么用?Argo CD和Flux这两个工具怎么选?

19.1 什么是GitOps? ​

先从概念讲起——什么是GitOps?

19.1.1 GitOps的定义 ​

GitOps是什么?简单说——以Git为唯一真相来源(Single Source of Truth),来管理基础设施和应用配置。

什么意思?就是:

  • 所有的基础设施和应用的配置,都存在Git仓库里
  • 所有的变更,都通过Git提交——PR、review、合并
  • 有个工具自动把Git里的状态,同步到集群里
  • 集群的实际状态,跟Git里声明的状态,保持一致

你想要什么状态,就写在Git里——工具自动帮你把集群变成那个状态。

跟K8s的声明式API是不是很像?——对,GitOps就是把K8s的声明式思想,延伸到整个应用交付流程。

19.1.2 GitOps的核心原则 ​

GitOps有几个核心原则:

1. 声明式:所有配置都是声明式的——描述你想要什么状态,不是描述怎么做。跟K8s的理念一致。

2. Git是唯一真相来源:所有的配置都在Git里——Git里的就是权威的,集群应该跟Git保持一致。不要直接在集群里改东西。

3. 自动同步:有个工具自动把Git里的状态同步到集群——不用人工kubectl apply。Git改了,集群自动就变了。

4. 可观测:你能看到实际状态跟期望状态是不是一致——如果不一致,能告警,能知道。

19.1.3 GitOps vs 传统CI/CD ​

GitOps跟传统的CI/CD有什么不一样?

传统CI/CD的流程一般是:

  1. 代码提交
  2. CI构建镜像、跑测试
  3. CD阶段,用kubectl apply或者helm upgrade,直接把应用部署到集群
  4. CD工具需要有集群的访问权限

这种方式有什么问题?

  • CD工具要有所有集群的权限——安全风险
  • 部署过程是"推"的——CI/CD推到集群
  • 你不知道集群实际状态跟你期望的是不是一致——因为可能有人手动改了集群里的东西
  • 部署的历史分散在CI/CD系统里,不在Git里

GitOps的流程是:

  1. 代码提交
  2. CI构建镜像、跑测试
  3. CI更新Git仓库里的配置(比如更新镜像版本)
  4. GitOps工具检测到Git里的配置变了,自动把变更同步到集群
  5. GitOps工具是在集群里跑的,主动从Git拉配置——不用把集群权限给CI/CD

GitOps是拉模型(Pull)——集群里的工具主动从Git拉配置,不是CI/CD推过来。

拉模型有什么好处?

  • 更安全——不用把集群凭证给CI/CD工具,减少攻击面
  • 更可靠——集群跟Git保持一致,有人手动改了集群,会自动改回去
  • 更透明——所有变更都在Git里,有历史,可审计
  • 更容易回滚——Git回滚一下,集群就回滚了

19.2 为什么GitOps这么火? ​

GitOps这几年特别火,为什么?

19.2.1 好处一:安全 ​

安全是GitOps的一大优势。

传统CI/CD,你的CI/CD系统要有所有集群的访问权限——CI/CD系统被攻破了,所有集群都危险了。而且集群越多,权限管理越麻烦。

GitOps呢?——GitOps工具是在集群里面跑的,主动从Git拉配置。CI/CD系统不需要有集群的权限——它只要往Git仓库里提交配置就行。

这样攻击面就小多了——CI/CD被攻破了,最多能改Git,改不了集群。而且Git有历史,改了什么都能看到,能回滚。

还有,所有变更都走Git——都有记录,谁改了什么、什么时候改的,一清二楚,可审计,符合合规要求。

19.2.2 好处二:可靠 ​

GitOps更可靠——因为它是声明式的,持续同步的。

传统部署,你apply一下就完了——之后集群里的东西被人改了,你不知道。时间长了,集群实际状态跟你以为的状态,差得越来越远——这就是配置漂移(Configuration Drift)。

GitOps呢?——它会持续对比Git里的期望状态和集群的实际状态,如果不一致,就自动同步回去。有人手动改了集群里的东西?——没关系,GitOps会自动把它改回来,保证集群跟Git一致。

这样,集群的状态始终是你期望的状态——不会漂移,更可靠。

19.2.3 好处三:简单易用 ​

GitOps用起来简单——因为大家都会用Git。

开发者不用学新工具——会用Git就行。提交PR、review、合并,跟平时写代码一样的流程。

回滚也简单——Git revert一下,就回滚了,不用记复杂的命令。

而且Git本身有版本控制、分支、PR、review这些功能——这些都是现成的,直接用。

19.2.4 好处四:适合多集群、多云 ​

现在很多公司有多个K8s集群——开发、测试、生产,多个地域,多云、混合云……

传统CI/CD管多个集群很麻烦——每个集群都要配置权限,部署逻辑复杂。

GitOps管多集群就很方便——每个集群里跑一个GitOps Agent,都从同一个Git仓库拉配置(或者各自的分支/目录)。集群再多,管理方式都是一样的。

而且集群挂了,恢复也快——新起一个集群,装上GitOps工具,指向Git仓库,自动就把所有应用都部署好了——分钟级恢复。

这在灾备场景下特别有用。

19.3 GitOps的两大工具:Argo CD vs Flux ​

现在GitOps的主流工具有两个——Argo CD和Flux。

这两个都是CNCF的项目——Argo CD已经毕业了,Flux还在孵化。

它们都是做GitOps的,但各有特点。我们来对比一下。

19.3.1 Argo CD ​

Argo CD是什么?——它是Intuit(就是做QuickBooks那个公司)开源的GitOps工具,现在是CNCF毕业项目。

Argo CD的特点:

  • UI非常好用:有个漂亮的Web UI,能看到应用的状态、同步状态、资源拓扑图……可视化做得很好
  • 功能丰富:支持很多功能——多集群、多租户、RBAC、SSO、回滚、同步策略、钩子……
  • 应用概念清晰:Application资源——一个应用就是一个Application对象,管理一组K8s资源
  • 支持多种配置格式:YAML、Kustomize、Helm、Jsonnet……都支持
  • 社区活跃:用的人很多,社区很活跃,发展很快
  • Argo全家桶:跟Argo Workflows、Argo Rollouts、Argo Events一起,组成Argo全家桶,覆盖CI/CD、GitOps、渐进式交付

Argo CD的优势是——功能强,UI好,易用。新手容易上手,功能全,大部分场景都能满足。

19.3.2 Flux ​

Flux是什么?——它是Weaveworks开源的GitOps工具,"GitOps"这个词就是Weaveworks提出来的。现在是CNCF孵化项目。

Flux的特点:

  • 极简主义:设计理念是"做一件事,做好"——专注GitOps,功能不追求多,但核心功能做得很好
  • K8s原生:非常符合K8s的设计哲学——声明式、控制器模式、小而专
  • 组件化:由多个小组件组成——source-controller、kustomize-controller、helm-controller、notification-controller……每个组件负责一件事
  • 跟GitOps理念更贴近:因为GitOps就是Flux的公司提出来的,所以理念上更"纯正"
  • 轻量:比较轻,资源占用小
  • Flux v2重写了:Flux v1比较老,v2完全重写了,现在v2是主力

Flux的优势是——简单、轻量、K8s原生、理念纯正。喜欢极简风格、熟悉K8s的人,可能更喜欢Flux。

19.3.3 怎么选? ​

Argo CD和Flux怎么选?

  • 你想要功能丰富、UI好用、容易上手 → 选Argo CD
  • 你喜欢极简、K8s原生、小而美的工具 → 选Flux
  • 你需要多租户、SSO、复杂的RBAC → Argo CD这方面更强
  • 你已经在用Argo其他工具(Workflows、Rollouts) → 选Argo CD,全家桶配合好
  • 你团队小,需求简单 → 两个都行,Flux更轻量

其实两个都是很好的工具——都能满足大部分场景的需求。选哪个都不会错,看你喜欢哪个风格。

国内现在Argo CD用得更多一些——因为UI好,功能全,容易推广。

19.4 GitOps的工作流 ​

GitOps具体怎么工作?我们以Argo CD为例,看看典型的工作流。

19.4.1 典型的GitOps工作流 ​

一个典型的GitOps工作流,大概是这样的:

1. 代码仓库和配置仓库分开

  • 应用代码在一个Git仓库(App Repo)
  • 部署配置在另一个Git仓库(Config Repo)
  • 为什么分开?——代码提交频繁,配置变更相对少;而且配置的权限跟代码不一样,配置可能是运维管的,代码是开发管的

2. 开发提交代码

  • 开发者提交代码到App Repo
  • 触发CI流水线

3. CI构建镜像,更新配置

  • CI构建镜像,跑测试
  • 测试通过后,把镜像推到镜像仓库
  • 然后CI更新Config Repo里的配置——把镜像版本改成新版本
  • 怎么更新?——用工具改YAML,或者用Kustomize改,然后提交PR

4. 配置变更走PR + Review

  • CI提交一个PR到Config Repo
  • 运维或者负责人review这个PR
  • 没问题就合并到主分支

5. GitOps工具自动同步

  • Argo CD/Flux监测到Config Repo的主分支有变更
  • 自动把变更同步到K8s集群——更新Deployment的镜像版本
  • 滚动更新应用

6. 同步完成,应用更新了

  • 同步完成后,Argo CD显示应用是Synced状态
  • 新版本的应用就部署好了

整个过程,完全自动化——开发者提交代码,然后自动构建、自动更新配置、自动部署。所有变更都有记录,都在Git里。

19.4.2 回滚怎么办? ​

回滚非常简单——Git revert一下,把配置回退到上一个版本,合并到主分支,GitOps工具自动就把集群回滚了。

或者用Argo CD的UI——点一下回滚按钮,就回滚到上一个同步的版本。

回滚跟部署一样,都是声明式的——非常方便。

19.4.3 多环境怎么管理? ​

多环境(开发、测试、生产)怎么管理?

常见的方式有几种:

1. 目录结构区分

  • 同一个Git仓库,不同目录对应不同环境
  • 比如:envs/dev/、envs/staging/、envs/prod/
  • 每个环境一个Application,指向不同的目录
  • 简单直观,适合环境不多的情况

2. 分支区分

  • 不同环境用不同的分支——dev分支对应开发环境,prod分支对应生产环境
  • 每个环境的GitOps工具监听不同的分支
  • 适合环境比较独立的情况

3. Kustomize Overlay

  • 用Kustomize的base + overlay模式
  • base是基础配置,每个环境有自己的overlay,覆盖一些配置(比如副本数、镜像版本、资源限制)
  • 复用性好,不会有太多重复配置
  • 推荐这种方式——干净,复用性好

一般推荐用Kustomize Overlay + 目录结构的方式——复用性好,也清晰。

19.5 GitOps的最佳实践 ​

GitOps用起来简单,但要做好,也有一些最佳实践。

19.5.1 代码仓库和配置仓库分开 ​

应用代码和部署配置,分开两个仓库——不要放在一起。

为什么?

  • 变更频率不一样——代码提交频繁,配置变更少
  • 权限不一样——代码谁都能提交,配置可能只有运维能改
  • 关注点分离——开发管代码,运维管配置
  • 部署历史清晰——配置仓库的历史就是部署历史,跟代码历史分开

19.5.2 所有变更都走Git,不要直接改集群 ​

这是GitOps最核心的原则——所有变更都通过Git,不要直接在集群里改东西。

如果你直接在集群里kubectl apply了什么——GitOps工具会自动把它改回去,因为跟Git不一致。

当然,紧急情况可以临时改——但改完之后,要记得把变更同步到Git里,不然下次同步又改回去了。

养成习惯——要改什么,先改Git,然后让GitOps工具自动同步。

19.5.3 PR + Review,所有变更都要审核 ​

所有配置变更,都走PR + Review——不要直接往主分支推。

为什么?

  • 有人审核,减少错误
  • 有记录,知道谁改的、为什么改
  • 符合合规要求

生产环境的配置,一定要有审核流程——不能一个人说了算。

19.5.4 开启自动同步 + 自动修复 ​

开启自动同步——Git变了,自动同步到集群。

还要开启自动修复(Self-Heal)——如果集群里的东西被手动改了,自动改回去,跟Git保持一致。

这样才能保证集群跟Git始终一致——不会有配置漂移。

19.5.5 配置漂移告警 ​

如果集群跟Git不一致了,要告警——通知相关人员。

正常情况下应该是一致的——如果不一致了,说明有人手动改了东西,或者出了什么问题,需要关注。

19.5.6 渐进式交付配合 ​

GitOps负责部署——但发布策略(金丝雀、蓝绿、A/B测试),可以配合渐进式交付工具。

比如Argo CD + Argo Rollouts——Argo CD负责同步配置,Argo Rollouts负责金丝雀发布、流量切分。

这样GitOps + 渐进式交付,就是完整的云原生交付方案了。

19.6 扩展知识:从CI/CD到GitOps到平台工程 ​

最后,我们聊聊应用交付的演进——从CI/CD到GitOps,再到现在的平台工程。

19.6.1 第一代:脚本 + 手动部署 ​

最早的时候,部署是怎么做的?——写脚本,手动执行。

  • 写个shell脚本,ssh到服务器上执行
  • 或者手动敲命令部署
  • 麻烦,容易出错,不可靠

19.6.2 第二代:CI/CD工具 ​

然后有了CI/CD工具——Jenkins、GitLab CI、GitHub Actions……

  • 代码提交,自动构建、自动测试、自动部署
  • 比手动强多了,自动化了
  • 但还是"推"模型,CD工具要有所有环境的权限
  • 配置漂移的问题——部署完了之后,环境被改了不知道

19.6.3 第三代:GitOps ​

现在是第三代——GitOps。

  • Git为真相来源,声明式,自动同步
  • 拉模型,更安全
  • 不会配置漂移,更可靠
  • 所有变更可审计、可回滚

GitOps是云原生时代的应用交付方式——跟K8s的声明式理念完美契合。

19.6.4 下一代:平台工程? ​

现在又有个新的概念——平台工程(Platform Engineering)。

什么是平台工程?——就是搭建一个内部开发者平台(Internal Developer Platform),开发者不用管底层的K8s、CI/CD、GitOps这些东西,只要提交代码,平台自动帮你搞定一切——构建、部署、监控、告警……

开发者只关心业务代码——其他的平台都帮你做好了。

GitOps是平台工程的基础之一——平台底层用GitOps来管理部署,上层给开发者提供更友好的接口。

技术一直在演进——从手动到自动化,从CI/CD到GitOps,从GitOps到平台工程——目标都是一样的:让开发者更高效,让交付更可靠。

19.7 本章小结 ​

这一章我们讲了GitOps与持续交付。

总结一下重点:

  • GitOps:以Git为唯一真相来源,管理基础设施和应用配置
  • 核心原则:声明式、Git是唯一真相来源、自动同步、可观测
  • GitOps vs 传统CI/CD:拉模型 vs 推模型,更安全、更可靠、更透明
  • GitOps的好处:安全、可靠、简单易用、适合多集群
  • 两大工具:Argo CD(功能强、UI好、易用)和Flux(极简、轻量、K8s原生)
  • 典型工作流:代码提交 → CI构建 → 更新配置仓库 → GitOps自动同步
  • 最佳实践:代码和配置仓库分开、所有变更走Git、PR+Review、自动同步+自动修复
  • 演进历史:手动部署 → CI/CD → GitOps → 平台工程

GitOps是云原生应用交付的最佳实践——如果你还在用手动kubectl apply,或者用CI脚本直接部署,建议试试GitOps——体验会好很多。

下一章,我们来讲Serverless与弹性伸缩——KEDA、Knative与Virtual Kubelet,看看K8s上的Serverless是什么样的。


第20章 Serverless与弹性伸缩:KEDA、Knative与Virtual Kubelet ​

前面讲HPA的时候,我们提到了自动伸缩——HPA是基于CPU和内存来伸缩的。但有些场景,HPA不够用——比如事件驱动的应用,伸缩应该基于事件、基于队列长度,而不是CPU。

还有更激进的——Serverless——没有请求的时候,缩到0,不占资源;有请求来了,自动起来处理。

这一章我们就来讲讲K8s上的Serverless和更高级的弹性伸缩——KEDA、Knative、Virtual Kubelet这些东西。

20.1 什么是Serverless? ​

先从概念讲起——什么是Serverless?

20.1.1 Serverless的定义 ​

**Serverless(无服务器)**是什么?——字面意思是"没有服务器",但不是真的没有服务器,而是——你不用管服务器。

你只管写代码,部署上去,平台自动帮你运行——有请求就起来处理,没请求就缩到0,按实际使用量付费。

Serverless的核心特点:

  • 不用管服务器:不用管底层的服务器、操作系统、运行时——平台都帮你搞定
  • 自动伸缩:根据负载自动扩缩容,从0到N,从N到0
  • 按需付费:按实际使用的资源和时间付费,不用的时候不花钱
  • 事件驱动:通常是事件触发的——HTTP请求、消息队列事件、定时任务……

最有名的Serverless服务是AWS Lambda——函数即服务(FaaS),你写个函数,上传上去,触发了就运行,按调用次数和运行时间付费。

20.1.2 Serverless的优势 ​

Serverless有什么好处?

  1. 降低成本:不用的时候不占资源,不花钱——特别是负载波动大的场景,省很多钱
  2. 减少运维:不用管服务器、不用管扩容缩容、不用管操作系统补丁——平台都搞定
  3. 快速开发:开发者只管写业务逻辑,其他的不用管,开发速度快
  4. 自动弹性:自动扩缩容,从0到几千实例都可以,应对突发流量
  5. 按需付费:用多少付多少,没有浪费

听起来很美好——但Serverless也不是银弹,有它的适用场景和局限性。

20.1.3 Serverless的局限性 ​

Serverless的局限性:

  1. 冷启动:缩到0之后,第一次请求的时候,要启动实例——有延迟,叫"冷启动"。对延迟敏感的应用可能受不了。
  2. 执行时间限制:函数一般有执行时间限制——比如最多跑15分钟,长任务跑不了。
  3. 状态管理麻烦:Serverless函数是无状态的——有状态的应用不好搞。
  4. 调试困难:在平台上跑,本地调试麻烦,出问题不好排查。
  5. 厂商锁定:用云厂商的Serverless服务,容易被厂商绑定,迁移成本高。
  6. 不适合长驻应用:一直有流量的应用,用Serverless反而更贵,还不如一直跑着。

Serverless不是万能的——适合的场景用很好,不适合的场景反而受罪。

20.1.4 适合Serverless的场景 ​

哪些场景适合Serverless?

  • 事件驱动的应用:消息处理、事件处理
  • API后端:请求量波动大的API
  • 定时任务:定时跑的任务
  • 数据处理:ETL、图片处理、视频处理
  • IoT后端:设备消息处理
  • 突发流量场景:平时流量小,偶尔有大流量

简单说——负载波动大、请求不频繁、短任务的场景,适合Serverless。

一直有稳定流量的长驻应用,就不太适合——还不如一直跑着,成本更低,延迟也更低。

20.2 K8s上的Serverless:Knative ​

那K8s上怎么搞Serverless?——最主流的方案是Knative。

20.2.1 Knative是什么? ​

Knative是什么?——它是Google、Pivotal、IBM等公司联合发起的,K8s上的Serverless平台。现在是CNCF孵化项目。

Knative的目标是——在K8s上提供一套Serverless的能力,让你在自己的K8s集群里,也能享受到Serverless的体验,而且不被厂商锁定。

Knative主要有三个核心组件:

  1. Serving(服务):Serverless服务——自动伸缩、缩到0、蓝绿发布、流量切分
  2. Eventing(事件):事件驱动——事件的生产、消费、路由,事件驱动架构
  3. Build(构建)——这个现在已经独立出去了,变成Tekton了

我们主要讲Serving和Eventing——这两个是Knative的核心。

20.2.2 Knative Serving:Serverless服务 ​

Knative Serving是做什么的?——它提供Serverless应用的部署和服务能力。

核心功能:

  • 自动伸缩:根据请求量自动扩缩容——从0到N,从N到0
  • 缩到0:没有请求的时候,实例数缩到0,不占资源
  • 冷启动:请求来了,自动启动实例——有冷启动延迟
  • 蓝绿发布:新版本发布,流量逐步切过去
  • 流量切分:可以按百分比把流量切到不同版本
  • 修订版本:每次部署生成一个Revision(修订版本),可以随时切回去

用Knative Serving,你部署一个应用——它会自动根据请求量伸缩,没请求的时候就缩到0,有请求自动起来。跟AWS Lambda类似,但跑在你自己的K8s集群里。

20.2.3 Knative Eventing:事件驱动 ​

Knative Eventing是做什么的?——它提供事件驱动的能力。

核心功能:

  • 事件生产者:各种事件源——HTTP、消息队列、定时任务、云服务事件……
  • 事件消费者:你的应用,接收事件处理
  • 事件路由:事件的路由、过滤、转换
  • 发布订阅:Pub/Sub模式,一个事件多个消费者
  • 事件通道:事件的缓冲和传递

有了Eventing,你可以做事件驱动架构——事件来了,触发你的函数/服务来处理,处理完就缩到0。

20.2.4 Knative的优缺点 ​

Knative的优点:

  • 开源,跑在自己的K8s上,不被厂商锁定
  • 跟K8s生态集成好
  • 功能强大——Serving + Eventing,完整的Serverless体验
  • 支持多种语言和运行时——只要能跑在容器里就行,不像FaaS限制那么多

Knative的缺点:

  • 比较重,组件多,部署和运维复杂
  • 学习曲线陡——概念多,理解起来有难度
  • 冷启动还是存在——虽然有各种优化,但跟一直跑着的应用比,还是有延迟
  • 性能和成熟度跟云厂商的Serverless服务比,还有差距

如果你想搞Serverless,但又不想被云厂商绑定,想自己掌控——Knative是个不错的选择。

20.3 事件驱动伸缩:KEDA ​

HPA只能基于CPU和内存伸缩——但很多应用的负载不是CPU决定的,而是事件、消息、队列长度决定的。

比如:

  • 消息队列里消息堆积了,应该扩容消费者
  • 定时任务来了,应该启动任务处理
  • HTTP请求多了,应该扩容

这时候HPA就不够用了——怎么办?用KEDA。

20.3.1 KEDA是什么? ​

**KEDA(Kubernetes Event-driven Autoscaling)**是什么?——它是K8s的事件驱动自动伸缩器,由Microsoft和Red Hat联合发起,现在是CNCF沙箱项目。

KEDA是做什么的?——它扩展了HPA,让HPA可以基于各种事件源来伸缩,而不只是CPU和内存。

简单说——KEDA = HPA + 事件源。它可以基于几十种事件源来自动伸缩你的应用。

20.3.2 KEDA支持的事件源 ​

KEDA支持很多事件源——常用的有:

  • 消息队列:Kafka、RabbitMQ、NATS、Azure Service Bus、AWS SQS、GCP Pub/Sub……
  • 数据库:MySQL、PostgreSQL、MSSQL……
  • 定时任务:Cron
  • 监控指标:Prometheus、Datadog、New Relic……
  • HTTP:基于请求量
  • 云服务:各种云的事件源
  • ……还有很多,总共几十种

基本上你能想到的事件源,KEDA都支持。

20.3.3 KEDA怎么工作? ​

KEDA的工作原理:

  1. KEDA定期从事件源获取指标——比如Kafka的消息堆积数、队列长度
  2. KEDA把这些指标暴露给HPA
  3. HPA基于这些指标,计算需要多少个副本
  4. HPA调整Deployment/StatefulSet的副本数
  5. KEDA还支持缩到0——如果没有事件,就把副本数缩到0,HPA不支持缩到0,KEDA帮它实现

简单说——KEDA负责从各种事件源拿指标,喂给HPA,HPA负责伸缩。KEDA是HPA的"扩展插件"。

而且KEDA支持缩到0——这是HPA做不到的。HPA最少1个副本,KEDA可以缩到0个——真正的Serverless体验。

20.3.4 KEDA vs Knative ​

KEDA和Knative都是做Serverless/自动伸缩的,它们有什么区别?

  • KEDA:专注于自动伸缩——它就是个伸缩器,你的应用还是普通的Deployment,KEDA帮你伸缩。简单、轻量,容易上手。
  • Knative:完整的Serverless平台——不仅有伸缩,还有流量管理、版本管理、事件系统……功能更全,但也更重更复杂。

怎么选?

  • 你只是想让应用基于事件自动伸缩,不想搞太复杂 → 选KEDA,简单轻量
  • 你想要完整的Serverless体验,事件驱动架构 → 选Knative,功能全

很多时候KEDA就够了——它解决了最核心的问题:基于事件的自动伸缩,而且简单。

20.4 虚拟节点:Virtual Kubelet ​

还有一种Serverless的思路——虚拟节点(Virtual Kubelet)。

20.4.1 Virtual Kubelet是什么? ​

Virtual Kubelet是什么?——它是一个虚拟的kubelet,模拟K8s节点的行为,但实际上背后不是真实的节点,而是Serverless容器服务。

什么意思?——Virtual Kubelet假装是一个K8s节点,注册到K8s集群里,但它这个"节点"上跑Pod,实际上是跑在Serverless容器服务上的——比如AWS Fargate、Azure Container Instances、阿里云ECI……

Pod调度到这个虚拟节点上,就会在Serverless容器服务里启动,按实际使用付费,不用你管节点。

20.4.2 Virtual Kubelet的优势 ​

Virtual Kubelet的好处:

  1. 无限容量:虚拟节点"容量无限"——你要多少Pod都能跑,不用管节点够不够
  2. 按需付费:按实际使用的资源和时间付费,不用的时候不花钱
  3. 不用管节点:不用维护节点,不用扩容节点——Serverless容器服务帮你搞定
  4. 弹性好:突发流量的时候,快速启动大量Pod,不用等节点扩容
  5. 跟K8s兼容:普通的Pod,调度到虚拟节点上就行,不用改应用

20.4.3 常见用法:弹性 bursting ​

Virtual Kubelet最常见的用法是——弹性 bursting(突发扩容)。

什么意思?——你的集群里有一些真实的节点,跑日常的负载。当突发流量来了,真实节点不够了,Pod调度到虚拟节点上,用Serverless容器服务来扛突发流量。

平时用自己的节点,成本低;突发的时候用Serverless,弹性好——两者结合,兼顾成本和弹性。

这种模式叫**"Serverless bursting"或者"虚拟节点弹性"**——很实用。

20.4.4 各云厂商的实现 ​

各大云厂商都有类似的产品:

  • 阿里云:ECI(弹性容器实例)+ Virtual Kubelet
  • AWS:Fargate + Fargate Provider
  • Azure:Container Instances + ACI Connector
  • 腾讯云:EKS 弹性容器
  • Google:Cloud Run on GKE

基本上主流云都支持——如果你在云上,想搞Serverless弹性,可以试试虚拟节点的方式,非常方便。

20.5 Serverless的几种模式对比 ​

K8s上的Serverless,我们讲了几种方案——Knative、KEDA、Virtual Kubelet。它们有什么区别?怎么选?

我们来对比一下:

方案定位核心功能复杂度适用场景
Knative完整Serverless平台Serving + Eventing,全功能高想搞完整的Serverless、事件驱动架构
KEDA事件驱动伸缩器基于事件的自动伸缩,支持缩到0低只想让应用基于事件伸缩,简单轻量
Virtual Kubelet虚拟节点/Serverless容器把Serverless容器当成K8s节点中突发弹性、按需扩容、不想管节点

它们不是互斥的——可以组合使用:

  • KEDA + Virtual Kubelet:基于事件伸缩,Pod跑在虚拟节点上——完全Serverless体验
  • Knative + Virtual Kubelet:Knative的Pod跑在虚拟节点上——更弹性

根据你的需求选——简单的需求用简单的方案,复杂的需求用完整的方案。

20.6 扩展知识:Serverless的冷启动优化 ​

Serverless最大的痛点是什么?——冷启动。

缩到0之后,第一次请求要等实例启动——延迟高,用户体验差。

怎么优化冷启动?我们来聊聊常见的优化手段。

20.6.1 保持最小实例数 ​

最简单的方式——不要缩到0,保持最少1个实例。

这样就不会有冷启动了——但这样就不是真正的Serverless了,一直占着资源,要花钱。

适合对延迟要求高、不能接受冷启动的场景。

20.6.2 预热/预留实例 ​

第二种——预留一部分实例,预热好。

平时保持几个预热好的实例,处理常规流量;突发的时候再启动新的实例。这样大部分请求都不会遇到冷启动,只有突增的部分会有。

平衡成本和延迟——比全量常驻便宜,比缩到0延迟低。

20.6.3 优化镜像 ​

优化镜像——让镜像更小,启动更快。

怎么做?

  • 用更小的基础镜像——Alpine、Distroless、scratch
  • 优化镜像层数,减少层数
  • 把不常变的层放下面,常变的放上面,利用缓存
  • 多阶段构建,镜像里只放运行需要的东西

镜像小了,拉镜像快,启动就快,冷启动时间就短了。

20.6.4 优化应用启动速度 ​

应用本身启动要快——别启动半天都起不来。

怎么做?

  • 减少初始化工作——能懒加载的就懒加载
  • 优化依赖——少加载没用的东西
  • JVM应用可以用GraalVM编译成本地镜像,启动快很多
  • 解释型语言(Python、Node.js)一般启动比编译型(Java)快

应用启动快,冷启动就快。

20.6.5 快照/恢复 ​

更高级的——快照/恢复。

把应用启动好的状态拍个快照存起来——启动的时候,直接从快照恢复,不用从头启动。

这样启动速度非常快——几乎是瞬间的。

比如AWS Lambda的SnapStart,就是这个思路——把Java应用的快照存起来,启动的时候直接恢复,冷启动时间缩短90%以上。

这是现在Serverless冷启动优化的一个重要方向。

20.6.6 流量预热 ​

还有一种——流量预热。

新版本发布的时候,先给一点点流量,让实例启动起来,再慢慢加大流量——避免一下子大量请求都遇到冷启动。

跟金丝雀发布有点像——逐步放量,让实例慢慢起来。

冷启动是Serverless的老问题了——一直在优化,现在已经比以前好很多了。但跟长驻应用比,还是有差距。所以要不要用Serverless,要看你对延迟的容忍度。

20.7 本章小结 ​

这一章我们讲了Serverless与弹性伸缩。

总结一下重点:

  • Serverless:不用管服务器,自动伸缩,按需付费,事件驱动
  • Serverless的优势:成本低、运维少、开发快、弹性好
  • Serverless的局限性:冷启动、执行时间限制、状态管理难、调试困难
  • 适合场景:事件驱动、API后端、定时任务、数据处理、突发流量
  • Knative:K8s上的完整Serverless平台,Serving + Eventing,功能全但比较重
  • KEDA:事件驱动自动伸缩器,扩展HPA,支持几十种事件源,支持缩到0,简单轻量
  • Virtual Kubelet:虚拟节点,把Serverless容器服务当成K8s节点,适合突发弹性
  • 几种方案可以组合使用,根据需求选
  • 冷启动优化:保持最小实例、预热、优化镜像、优化应用启动、快照恢复、流量预热

Serverless是云原生的一个重要方向——它不是要替代K8s,而是在K8s之上,提供更高层次的抽象,让开发者更专注于业务。

未来,Serverless和K8s会越来越融合——K8s做底层基础设施,Serverless做上层的应用平台,各取所长。

下一章,我们来讲服务网格——Istio与eBPF时代的服务治理。


基于 Vite 强力驱动 | 纯静态轻量托管