使用 Ansible 与 kubeadm 一键部署基于 containerd 的 Kubernetes 集群

原创2026-09-12 21:53:001,832 阅读
文章标签:云原生容器运行时运维

使用 Ansible 与 kubeadm 一键部署基于 containerd 的 Kubernetes 集群

本指南以仓库中 contrib/ansible/README.md 为核心,结合其配套的 Ansible 安装器源码(cri-containerd.yaml 及其 tasks 目录下的任务文件),完整讲解如何用 Ansible 批量安装 containerd 与 Kubernetes 组件,并用 kubeadm 初始化、加入节点、最终拉起一个可用于部署应用的 Kubernetes 集群。读完本文,你将掌握 Ansible 安装器的目录结构、Playbook 的完整执行流程、每个任务背后的系统级配置(systemd 服务、内核模块、sysctl、kubelet 参数注入、pause 镜像预拉取),以及 kubeadm 初始化/加入节点的完整操作与输出解读。

一、安装器全貌:contrib/ansible 目录里有什么

仓库中面向 Ansible 部署的完整资源位于 contrib/ansible,其结构如下:

需要特别说明版本背景:当前仓库主线代码已演进到 containerd v2.x(见 version/version.go 中的 Version = "2.4.0-beta+unknown"),而 Ansible 安装器通过 vars/vars.yaml 将 containerd_release_version 锁定为 1.5.5,即安装器实际部署的是通过官方发布包下载的指定版本二进制,而非从本仓库源码现场编译。读者在使用时可按需修改该变量获取其他发布版本。

二、前置条件

根据 contrib/ansible/README.md 的说明,使用该安装器需要满足:

  • OS:Ubuntu 16.04(文档注明其余发行版将在测试后陆续补充;不过从源码看,Playbook 已经内置了 CentOS 分支,见下文);
  • Python:2.7+(Ansible 运行依赖);
  • Ansible:2.4+(在控制机上安装)。

从 cri-containerd.yaml 的源码可以确认,Playbook 通过 when: ansible_distribution == "Ubuntu" 与 when: ansible_distribution == "CentOS" 两个条件分支分别执行 bootstrap_ubuntu.yaml 与 bootstrap_centos.yaml,因此实际可支持 Ubuntu 与 CentOS 两类系统。

三、Step 0:准备 Ansible 控制机

该步骤在本地(或集群中的某一节点)完成三件事:

  1. 安装 Ansible:在将要执行部署的主机上安装 Ansible。该主机可以是集群节点之一,也可以是独立的管理机。
  2. 创建 hosts 文件:把需要被管理的所有节点 IP 写入一个 hosts 文件,每行一个 IP:
$ cat hosts
172.31.7.230
172.31.13.159
172.31.1.227
  1. 配置免密 SSH:从运行 Ansible 的主机到 hosts 文件中的每一台机器,都需要打通基于密钥的免密 SSH 登录,否则 Playbook 无法连接目标主机。

除此之外,若希望进一步定制 Ansible 的默认行为(如默认用户名、默认私钥、SSH 端口等),可以编辑 Ansible 配置文件(如 /etc/ansible/ansible.cfg)来设置默认值,实现更高级的 Ansible 配置管理。

四、Step 1:运行 cri-containerd.yaml Playbook

完成 Step 0 后,Ansible 已能通过 SSH 进入 hosts 文件中的所有机器。此时先获取 containerd 仓库源码,并进入 ansible 目录执行 Playbook:

git clone https://github.com/containerd/containerd
cd ./containerd/contrib/ansible
ansible-playbook -i hosts cri-containerd.yaml

对于典型的云主机登录场景(通常带用户名和私钥文件),可以使用以下形式:

ansible-playbook -i hosts -u <username> --private-key <example.pem> cri-containerd.yaml

Playbook 执行结束后,目标主机上应当已具备拉起 Kubernetes 集群所需的全部软件。文档给出的成功执行示例(PLAY RECAP)如下:

PLAY RECAP ***************************************************************************************************************************************************************
172.31.1.227               : ok=21   changed=7    unreachable=0    failed=0
172.31.13.159              : ok=21   changed=7    unreachable=0    failed=0
172.31.7.230               : ok=21   changed=7    unreachable=0    failed=0

ok=21 表示 21 个任务成功执行,changed=7 表示其中 7 个任务实际改变了系统状态,unreachable=0 与 failed=0 说明三台主机全部可达且无失败任务。

4.1 Playbook 任务编排全解析

从 cri-containerd.yaml 的源码可以看到,该 Playbook 的核心编排逻辑为:

---
- hosts: all
  become: true
  tasks:
    - include_vars: vars/vars.yaml # Contains tasks variables for installer
    - include_tasks: tasks/bootstrap_ubuntu.yaml # Contains tasks bootstrap components for ubuntu systems
      when: ansible_distribution == "Ubuntu"
    - include_tasks: tasks/bootstrap_centos.yaml # Contains tasks bootstrap components for centos systems
      when: ansible_distribution == "CentOS"
    - include_tasks: tasks/k8s.yaml # Contains tasks kubernetes component installation
    - include_tasks: tasks/binaries.yaml # Contains tasks for pulling containerd components

hosts: all 表示对 hosts 文件中的全部主机生效,become: true 表示以提权方式执行(即获得 root 权限)。整个执行流可分为以下几个阶段:

阶段一:系统依赖引导(bootstrap)

Ubuntu 分支(bootstrap_ubuntu.yaml)通过 package 模块安装:

  • unzip、tar:解压 containerd 发布包所需;
  • apt-transport-https:apt 使用 HTTPS 源所需;
  • btrfs-tools:btrfs 快照后端工具;
  • libseccomp2:seccomp 安全隔离依赖;
  • util-linux:通用系统工具。

CentOS 分支(bootstrap_centos.yaml)通过 yum 模块安装的对应包为:unzip、tar、btrfs-progs、libseccomp、util-linux,以及额外的 libselinux-python(供 Ansible 操作 SELinux 使用)。

阶段二:Kubernetes 组件安装(k8s.yaml)

k8s.yaml 按发行版配置软件源并安装 kubelet、kubeadm、kubectl:

  • Ubuntu:导入 apt-key.gpg,添加 deb http://apt.kubernetes.io/ kubernetes-<release> main 源,apt update 后安装三个组件;
  • CentOS:添加 kubernetes-el7-x86_64 的 yum 源(开启 gpgcheck 与 repo_gpgcheck),先 禁用 SELinux(selinux: state=disabled),再通过 yum 安装 kubelet、kubeadm、kubectl。

阶段三:containerd 与 CNI 二进制安装(binaries.yaml)

binaries.yaml 从官方发布地址下载 cri-containerd-cni-{{ containerd_release_version }}-linux-amd64.tar.gz(变量默认 1.5.5,见 vars/vars.yaml),并使用 unarchive 模块配合 remote_src: yes 直接解压到根目录 /(该发布包内已包含 containerd、ctr、crictl 等二进制与配置文件)。随后创建 CNI 目录:

  • /opt/cni/bin/:CNI 插件二进制目录;
  • /etc/cni/net.d/:CNI 网络配置目录。

这两个路径同样由 vars/vars.yaml 中的 cni_bin_dir 与 cni_conf_dir 控制。

阶段四:containerd 运行时与网络内核参数

Playbook 随后执行以下关键系统配置:

  1. 创建 /etc/containerd 配置目录;
  2. 通过 systemd 模块将 containerd 注册为系统服务并立即启动、开机自启(daemon_reload=yes state=started enabled=yes);
  3. modprobe 加载 br_netfilter 内核模块;
  4. sysctl 设置 net.bridge.bridge-nf-call-iptables=1(保证经网桥转发的流量也能被 iptables 规则处理,这是 Pod 网络正常工作的前提);
  5. sysctl 设置 net.ipv4.ip_forward=1(开启 IPv4 转发,容器间与跨节点通信所需)。

阶段五:kubelet 运行时参数注入

Playbook 会先检查 kubelet 配置文件中是否已存在 KUBELET_EXTRA_ARGS(Ubuntu 路径为 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf,CentOS 为 /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf),若不存在则通过 lineinfile 在 [Service] 段后追加:

Environment="KUBELET_EXTRA_ARGS= --runtime-cgroups=/system.slice/containerd.service --container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock"

这些参数的意义:

  • --container-runtime=remote:让 kubelet 使用 CRI 远程运行时模式;
  • --container-runtime-endpoint=unix:///run/containerd/containerd.sock:指定 containerd 的 CRI 套接字地址,这是 kubelet 与 containerd 通信的入口;
  • --runtime-request-timeout=15m:运行时请求超时时间;
  • --runtime-cgroups=/system.slice/containerd.service:将运行时放入 systemd 管理的 cgroup 中。

随后 systemd 模块重新加载并启动 kubelet(daemon_reload=yes state=started enabled=yes)。

阶段六:预拉取 pause 镜像

最后,Playbook 会提前拉取沙箱基础镜像,避免后续创建 Pod 时因并发拉取而出现不稳定(源码注释明确说明这是临时方案,待并发拉取行为一致后移除):

/usr/local/bin/ctr pull registry.k8s.io/pause:3.10.2
/usr/local/bin/crictl --runtime-endpoint unix:///run/containerd/containerd.sock pull registry.k8s.io/pause:3.10.2

五、Step 2:初始化主节点(kubeadm init)

在 Playbook 执行完成后,从任一节点上初始化集群(该节点即成为 master 节点)。若选择第三方网络提供商,可能需要为其设置特定的 --pod-network-cidr 值:

$sudo kubeadm init --skip-preflight-checks

文档给出的完整输出过程(基于 Kubernetes v1.7.6 时代)展示了初始化的关键阶段:

[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters.
[init] Using Kubernetes version: v1.7.6
[init] Using Authorization modes: [Node RBAC]
[preflight] Skipping pre-flight checks
[certificates] Generated CA certificate and key.
[certificates] Generated API server certificate and key.
[certificates] API Server serving cert is signed for DNS names [abhi-k8-ubuntu-1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.31.7.230]
[certificates] Generated API server kubelet client certificate and key.
[certificates] Generated service account token signing key and public key.
[certificates] Generated front-proxy CA certificate and key.
[certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf"
[apiclient] Created API client, waiting for the control plane to become ready
[apiclient] All control plane components are healthy after 42.002391 seconds
[token] Using token: 43a25d.420ff2e06336e4c1
[apiconfig] Created RBAC rules
[addons] Applied essential addon: kube-proxy
[addons] Applied essential addon: kube-dns

从输出中可以读出初始化过程的完整动作:生成 CA 与各类服务证书(存放于 /etc/kubernetes/pki)、生成多个组件的 KubeConfig 文件、等待控制平面组件就绪、生成 join token(示例 43a25d.420ff2e06336e4c1)、创建 RBAC 规则并安装 kube-proxy 与 kube-dns 基础插件。

初始化成功后,文档提示以普通用户使用集群需要执行:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

同时会提示部署 Pod 网络(见 Step 4)以及通过 kubeadm join 加入其他节点(见 Step 3)。

需要说明:文档中的输出记录的是 kubeadm 早期版本(v1.7.x)的行为。现代 kubeadm 已默认执行 preflight 检查、token 默认 24 小时过期、默认安装 kube-proxy 与 CoreDNS,且通常无需 --skip-preflight-checks。具体参数以你实际部署的 kubeadm 版本为准。

六、Step 3:加入工作节点(kubeadm join)

在 master 节点完成初始化后,对其余每个节点执行 join 操作,使用初始化时生成的 token:

$sudo kubeadm join --token 43a25d.420ff2e06336e4c1 172.31.7.230:6443 --skip-preflight-checks

文档给出的完整输出展示了一个节点加入的全过程:

[discovery] Trying to connect to API Server "172.31.7.230:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://172.31.7.230:6443"
[discovery] Cluster info signature and contents are valid, will use API Server "https://172.31.7.230:6443"
[discovery] Successfully established connection with API Server "172.31.7.230:6443"
[bootstrap] Detected server version: v1.7.6
[bootstrap] The server supports the Certificates API (certificates.k8s.io/v1beta1)
[csr] Created API client to obtain unique certificate for this node, generating keys and certificate signing request
[csr] Received signed certificate from the API server, generating KubeConfig...
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"

join 过程的核心机制是:节点先通过 API Server 地址与 token 完成集群发现与信息校验,随后向 master 发起证书签名请求(CSR),拿到由 API Server 签发的证书后生成 kubelet 的 KubeConfig。输出结尾提示:在 master 上执行 kubectl get nodes 即可看到该节点加入。

完成 Step 3 后,一个可用于部署的 Kubernetes 集群便已就绪。

七、Step 4:部署 CNI 网络插件并验证

集群搭建的最后一步是部署 CNI 网络插件(Pod 网络)。在 master 节点上执行:

kubectl apply -f [podnetwork].yaml

其中 [podnetwork].yaml 需根据所选网络方案替换(如 Calico、Flannel、Weave 等),不同方案对 --pod-network-cidr 的要求不同。部署完网络插件后,即可按照对应方案的说明启动一个 demo 应用,验证集群端到端工作正常。

值得一提的是,contrib/ansible/tasks/binaries.yaml 已经为 CNI 预创建了 /opt/cni/bin/ 与 /etc/cni/net.d/ 两个目录,且官方 cri-containerd-cni 发布包自带 CNI 插件,因此网络插件安装的基础设施已提前备好。

八、可调参数与扩展

安装器把关键参数集中放在 contrib/ansible/vars/vars.yaml:

containerd_release_version: 1.5.5   # containerd 发布版本号
cni_bin_dir: /opt/cni/bin/          # CNI 插件二进制目录
cni_conf_dir: /etc/cni/net.d/       # CNI 网络配置目录
  • 更换 containerd 版本:修改 containerd_release_version 后重新运行 Playbook,binaries.yaml 会从官方发布地址下载对应版本的 cri-containerd-cni 包;
  • 自定义 CNI 路径:调整 cni_bin_dir 与 cni_conf_dir 可改变插件与配置的落盘位置;
  • 更细粒度的 Ansible 行为(默认用户名、私钥等):通过 Ansible 配置文件(如 /etc/ansible/ansible.cfg)设置全局默认值。

安装器的维护目标是在更多发行版上得到验证与改进。若在使用中发现问题或希望增强功能,可以参考仓库的贡献规范(CONTRIBUTING.md)提交 issue 或改进建议。

结语

通过 contrib/ansible/README.md 及其配套安装器,你可以在数分钟内完成"控制机准备 → Playbook 批量安装 → kubeadm 初始化 → 节点加入 → CNI 部署"的完整 Kubernetes 集群搭建链路。整个流程的关键工程要点包括:以 cri-containerd-cni 官方发布包统一交付 containerd 与 CNI 插件、通过 KUBELET_EXTRA_ARGS 把 kubelet 无缝切换到 containerd CRI 套接字、提前完成 br_netfilter/ip_forward 等内核网络参数与 pause 镜像预拉取,从而让后续的 kubeadm 初始化与节点加入只需最简单的两条命令即可完成。

登录后查看全文
containerd