带入离线环境的清单 — 文件、镜像与 Python
目标
生成 kubespray 在安装过程中所下载的文件和镜像的清单,并通过 inventory 的离线变量,让这份清单指向内部镜像站 (registry.lab.internal:5000 和 http://files.lab.internal)。 制作交给负责填充镜像站的人的映射表,以及连同控制节点的 Ansible 在内的导入包。不会真正搭建隔离网络和镜像站。
为什么重要
隔离网络安装的失败,大多是因为“漏掉了东西”。经过导入审查带进去之后才发现少了一个文件,就得再出去一趟,这一来一回就是几天。 所以必须让安装工具自己说出它要下载什么(generate_list.sh),并且在身处外部的时候,确认这份清单是否真的是这次要安装的版本、 所有地址是否都指向了内部。本模块遇到的清单版本陷阱,是制作本课程时实际遇到的——inventory 里写了版本,清单却生成了另一个版本。
步骤
- 在
/opt/ks/kubespray/contrib/offline中不带参数运行./generate_list.sh,并把生成的temp/files.list和temp/images.list复制到/root/ks/offline/default/。在/root/ks/offline/default/count.json中写入files、images(两份清单的行数)以及registries(images.list 中按第一个路径片段统计的数量,例如 {"quay.io": 3})。 - inventory 的 kube_version 是 1.35.8。用
./generate_list.sh -i /root/ks/inventory/lab/inventory.ini运行一次,再加上-e kube_version=1.35.8运行一次,分别确认 images.list 中 kube-apiserver 的标签。在/root/ks/offline/trap.json中写入with_inventory(第一次运行的 kube-apiserver 标签)、with_extra_var(第二次运行的标签)、ignored_group(写有 inventory 中 kube_version 的 group_vars 组里,没有应用到清单 playbook 的那个组的名称)。 - 修改
/root/ks/inventory/lab/group_vars/all/offline.yml,设置registry_host: "registry.lab.internal:5000"、files_repo: "http://files.lab.internal",并按照 kubespray 文档的隔离网络一节,把kube_image_repo、gcr_image_repo、docker_image_repo、quay_image_repo、github_image_repo设为{{ registry_host }},把github_url、dl_k8s_io_url、storage_googleapis_url、get_helm_url设为{{ files_repo }}/<원래 도메인>(占位符为原始域名)。这个文件必须位于 group_vars/all 中。 - 用
./generate_list.sh -i /root/ks/inventory/lab/inventory.ini -e kube_version=1.35.8重新生成清单,并把两个文件复制到/root/ks/offline/mirror/。files.list 的每一行都必须以http://files.lab.internal/开头,images.list 的每一行都必须以registry.lab.internal:5000/开头,并且行数必须与第 1 步相同。 - 制作交给负责填充镜像站的人的映射表。把没有应用离线变量的 1.35.8 原始清单与第 4 步的镜像站清单按行配对,在
/root/ks/offline/image-map.tsv中每行写一条원본<TAB>미러(依次为原始地址、制表符和镜像站地址)(images.list 中的所有镜像)。 - 在
/root/ks/inventory/lab/group_vars/all/offline.yml中加入containerd_registries_mirrors,让 prefixregistry.lab.internal:5000把 hosthttp://registry.lab.internal:5000用于 pull 和 resolve,并跳过 TLS 验证(skip_verify: true)。ansible-inventory --host node1必须原样解析出这份列表。 - 用 kubespray 的
requirements.txt把 Python 软件包下载到/root/ks/offline/pypi/(pip download),并用pip install --dry-run --no-index --find-links /root/ks/offline/pypi -r requirements.txt确认不使用互联网的安装仅凭该目录就能解析。在/root/ks/offline/pypi.json中写入wheels(下载的文件数)、resolved(dry-run 是否成功,布尔值)。
参考
- kubespray v2.32.0 位于
/opt/ks/kubespray,inventory 位于/root/ks/inventory/lab/inventory.ini(kube_version 1.35.8),均已准备好。这台 VM 可以访问互联网(80/443),所以第 7 步的下载可以进行。 - generate_list.sh 会覆盖
/opt/ks/kubespray/contrib/offline/temp/中的结果。请在每一步都把需要的文件复制保存下来。 - 常见错误:生成清单时只给
-i,而不检查版本是否正确。 - 常见错误:把离线变量放在 group_vars/k8s_cluster 中。只负责 etcd 的节点和清单 playbook 得不到这些值。
- 文档:Kubespray — Offline environment · Kubespray — contrib/offline
先从要下载什么的清单开始
在 /opt/ks/kubespray/contrib/offline 中不带参数运行 ./generate_list.sh,并把生成的 temp/files.list 和 temp/images.list 复制到 /root/ks/offline/default/。在 /root/ks/offline/default/count.json 中写入 files、images(两份清单的行数)以及 registries(images.list 中按第一个路径片段统计的数量,例如 {"quay.io": 3})。
generate_list.sh 从 roles/kubespray_defaults/defaults/main/download.yml 中提取 download_url 以及镜像的 repo 和 tag 来生成模板,再用一个小 playbook 填入变量。其中也包括没有启用的 CNI 和附加组件的内容,所以比实际安装更宽松。镜像清单的第一个片段,就是需要做镜像的原始注册表。
清单悄悄地生成了另一个版本
inventory 的 kube_version 是 1.35.8。用 ./generate_list.sh -i /root/ks/inventory/lab/inventory.ini 运行一次,再加上 -e kube_version=1.35.8 运行一次,分别确认 images.list 中 kube-apiserver 的标签。在 /root/ks/offline/trap.json 中写入 with_inventory(第一次运行的 kube-apiserver 标签)、with_extra_var(第二次运行的标签)、ignored_group(写有 inventory 中 kube_version 的 group_vars 组里,没有应用到清单 playbook 的那个组的名称)。
generate_list.yml 是以 hosts: localhost 运行的。localhost 不在 inventory 的任何组中,所以只会得到 all 的 group_vars。如果清单生成了错误的版本,用导入的文件安装,一开始就会因为“文件不存在”而停住——而且是在隔离网络的现场。
让 inventory 指向内部镜像站
修改 /root/ks/inventory/lab/group_vars/all/offline.yml,设置 registry_host: "registry.lab.internal:5000"、files_repo: "http://files.lab.internal",并按照 kubespray 文档的隔离网络一节,把 kube_image_repo、gcr_image_repo、docker_image_repo、quay_image_repo、github_image_repo 设为 {{ registry_host }},把 github_url、dl_k8s_io_url、storage_googleapis_url、get_helm_url 设为 {{ files_repo }}/<원래 도메인>(占位符为原始域名)。这个文件必须位于 group_vars/all 中。
按照文档的提示,在 files_repo 之下把原来的域名作为第一级目录(files_repo/github.com/...),填充镜像站时就能机械地转换 URL。把变量放在 all 中有两个原因——只有 etcd 的节点也需要下载,而且清单 playbook(localhost)也必须读取这个值。
清单是否全部变成了内部地址
用 ./generate_list.sh -i /root/ks/inventory/lab/inventory.ini -e kube_version=1.35.8 重新生成清单,并把两个文件复制到 /root/ks/offline/mirror/。files.list 的每一行都必须以 http://files.lab.internal/ 开头,images.list 的每一行都必须以 registry.lab.internal:5000/ 开头,并且行数必须与第 1 步相同。
只要还有一行保留着原来的域名,那个文件或镜像在隔离网络中就无法下载。如果有剩余的行,那一行的域名会告诉你缺少了哪个变量。
原始地址与镜像站地址的配对
制作交给负责填充镜像站的人的映射表。把没有应用离线变量的 1.35.8 原始清单与第 4 步的镜像站清单按行配对,在 /root/ks/offline/image-map.tsv 中每行写一条 원본<TAB>미러(依次为原始地址、制表符和镜像站地址)(images.list 中的所有镜像)。
离线变量在 group_vars/all 中,所以原始清单不使用 inventory,只给出 -e kube_version=... 来生成。两份清单出自同一个模板,顺序相同。只改变注册表地址而路径保持不变,这一点是镜像站设计的关键——如果改变镜像站一侧的路径,这种对应就会被破坏。
让节点信任内部注册表
在 /root/ks/inventory/lab/group_vars/all/offline.yml 中加入 containerd_registries_mirrors,让 prefix registry.lab.internal:5000 把 host http://registry.lab.internal:5000 用于 pull 和 resolve,并跳过 TLS 验证(skip_verify: true)。ansible-inventory --host node1 必须原样解析出这份列表。
kubespray 文档写道,containerd 2 与 1.7 的配置方法不同。在 2 中,containerd_registries_mirrors 会变成 /etc/containerd/certs.d//hosts.toml。因为是实验用途,所以关闭了 TLS,但在生产中,原则是使用由内部 CA 签名的证书,并且不要开启 skip_verify。
Ansible 也必须导入
用 kubespray 的 requirements.txt 把 Python 软件包下载到 /root/ks/offline/pypi/(pip download),并用 pip install --dry-run --no-index --find-links /root/ks/offline/pypi -r requirements.txt 确认不使用互联网的安装仅凭该目录就能解析。在 /root/ks/offline/pypi.json 中写入 wheels(下载的文件数)、resolved(dry-run 是否成功,布尔值)。
在隔离网络中,控制节点的 Ansible 也必须带进去。kubespray 文档把 Python 软件包写为“可选”,指的是操作系统提供相同版本的情况,而这个版本要求 ansible==12.3.0 这样确切的版本,所以通常必须自己带进去。下载时和安装时,Python 版本和 CPU 架构必须相同——wheel 文件名中写明了这些。