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

用 Kubespray 与 Terraform 搭建集群

一份 inventory 决定集群的形状

在 TT Lab 中继续学习

目标

用 kubespray v2.32.0 的示例 inventory 设计一个单节点集群的 inventory,把版本固定在 group_vars 中, 并亲自确认变量在哪一层胜出,以及组名写错时什么会坏掉。集群暂时还不搭建。

为什么重要

用 kubespray 搭建集群时,人需要亲手编写的,实际上只有 inventory 和 group_vars。playbook 保持原样, 只修改这两样,就能决定集群的形态(谁是控制平面、谁是 etcd)和内容(哪个版本、哪个 CNI、哪个运行时)。 所以安装出问题的原因,往往也在这里——组名写错一个,安装一分钟就会以莫名其妙的错误停住, 如果不写版本,同一个 inventory 在每次升级 kubespray 时都会安装不同的 Kubernetes。本模块的目标,是养成在运行漫长的安装之前, 先用 inventory 工具确认解析出的值的习惯。

步骤

  1. 把 /opt/ks/kubespray/inventory/sample 整个复制到 /root/ks/inventory/lab。group_vars/all/all.yml 和 group_vars/k8s_cluster/k8s-cluster.yml 必须位于其下。
  2. 在 /root/ks/inventory/lab/inventory.ini 中,把节点 node1 放入 kube_control_plane 和 kube_node 组,让 etcd 以 kube_control_plane 为子组([etcd:children])。同样让 k8s_cluster 也以 kube_control_plane 和 kube_node 为子组([k8s_cluster:children])。连接方式不写在 inventory 行中,而是在 /root/ks/inventory/lab/host_vars/node1.yml 中设置 ansible_connection: local。inventory.ini 中不能有 ansible_connection。
  3. 在 /opt/ks/kubespray 中运行两次 ansible-inventory --list 来统计解析出的主机数,并在 /root/ks/parse.json 中写入 dir_hosts(用 -i /root/ks/inventory/lab 传入目录时)、file_hosts(-i /root/ks/inventory/lab/inventory.ini)、ignored_ext(kubespray 的 ansible.cfg 在 inventory 目录中跳过的扩展名里,会遮住 inventory.ini 的那一个,带点的字符串)。
  4. 在 /root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 中加入 kube_version: 1.35.8(示例中没有)。然后用 ansible-inventory --host node1 读取实际解析出的值,在 /root/ks/vars.json 中以字符串形式写入 kube_version、container_manager、kube_network_plugin、kube_proxy_mode、kube_service_addresses、kube_pods_subnet 这六项。
  5. 在 /root/ks/inventory/lab/group_vars/all/all.yml 末尾暂时加入 kube_version: 1.34.11,然后用 ansible -i /root/ks/inventory/lab/inventory.ini node1 -m debug -a var=kube_version 查看实际值,再在同一条命令上加上 -e kube_version=1.36.4 查看一次。在 /root/ks/precedence.json 中写入 all_yml(写入 all.yml 的值)、effective(不带 -e 时胜出的值)、extra_vars(给出 -e 时的值)、winner_file(写有不带 -e 时胜出值的文件,相对于 inventory 的相对路径),然后删除写入 all.yml 的那一行。
  6. /root/ks/broken/inventory.ini 是有人写成 [masters] 的 inventory。不要修改它,在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/broken/inventory.ini playbooks/boilerplate.yml。在 /root/ks/broken.json 中写入 failed_task(失败的任务名称,不带 role 前缀)、node1_groups(在这个 inventory 中 node1 所属的组名排序后的数组,不含 all 和 ungrouped)、missing_group(本不该为空却为空的 kubespray 组名)。
  7. 在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml,把完整输出保存到 /root/ks/logs/boilerplate.log。PLAY RECAP 中必须是 failed=0。
  8. 在 /root/ks/report.json 中写入 kubespray_tag(git -C /opt/ks/kubespray describe --tags)、ansible_core(ansible --version 第一行的版本号,例如 2.19.0)、kube_version_default(这个版本的默认 kube_version)、kube_version_min(这个版本所接受的最低版本)。

参考

把示例 inventory 复制到自己的位置

把 /opt/ks/kubespray/inventory/sample 整个复制到 /root/ks/inventory/lab。group_vars/all/all.yml 和 group_vars/k8s_cluster/k8s-cluster.yml 必须位于其下。

kubespray 会读取 inventory 目录旁边的 group_vars。之所以复制示例而不是直接修改,是因为升级到下一个版本时示例会发生变化。如果目标目录已经存在,cp -r 会在其中再多创建一个名为 sample 的子目录。

把一台节点放进三个组

在 /root/ks/inventory/lab/inventory.ini 中,把节点 node1 放入 kube_control_plane 和 kube_node 组,让 etcd 以 kube_control_plane 为子组([etcd:children])。同样让 k8s_cluster 也以 kube_control_plane 和 kube_node 为子组([k8s_cluster:children])。连接方式不写在 inventory 行中,而是在 /root/ks/inventory/lab/host_vars/node1.yml 中设置 ansible_connection: local。inventory.ini 中不能有 ansible_connection。

这台 VM 既是控制节点,也是目标节点,所以使用 local 连接而不是 ssh。把这个事实放在 host_vars 中,这样节点增加时,在 inventory 中只需要加上名称,连接方式在各节点的文件中修改即可。组名必须与 kubespray 规定的拼写完全一致。示例 inventory.ini 中没有 k8s_cluster——因为 kubespray 是在 playbook 内部创建它,而这样一来,playbook 之外的工具(ansible-inventory、ansible ad-hoc)就读取不到 group_vars/k8s_cluster。

传入目录时主机数为 0

在 /opt/ks/kubespray 中运行两次 ansible-inventory --list 来统计解析出的主机数,并在 /root/ks/parse.json 中写入 dir_hosts(用 -i /root/ks/inventory/lab 传入目录时)、file_hosts(-i /root/ks/inventory/lab/inventory.ini)、ignored_ext(kubespray 的 ansible.cfg 在 inventory 目录中跳过的扩展名里,会遮住 inventory.ini 的那一个,带点的字符串)。

主机数可以通过 --list 结果中 _meta.hostvars 的键的个数来统计。ansible-inventory 读取哪个配置文件,可以用 ansible-config dump --only-changed 查看,而那个文件是在当前目录中查找的。

把版本固定在 group_vars 中

在 /root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 中加入 kube_version: 1.35.8(示例中没有)。然后用 ansible-inventory --host node1 读取实际解析出的值,在 /root/ks/vars.json 中以字符串形式写入 kube_version、container_manager、kube_network_plugin、kube_proxy_mode、kube_service_addresses、kube_pods_subnet 这六项。

如果不写 kube_version,默认值会随 kubespray 版本而变,同一个 inventory 在不同的日子就会安装不同的 Kubernetes。文件中写的值与 Ansible 实际解析出的值是否相同,要用 inventory 工具来确认。在 YAML 中,像 1.35 这样只有一个点的数字会被当作浮点数读取,而三段式的版本号是字符串。

同一个变量出现在三处时

在 /root/ks/inventory/lab/group_vars/all/all.yml 末尾暂时加入 kube_version: 1.34.11,然后用 ansible -i /root/ks/inventory/lab/inventory.ini node1 -m debug -a var=kube_version 查看实际值,再在同一条命令上加上 -e kube_version=1.36.4 查看一次。在 /root/ks/precedence.json 中写入 all_yml(写入 all.yml 的值)、effective(不带 -e 时胜出的值)、extra_vars(给出 -e 时的值)、winner_file(写有不带 -e 时胜出值的文件,相对于 inventory 的相对路径),然后删除写入 all.yml 的那一行。

在 Ansible 中,更具体的组的 group_vars 会胜过 all。k8s_cluster 是 all 的子组。用 -e 给出的 extra vars 胜过一切——所以 kubespray 文档要求把 -e 限定在“覆盖内部变量”的场合。请在 kubespray 目录中运行这些命令。

组名写错会坏掉什么

/root/ks/broken/inventory.ini 是有人写成 [masters] 的 inventory。不要修改它,在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/broken/inventory.ini playbooks/boilerplate.yml。在 /root/ks/broken.json 中写入 failed_task(失败的任务名称,不带 role 前缀)、node1_groups(在这个 inventory 中 node1 所属的组名排序后的数组,不含 all 和 ungrouped)、missing_group(本不该为空却为空的 kubespray 组名)。

错误信息不会告诉你组名写错了。请读一读失败的条件表达式是在查找哪个组时失败的。旧名称 kube-master 会被 kubespray 自动迁移,但 masters 不会。节点所属的组(包括经由子组的)可以用 ansible ... -m debug -a var=group_names 查看。

我的 inventory 通过了检查

在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml,把完整输出保存到 /root/ks/logs/boilerplate.log。PLAY RECAP 中必须是 failed=0。

boilerplate.yml 是 cluster.yml、upgrade-cluster.yml、reset.yml 都在最前面调用的一组检查。在这里被挡住,就是在安装开始之前被挡住,所以如果在安装前单独运行一遍,就能避免在运行漫长的 playbook 时一分钟就停住。

这个版本的 kubespray 所接受的范围

在 /root/ks/report.json 中写入 kubespray_tag(git -C /opt/ks/kubespray describe --tags)、ansible_core(ansible --version 第一行的版本号,例如 2.19.0)、kube_version_default(这个版本的默认 kube_version)、kube_version_min(这个版本所接受的最低版本)。

kubespray 没有单独写下默认版本和最低版本,而是从 roles/kubespray_defaults/vars/main/checksums.yml 中 kubelet 校验和列表的第一个键和最后一个键计算得出(roles/kubespray_defaults/defaults/main/main.yml)。这意味着没有校验和的版本无法安装。