cluster.yml 运行两次,仍是同一个集群
目标
用准备好的 inventory 运行 cluster.yml,在一台 VM(4 vCPU · 4 GiB)上搭建 Kubernetes 1.35.8。再把同一个 playbook 多运行一次,
观察什么会再次改变,并修改一个值,用标签只重新应用那一部分。
为什么重要
kubespray 的运维方式是“修改声明,再重新运行同一个 playbook”。无论是增加节点,还是修改配置,运行的都是同一个 cluster.yml。 所以必须知道第二次运行会改变什么——幂等这个词并不意味着 changed 为 0,而要知道每次都会变化的任务是什么, 才能判断“这次运行是不是只改变了想要改变的东西”。你也会在这里学会从末尾往前读长 playbook 日志的方法(PLAY RECAP 和 TASKS RECAP)。 本实验共有两次安装和一次部分运行,总共要等待约 15 分钟。会话是 60 分钟,如果时间不够请延长。VM 结束后,集群也会消失。
步骤
- 在
/opt/ks/kubespray中用ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml --list-tasks查看 play 列表,并在/root/ks/install/plan.json中用数字写入play_count(play 的个数)、etcd_play(“Install etcd” play 的编号)、cni_play(“Invoke kubeadm and install a CNI” 的编号)、apps_play(“Install Kubernetes apps” 的编号)。 - 在
/opt/ks/kubespray中运行ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,并把完整输出保存到/root/ks/logs/cluster-1.log(用| tee或重定向)。大约需要 7 分钟。结束后,PLAY RECAP 中的 node1 必须是failed=0,并且kubectl get node node1必须是 Ready。 - 在
/root/ks/install/run1.json中写入第一次运行的ok、changed、failed(PLAY RECAP 中 node1 的值)、elapsed_sec(TASKS RECAP 标题处显示的累计时间,换算为秒,整数)、slowest_task(TASKS RECAP 列表最上面的任务名称,连同 role 前缀原样)、node_uid(kubectl get node node1的 metadata.uid)。 - 把同一条命令再运行一次,把完整输出保存到
/root/ks/logs/cluster-2.log。第二次也必须是failed=0,并且节点 UID 必须与第 3 步写下的值相同(意味着没有重新创建集群)。 - 把第二次运行中产生
changed: [node1]的任务名称,按日志中TASK [...](handler 是RUNNING HANDLER [...])括号内的原样(包含 role 前缀),每行一个地写入/root/ks/install/changed.txt。然后在/root/ks/install/run2.json中写入第二次运行的ok、changed、failed、elapsed_sec。 - 在
/root/ks/inventory/lab/group_vars/all/containerd.yml中加入containerd_max_container_log_line_size: 32768,用cluster.yml --tags containerd只重新运行容器运行时那一部分,把完整输出保存到/root/ks/logs/containerd.log。结束后,/etc/containerd/config.toml中的max_container_log_line_size必须是 32768,containerd 必须已用新配置重新启动,并且节点必须仍然是 Ready。 - 在
/root/ks/install/report.json中写入kubespray(标签)、server_version(API 服务器的 gitVersion)、first_run_sec、second_run_sec(两次运行的累计时间,整数)、first_changed、second_changed、tags_run_changed(第 6 步运行的 changed)、containerd_restarted(第 6 步是否使 containerd 重新启动了,布尔值)。
参考
- kubespray v2.32.0 位于
/opt/ks/kubespray,inventory 位于/root/ks/inventory/lab/inventory.ini(一台节点,kube_version 1.35.8),均已准备好。playbook 在/opt/ks/kubespray中运行。 - 安装期间下载的文件堆积在
/tmp/releases中,镜像堆积在 containerd 存储中。这就是第二次运行更快的原因。 - 常见错误:看到日志中的
fatal:就判断为失败。带有...ignoring的 fatal 是 kubespray 有意跳过的确认任务。判定要看 PLAY RECAP 的 failed。 - 常见错误:首次安装中途停止后,只重新运行 cluster.yml。如果是在 CNI 之前停住的,第二次运行会在等待控制平面 Ready 时失败。这时要用 reset.yml 清除并从头搭建(第 7 个模块)。
- 文档:Kubespray — Getting started · Kubespray — Ansible tags
运行之前先看顺序
在 /opt/ks/kubespray 中用 ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml --list-tasks 查看 play 列表,并在 /root/ks/install/plan.json 中用数字写入 play_count(play 的个数)、etcd_play(“Install etcd” play 的编号)、cni_play(“Invoke kubeadm and install a CNI” 的编号)、apps_play(“Install Kubernetes apps” 的编号)。
--list-tasks 不会改变任何东西,只是把 playbook 展开显示出来。请看输出中的 play #N (호스트 패턴): 이름 行(占位符依次为主机模式和名称)。想一想 etcd 为什么排在控制平面之前、CNI 为什么排在附加组件之前,之后读取失败位置就会容易得多。
运行 cluster.yml
在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,并把完整输出保存到 /root/ks/logs/cluster-1.log(用 | tee 或重定向)。大约需要 7 分钟。结束后,PLAY RECAP 中的 node1 必须是 failed=0,并且 kubectl get node node1 必须是 Ready。
如果控制台断开,playbook 也可能随之终止。用 systemd-run --unit=<이름> --setenv=HOME=/root ...(占位符为单元名称)或 tmux 启动,它就会与终端无关地运行,并且可以用 tail -f 观察。如果 HOME 为空,kubespray 的 kube 模块找不到 kubeconfig,会去连接 localhost:8080。日志中间带有 ...ignoring 的 fatal 是正常的。
从日志末尾读取的内容
在 /root/ks/install/run1.json 中写入第一次运行的 ok、changed、failed(PLAY RECAP 中 node1 的值)、elapsed_sec(TASKS RECAP 标题处显示的累计时间,换算为秒,整数)、slowest_task(TASKS RECAP 列表最上面的任务名称,连同 role 前缀原样)、node_uid(kubectl get node node1 的 metadata.uid)。
ansible.cfg 打开的 profile_tasks 回调会在日志末尾附加 TASKS RECAP。第一行最后的时间是总累计时间,下面的列表是按耗时长短排列的。节点 UID 会成为下一步确认“重新运行后还是同一个节点吗”的依据。
再运行一次
把同一条命令再运行一次,把完整输出保存到 /root/ks/logs/cluster-2.log。第二次也必须是 failed=0,并且节点 UID 必须与第 3 步写下的值相同(意味着没有重新创建集群)。
kubespray 被设计为可以对已经搭建好的集群重新运行 cluster.yml——增加节点或修改配置时,重新运行同一个 playbook 是基本的运维方法。第二次运行要下载的内容已经在缓存中,所以比第一次快。
幂等,但 changed 不是 0
把第二次运行中产生 changed: [node1] 的任务名称,按日志中 TASK [...](handler 是 RUNNING HANDLER [...])括号内的原样(包含 role 前缀),每行一个地写入 /root/ks/install/changed.txt。然后在 /root/ks/install/run2.json 中写入第二次运行的 ok、changed、failed、elapsed_sec。
幂等(idempotent)指的是“无论运行多少次,结果状态都相同”,而不是“没有任何任务产生 changed”。每次都要执行某些操作的 command 和 shell 任务,或者不比较值而直接重写的任务,都会产生 changed。在日志中,紧挨在 changed: [node1] 那一行上方的最近的 TASK(或 RUNNING HANDLER)标题,就是那个任务。
改一个值,只重新运行那一部分
在 /root/ks/inventory/lab/group_vars/all/containerd.yml 中加入 containerd_max_container_log_line_size: 32768,用 cluster.yml --tags containerd 只重新运行容器运行时那一部分,把完整输出保存到 /root/ks/logs/containerd.log。结束后,/etc/containerd/config.toml 中的 max_container_log_line_size 必须是 32768,containerd 必须已用新配置重新启动,并且节点必须仍然是 Ready。
给出标签之后,只有带这个标签的任务(以及 always 标签的准备任务)会运行。有哪些标签,请查看 kubespray 文档的标签表或用 --list-tags。如果只是配置文件变了而守护进程没有重新启动,它就会继续以旧值运行——重启由 role 的 handler 负责。正如文档所警告的,只有在确切知道会运行什么时才使用标签。
安装报告
在 /root/ks/install/report.json 中写入 kubespray(标签)、server_version(API 服务器的 gitVersion)、first_run_sec、second_run_sec(两次运行的累计时间,整数)、first_changed、second_changed、tags_run_changed(第 6 步运行的 changed)、containerd_restarted(第 6 步是否使 containerd 重新启动了,布尔值)。
这些值都可以根据前面步骤的记录、三份日志以及当前的集群重新计算。评分器也会从同样的地方重新计算并核对。containerd 是否重新启动了,可以根据 containerd.log 中重启 handler 是否以 changed 输出来判断。