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

用 Kubespray 与 Terraform 搭建集群

cluster.yml 运行两次,仍是同一个集群

在 TT Lab 中继续学习

目标

用准备好的 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 结束后,集群也会消失。

步骤

  1. 在 /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” 的编号)。
  2. 在 /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。
  3. 在 /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)。
  4. 把同一条命令再运行一次,把完整输出保存到 /root/ks/logs/cluster-2.log。第二次也必须是 failed=0,并且节点 UID 必须与第 3 步写下的值相同(意味着没有重新创建集群)。
  5. 把第二次运行中产生 changed: [node1] 的任务名称,按日志中 TASK [...](handler 是 RUNNING HANDLER [...])括号内的原样(包含 role 前缀),每行一个地写入 /root/ks/install/changed.txt。然后在 /root/ks/install/run2.json 中写入第二次运行的 ok、changed、failed、elapsed_sec。
  6. 在 /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。
  7. 在 /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 重新启动了,布尔值)。

参考

运行之前先看顺序

在 /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 输出来判断。