TT Lab
开始
学习 学习路径 课程

用 Kubespray 与 Terraform 搭建集群

换掉文件与用上新证书 — 续期与重置

在 TT Lab 中继续学习

一句话总结

证书续期分为两步:替换文件,以及重新启动读取该文件的进程;kubespray 的定时器只在临近到期时才代为执行这两步;reset.yml 会清除集群,但下载的文件和一些痕迹会保留下来。

为什么需要它

根据 kubeadm 证书管理文档,kubeadm 创建的客户端证书一年后到期,升级控制平面时 kubeadm 会把它们全部续期。所以文档写道:“经常升级是最好的办法。”然而现场的集群常常把版本固定一年以上,这样的集群在安装满一年的那天,API 服务器与控制器之间的认证会同时失败。如果没有告警,光是找原因就要花很久。

工作原理

在 kubespray 中,kubeadm 证书位于 /etc/kubernetes/ssl。 kubeadm 的默认位置是 /etc/kubernetes/pki,而 kubespray 把 kube_cert_dir 设为 ssl,并把 pki 链接到那里。kubeadm certs check-expiration 会显示叶子证书(apiserver、apiserver-kubelet-client、front-proxy-client,以及 admin.conf、controller-manager.conf、scheduler.conf、super-admin.conf 中的客户端证书)和 CA;在使用外部 etcd 的这种部署中,它不会显示 etcd 证书(第 4 个模块)。

续期分两步。 kubeadm certs renew all 用 CA 重新为叶子证书签名,替换文件和 kubeconfig。然后它会输出“必须重启 kube-apiserver、kube-controller-manager、kube-scheduler、etcd,才会使用新证书”。实测发现,API 服务器的服务证书在文件被替换后,即使没有重启,6443 上也已经出现了新的 serial——这是因为 kube-apiserver 会重新读取服务证书文件。但是 controller-manager 和 scheduler 是在启动时读取 kubeconfig 中的客户端证书的。所以 kubespray 的 k8s-certs-renew.sh 在续期之后,会用 crictl rmp 删除三个静态 Pod 的沙箱(kubelet 会根据清单重新启动它们),把 /root/.kube/config 替换为新的 admin.conf,并等待 6443 重新开放。实测中,从删除沙箱到 /readyz 恢复用了 6 秒。

定时器只在临近到期时才会行动。 设置 auto_renew_certificates: true 之后,控制平面 role 会安装 k8s-certs-renew.timer。默认日程是 Mon *-*-1,2,3,4,5,6,7 03:00:00,即每月第一个星期一的凌晨 3 点。只有当存在先于“下一次定时器时刻 + 7 天”到期的证书时,脚本才会续期并重启。如果用刚续期过的证书来运行服务,就会以 ## Skip cert renew and K8S container restart, since all residualTimes are beyond threshold ## 结束。这是为了在不每月扰动控制平面的情况下,只在到期前一个月左右重启一次而设计的。

reset.yml 无法撤销。 因此,如果不给出 reset_confirmation=yes,它会停在提示处。这个 role 会停止服务(kubelet、containerd、etcd),删除容器和 Pod,清空 iptables 和 IPVS 规则,并删除一长串文件和目录——/etc/kubernetes、/var/lib/kubelet、etcd 数据、containerd 存储、/etc/cni、用户主目录下的 .kube,以及 kubespray 安装的二进制文件。这些删除任务带有 ignore_errors,所以其中一个失败,也会继续删除其余的。反过来,不在列表中的东西会保留下来。实测中,下载文件缓存 /tmp/releases(543MB)、/usr/local/bin/etcdutl,以及被 kubespray 改掉的主机名都保留了下来。下载的文件被保留是有意为之的便利,使重新安装更快(实测 326 秒),而 etcdutl 则是被遗漏在删除列表之外的。

在现场相遇的样子

第一年故障的典型顺序是这样的。某一天 kubectl 因 x509: certificate has expired 被拒绝,不久之后控制器停止,新的 Pod 无法创建。紧急运行了 kubeadm certs renew all,却依然不对劲——文件是新的,但 controller-manager 仍以旧的 kubeconfig 在运行,运维人员主目录下的 .kube/config 也仍是旧证书。必须做完第二步(重启和分发 kubeconfig)才算结束。本课程的建议很简单:一年内至少升级一次;如果是无法做到这一点的集群,就打开 auto_renew_certificates,并把 check-expiration 的结果纳入监控。

reset 用于两种情况。一种是像在第 3 个模块中看到的那样,首次安装在 CNI 之前停住,再次运行也无法接续;另一种是需要修改安装之后很难更改的值(网络插件、Pod 和 Service 网段)。两种情况下,“清除之后用同一个 inventory 重来”都是最快的路径,而这是因为 inventory 以声明的形式保留了下来,才成为可能的选择。

下一项实验要做什么

搭建集群并记录证书 serial,然后手动续期并重新启动静态 Pod,确认新证书被使用。打开自动续期定时器并立即运行一次,看看脚本为什么不续期。用 reset.yml 清除之后,写下剩下的东西,再用同一个 inventory 重新搭建,确认 CA 和节点是新的。