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

用 Kubespray 与 Terraform 搭建集群

续期一年期证书,然后清除并重建

在 TT Lab 中继续学习

目标

手动续期 kubeadm 证书,让控制平面使用新证书,然后打开 kubespray 的自动续期定时器,确认它在什么时候真正会续期。 最后用 reset.yml 清除集群,查看剩下什么,再用同一个 inventory 从头重新搭建。

为什么重要

kubeadm 创建的叶子证书有效期是一年。如果一年之内哪怕升级过一次,kubeadm 也会一并续期,但没有这样做的集群,某一天 组件之间的认证会同时被拒绝。续期并不是替换文件就结束了——读取这个文件的进程也必须已经在使用新证书。 而且有些日子,与其救活一个半坏的集群,不如清除后重新搭建更快。这时必须知道 reset.yml 会删除什么、保留什么, 才能相信“干净的重新安装”这句话。两次安装加一次重置大约要等待 15 分钟,必要时请延长会话。

步骤

  1. 在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,把完整输出保存到 /root/ks/logs/cluster-1.log(约 7 分钟)。PLAY RECAP 中的 node1 必须是 failed=0。
  2. 在 /root/ks/certs/before.json 中写入 apiserver_serial(/etc/kubernetes/ssl/apiserver.crt 的 serial,照 openssl 输出的十六进制原样)、apiserver_not_after(openssl 的 notAfter 字符串原样)、admin_client_serial(/etc/kubernetes/admin.conf 中 client-certificate-data 的 serial)、ca_serial(/etc/kubernetes/ssl/ca.crt 的 serial)、node_uid。
  3. 用 kubeadm certs renew all 续期 kubeadm 证书之后,重新启动 kube-apiserver、kube-controller-manager、kube-scheduler 静态 Pod,使控制平面使用新证书,并把 /etc/kubernetes/admin.conf 复制到 /root/.kube/config。完成后,apiserver.crt 的 serial 必须已经改变,6443 提供的证书必须与该文件相同,并且 controller-manager 和 scheduler 容器必须是在各自的 kubeconfig 被替换之后才启动的。
  4. 把 /root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 中的 auto_renew_certificates 改为 true,用 cluster.yml --tags control-plane 只重新运行那一部分,把完整输出保存到 /root/ks/logs/cp-tags.log。完成后,k8s-certs-renew.timer 必须是 enabled 和 active。
  5. 用 systemctl start k8s-certs-renew.service 立即运行一次续期服务,并用 journalctl -u k8s-certs-renew.service 查看结果。在 /root/ks/certs/timer.json 中写入 oncalendar(定时器的 OnCalendar 值)、renewed(这次运行是否续期了证书,布尔值)、decision_line(说明是否续期的、以 ## 开头的那一行,原样)。
  6. 在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini reset.yml -e reset_confirmation=yes,把完整输出保存到 /root/ks/logs/reset.log(约 1 分半)。然后在 /root/ks/certs/remnants.json 中写入 hostname(当前的主机名)、releases_kept(/tmp/releases 是否保留,布尔值)、left_bins(/usr/local/bin 中剩余的普通文件里,去掉 labhub-agent 之后的名称排序数组——不包括符号链接)。
  7. 用同一个 inventory 再次运行 cluster.yml,把完整输出保存到 /root/ks/logs/cluster-2.log。完成后,node1 必须是 Ready,并且作为新集群的证据,CA serial 和节点 UID 必须与第 2 步的记录不同。

参考

搭建一个要续期并清除的集群

在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,把完整输出保存到 /root/ks/logs/cluster-1.log(约 7 分钟)。PLAY RECAP 中的 node1 必须是 failed=0。

与前面几个模块是同样的安装。请用 systemd-run 或 tmux 启动,使它即使控制台断开也能继续运行,并传入 HOME=/root。

续期之前的 serial

在 /root/ks/certs/before.json 中写入 apiserver_serial(/etc/kubernetes/ssl/apiserver.crt 的 serial,照 openssl 输出的十六进制原样)、apiserver_not_after(openssl 的 notAfter 字符串原样)、admin_client_serial(/etc/kubernetes/admin.conf 中 client-certificate-data 的 serial)、ca_serial(/etc/kubernetes/ssl/ca.crt 的 serial)、node_uid。

serial 由 openssl x509 -noout -serial 以 serial=... 的形式输出。kubeconfig 中的证书是 base64 编码的,需要解码后再交给 openssl。这些值会成为后面判断“是不是真的新证书”“是不是真的新集群”的依据。

续期,并让它使用新证书

用 kubeadm certs renew all 续期 kubeadm 证书之后,重新启动 kube-apiserver、kube-controller-manager、kube-scheduler 静态 Pod,使控制平面使用新证书,并把 /etc/kubernetes/admin.conf 复制到 /root/.kube/config。完成后,apiserver.crt 的 serial 必须已经改变,6443 提供的证书必须与该文件相同,并且 controller-manager 和 scheduler 容器必须是在各自的 kubeconfig 被替换之后才启动的。

kubeadm 在续期结束后会输出“请重启”。静态 Pod 是由 kubelet 启动的,所以删除 Pod 沙箱(crictl pods --name ... -q | xargs crictl rmp -f)之后,kubelet 会根据清单重新启动它们。kubespray 的 /usr/local/bin/k8s-certs-renew.sh 用的也是同样的顺序——请读一读。删除之后的几秒钟内 API 不响应是正常的。

把续期交给日程

把 /root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 中的 auto_renew_certificates 改为 true,用 cluster.yml --tags control-plane 只重新运行那一部分,把完整输出保存到 /root/ks/logs/cp-tags.log。完成后,k8s-certs-renew.timer 必须是 enabled 和 active。

这个开关会让控制平面 role 安装 systemd 定时器和服务。什么时候运行,由 auto_renew_certificates_systemd_calendar 决定,systemctl list-timers 会显示下一次运行的时刻。默认值是每月第一个星期一。

定时器什么时候真正会续期

用 systemctl start k8s-certs-renew.service 立即运行一次续期服务,并用 journalctl -u k8s-certs-renew.service 查看结果。在 /root/ks/certs/timer.json 中写入 oncalendar(定时器的 OnCalendar 值)、renewed(这次运行是否续期了证书,布尔值)、decision_line(说明是否续期的、以 ## 开头的那一行,原样)。

只有当存在先于“下一次定时器时刻加上 7 天余量”的时点到期的证书时,脚本才会续期并重新启动控制平面。刚续期的证书还剩一年,请先预测会怎样,再去确认。脚本正文位于 /usr/local/bin/k8s-certs-renew.sh。

用 reset.yml 清除——会留下什么

在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini reset.yml -e reset_confirmation=yes,把完整输出保存到 /root/ks/logs/reset.log(约 1 分半)。然后在 /root/ks/certs/remnants.json 中写入 hostname(当前的主机名)、releases_kept(/tmp/releases 是否保留,布尔值)、left_bins(/usr/local/bin 中剩余的普通文件里,去掉 labhub-agent 之后的名称排序数组——不包括符号链接)。

reset.yml 是无法撤销的操作,所以要求提供确认变量。它会删除什么,在 roles/reset/tasks/main.yml 的列表中——不在那个列表中的东西会保留。了解剩下的东西,就能判断“清除得很干净”这句话可以相信到什么程度。

从头重新搭建

用同一个 inventory 再次运行 cluster.yml,把完整输出保存到 /root/ks/logs/cluster-2.log。完成后,node1 必须是 Ready,并且作为新集群的证据,CA serial 和节点 UID 必须与第 2 步的记录不同。

reset 会把 /etc/kubernetes 整个删除,所以 CA 也会消失。重新搭建会创建新的 CA,而由旧 CA 签名的旧 kubeconfig 就再也无法使用了。由于下载文件缓存(/tmp/releases)仍在,比首次安装稍快一些。