从一台到多台 — 法定人数、负载均衡器,以及增删节点的顺序
一句话总结
把节点扩展为多台时,kubespray 中改变的只是 inventory 里的几行名称和几个 host_vars 文件,但在它背后有一些设计决策:etcd 法定人数、API 服务器负载均衡,以及增加和移除节点的顺序。
为什么需要它
本课程的实验在一台 VM 上同时充当控制节点和目标节点。真实的集群则不同。控制平面挂掉一台,API 就会停止;etcd 挂掉一台,数据就会停止。Kubernetes 文档中的高可用拓扑一节介绍了两种形态——把 etcd 与控制平面节点放在一起的 stacked,以及把 etcd 单独放置的 external。stacked 所需节点少,但失去一个节点就会同时失去控制平面和 etcd 成员;external 把这种风险分开,代价是节点数量翻倍。在 kubespray 中,这个选择就是 [etcd:children] kube_control_plane,还是在 [etcd] 中写其他名称的区别。
工作原理
etcd 要用奇数。 etcd 每次写入都要获得过半数(法定人数,n//2+1)的同意。所以可容忍的故障数是 n − 过半数。
멤버 과반 견디는 장애
1 1 0
2 2 0 ← 한 대보다 나을 것이 없다
3 2 1
5 3 2
7 4 3 ← 쓰기마다 넷을 기다린다
该代码块中的韩文表头依次为成员数、过半数、可容忍的故障数;箭头之后的韩文说明分别是“并不比一台强”和“每次写入要等待四个成员”。
两台与一台可容忍的故障数相同,而过半数却变大了。kubespray 通过 validate_inventory 的 “Stop if even number of etcd hosts” 拦下这种情况,文档也说为了容灾至少要设置 3 台。etcd FAQ 对生产集群推荐 3 台或 5 台,并说明成员越多,写入延迟越大。
工作节点通过 localhost 连接 API 服务器。 如果控制平面有多台,kubelet 和 kube-proxy 就必须决定连接哪个 API 服务器。kubespray 的默认做法是:如果没有定义外部负载均衡器(loadbalancer_apiserver),loadbalancer_apiserver_localhost 就为真,在每个非控制平面的节点上启动 nginx 代理(loadbalancer_apiserver_type: nginx),在 localhost 的 kube_apiserver_port(6443)上接收请求,再分发给所有 API 服务器。HA 文档写道,这种方式比专用 LB 向 API 服务器发送更多健康检查,所以效率较低,但在不便管理 VIP 的地方很实用。对于外部客户端(运维人员的 kubectl 等),则要另外配置 LB 或 kube-vip。
增加和移除节点有专用的 playbook。 入门文档中的顺序是这样的。增加工作节点时,在 inventory 的组中加上名称,然后运行 scale.yml——重新运行 cluster.yml 也可以,但 scale.yml 只做在新工作节点上启动 kubelet 所必需的事情。移除时,remove-node.yml -e node=<이름>(占位符为节点名称)会依次执行 drain → 停止服务 → 清理证书 → 删除节点。升级文档要求,在用 --limit 选择节点运行之前,先不加限制地运行一次 playbooks/facts.yml 来刷新 facts 缓存。仓库的 ansible.cfg 把 facts 以 jsonfile 的形式缓存在 /tmp 中一天(86400 秒),而 --limit 运行不会收集其他节点的 facts,而是使用缓存。
inventory 检查不需要节点。 boilerplate.yml 不收集 facts,只看 inventory 和变量。用 -e ansible_connection=local 覆盖连接之后,即使没有真实的节点也能运行。实测中,五个节点的 inventory 检查只用了 2.4 秒。--list-hosts 不会改变任何东西,只显示每个 play 针对谁,所以在运行之前就能看到 scale.yml 是否只针对新节点、remove-node.yml 是否只确认要移除的节点。
在现场相遇的样子
常见的失败有三种。把 etcd 扩展成偶数(成为 4 台时,过半数是 3,可容忍的故障数与 3 台时相同);增加控制平面时没有确定工作节点访问 API 服务器的方式;以及只用 --limit 运行新节点时,facts 缓存为空,导致新节点的 /etc/hosts 或 etcd 配置得到了错误的地址。
本模块只到设计和检查为止。等为一个会话提供多台 VM 的功能准备好之后,会接着开设实验,直接使用这个 inventory,实际完成节点加入(scale.yml)、3 台控制平面与 etcd 法定人数、节点故障与恢复(remove-node.yml、recover-control-plane.yml),以及逐台升级的滚动升级(serial=1)。在单节点实验中把连接方式抽到 host_vars 里,就是为那一天做的准备。
下一项实验要做什么
复制示例,创建 3 台控制平面加 2 台工作节点的 inventory 和各节点的 host_vars,不用 ssh 就让它通过 kubespray 的 inventory 检查。观察 etcd 改为两台的 inventory 会在哪里被拦住,并计算法定人数表。从默认值中读取工作节点连接 API 服务器的方式,用 --list-hosts 确认增加和移除一台工作节点的命令针对谁,然后写进运维手册。