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

用 Kubespray 与 Terraform 搭建集群

离线安装拼的是清单 — 在外网确定 Kubespray 要下载的东西

在 TT Lab 中继续学习

一句话总结

kubespray 的隔离网络安装,就是“生成要下载内容的清单 → 在内部按相同路径搭建好 → 通过 inventory 变量只替换地址”,本模块涵盖其中的清单和变量部分。

为什么需要它

kubespray 在安装过程中会从互联网下载相当多的东西。在本课程的实测安装中,也下载了 github.com release(containerd、runc、etcd、CNI 插件、calicoctl)、dl.k8s.io(kubeadm、kubelet、kubectl)、registry.k8s.io、quay.io、docker.io 的镜像,以及 Ubuntu apt 仓库的软件包。金融、公共机构、制造业现场的服务器,这些地方一个也连不上。因此,kubespray 文档的隔离网络一节把需要提前带进去的东西分为五类——静态文件(二进制文件、压缩包)、操作系统软件包、容器镜像,以及可选的 Python 软件包和 Helm Chart。并且对应地写明了需要在内部搭建的东西——文件用的 HTTP 镜像站、内部的 deb 和 rpm 仓库、内部容器注册表,以及可选的 PyPI 和 Helm 仓库。

工作原理

清单由工具生成。 contrib/offline/generate_list.sh 从 download.yml 中提取 *_download_url 以及镜像的 repo 和 tag 来生成模板,再用一个小 playbook(generate_list.yml)把变量填入该模板,输出 temp/files.list 和 temp/images.list。在这台 VM 上实测,3.6 秒就得到 24 行文件和 48 行镜像。其中也包括没有启用的 CNI(cilium、flannel 等)和附加组件的内容,所以比实际安装所用的更宽松——为了一次就完成导入审查,宽松一些更好。镜像的来源是 quay.io 18 个、registry.k8s.io 18 个、docker.io 10 个、ghcr.io 2 个。

陷阱:清单 playbook 在 localhost 上运行。 README 要求把版本变量写在 inventory 或 group_vars 中,并通过 -i 传入。然而 generate_list.yml 的目标是 hosts: localhost,而 localhost 不属于 inventory 的任何组,只会得到 all 的 group_vars。如果像本课程这样把 kube_version 写在 group_vars/k8s_cluster 中(这是 kubespray 示例放置它的位置),清单 playbook 就看不到这个值,会按默认值生成清单。实测中,inventory 是 1.35.8,而清单却是 1.36.4,而且既没有错误也没有警告。必须给出 -e kube_version=1.35.8,或者把版本放在 group_vars/all 中才正确。

地址通过变量来替换。 示例的 group_vars/all/offline.yml 以及文档所展示的变量分为两支。

이미지   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 }}/<원래 도메인>"
노드     containerd_registries_mirrors(containerd 2) · containerd_registry_auth(1.7)                 → 사내 레지스트리를 믿게
OS 패키지 ubuntu_repo · debian_repo · yum_repo                                                         → 사내 저장소

该代码块中的韩文说明依次为:镜像方面,kube_image_repo、gcr_image_repo、docker_image_repo、quay_image_repo、github_image_repo 都指向注册表主机;文件方面,github_url、dl_k8s_io_url、storage_googleapis_url、get_helm_url 都指向 files_repo 下以原域名为目录的路径(其中原域名是占位符);节点方面,用 containerd_registries_mirrors(containerd 2)或 containerd_registry_auth(1.7)让节点信任内部注册表;操作系统软件包方面,ubuntu_repo、debian_repo、yum_repo 指向内部仓库。

对于镜像,只改变注册表地址,路径(coredns/coredns:v…)保持不变。文件也是一样,按照文档的提示,把原来的域名作为第一级目录(files_repo/dl.k8s.io/release/…),就能把原始 URL 机械地转换为镜像站 URL。把这些变量放在 all 中的原因是,只负责 etcd 的节点也需要下载,而且上面的清单 playbook 也需要读取它们。实测中,用放在 all 中的离线变量,清单的 72 行一行不漏地全部被替换成了内部地址。

控制节点也是导入对象。 kubespray v2.32.0 要求 ansible==12.3.0 以及若干个 Python 软件包,并且必须是确切的版本。要在隔离网络的控制节点上执行 pip install -r requirements.txt,就必须提前下载好 wheel,并且下载所在的环境与要安装的环境,Python 版本和架构必须相同。可以在外部先用 pip install --dry-run --no-index --find-links 确认没有互联网时能否解析。

在现场相遇的样子

隔离网络的导入通常是“提交清单 → 审查 → 导入 → 安装”的顺序,如果清单有误,整个日程就会推迟一轮。最常见的三个错误是:版本不同的清单(上面的陷阱)、漏掉一个镜像地址的离线变量(想把那一个镜像从原来的域名下载而停住)、以及忘记控制节点的 Ansible。本模块的实验就是按在外部提前确认这三者的顺序来设计的。

实际搭建内部注册表并把清单中的镜像搬进去(manage-offline-container-images.sh),用 nginx 发布文件镜像站(manage-offline-files.sh),并在断开互联网的节点上把安装一直运行到结束,这些将在专门讲隔离网络的课程中继续。在这里生成的清单、映射表、Python 包,就是那门课程的输入。

下一项实验要做什么

用 generate_list.sh 生成默认清单,并按来源统计。确认传入 inventory 时与用 -e 传入版本时,清单中的版本有何不同。在 offline.yml 中填入内部镜像站地址,查看清单是否全部指向内部,并制作原始地址与镜像站地址的映射表。加入让节点使用内部注册表的 containerd 配置,最后确认连同 Ansible 一起打包的 Python 包能否在没有互联网的情况下解析。