一份 inventory 决定集群的形状
目标
用 kubespray v2.32.0 的示例 inventory 设计一个单节点集群的 inventory,把版本固定在 group_vars 中, 并亲自确认变量在哪一层胜出,以及组名写错时什么会坏掉。集群暂时还不搭建。
为什么重要
用 kubespray 搭建集群时,人需要亲手编写的,实际上只有 inventory 和 group_vars。playbook 保持原样, 只修改这两样,就能决定集群的形态(谁是控制平面、谁是 etcd)和内容(哪个版本、哪个 CNI、哪个运行时)。 所以安装出问题的原因,往往也在这里——组名写错一个,安装一分钟就会以莫名其妙的错误停住, 如果不写版本,同一个 inventory 在每次升级 kubespray 时都会安装不同的 Kubernetes。本模块的目标,是养成在运行漫长的安装之前, 先用 inventory 工具确认解析出的值的习惯。
步骤
- 把
/opt/ks/kubespray/inventory/sample整个复制到/root/ks/inventory/lab。group_vars/all/all.yml和group_vars/k8s_cluster/k8s-cluster.yml必须位于其下。 - 在
/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。 - 在
/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 的那一个,带点的字符串)。 - 在
/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这六项。 - 在
/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 的那一行。 /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 组名)。- 在
/opt/ks/kubespray中运行ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml,把完整输出保存到/root/ks/logs/boilerplate.log。PLAY RECAP 中必须是failed=0。 - 在
/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(这个版本所接受的最低版本)。
参考
- VM 中 kubespray v2.32.0 位于
/opt/ks/kubespray,Ansible 位于/opt/ks/venv虚拟环境。ansible、ansible-playbook、ansible-inventory已链接到 PATH 中。 - playbook 和 inventory 工具要在
/opt/ks/kubespray中运行。该目录的ansible.cfg会告知 roles 和 library 的路径。 - 常见错误:像
-i /root/ks/inventory/lab这样传入目录。在这个仓库的配置下,inventory.ini 会被忽略。 - 常见错误:当
cp -r的目标已经存在时,会多复制深一层。 - 文档:Kubespray — Inventory · Kubespray — Ansible 变量层级 · Ansible — 变量优先级
把示例 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)。这意味着没有校验和的版本无法安装。