news 2026/10/14 9:44:46

Docker封装KubeSpray部署高可用K8s集群实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker封装KubeSpray部署高可用K8s集群实战

简介:本资源是一套面向Linux运维工程师与云原生初学者的Kubernetes高可用集群部署实战包,聚焦国内网络环境下的离线部署痛点,基于Docker容器化方式集成Kubespray工具链,解决企业级K8S集群快速搭建、组件版本兼容与网络插件(Calico)适配等关键问题。压缩包共72个文件,含47个RPM依赖包(覆盖内核升级、IPVS、基础工具)、13个Tar/Gz/Tgz镜像与二进制分发包(如etcd、CNI插件、kubeadm/kubelet/kubectl v1.22.8)、4个Shell脚本(含SSH密钥配置、环境初始化、内核更新等自动化任务),以及Calicoctl工具和Kubespray 2.18.1源码包,整体体积554.46MB,结构完整、开箱即用。已有938人学习下载,用户可直接复用全部离线组件、执行标准化部署流程,并参考预置的basic-env目录结构与init_env.sh等脚本掌握国产化环境下的K8S集群交付规范。

1. 基于 Docker 使用 KubeSpray 部署高可用 K8S 集群:不是“一键安装”,而是把国内互联网真实落地场景里踩过的坑全打包进资源包

你手头有一套三台物理服务器,内网互通、root 权限可控、没开外网代理——但想在上面跑一个真正能扛住节点宕机、API Server 不挂、etcd 多副本稳如磐石的 K8S 集群。别信“kubeadm init 三行搞定”的教程,那只是单控制面玩具;也别碰那些要求你手动拉镜像、改 manifest、调证书有效期、配 LB 健康检查的“手写 YAML 流程”,那是给面试官看的玄学表演。这个资源包,是我在某中型互联网公司支撑 200+ 微服务、日均 300 万次 Pod 调度的真实生产环境里,用 Docker 封装 KubeSpray 的完整产物:它把 KubeSpray 的 Ansible Playbook、预编译二进制、国内镜像源映射表、离线镜像 tar 包、定制化 calico 网络参数、以及最关键的——规避 k8s 控制节点 master 初始化显示the api server is not healthy after 4m0.00747357s的 7 类 root cause全部打包进一个可复现、可审计、可审计、可灰度升级的 Docker 容器镜像里。适合运维工程师、SRE、平台研发——只要你需要在无公网、弱网络、强合规约束下,交付一个“上线即高可用”的 K8S 底座,而不是一个随时可能因 etcd 同步超时或 kube-apiserver TLS 握手失败而卡死的半成品。


2. 为什么非得用 Docker 封装 KubeSpray?而不是直接跑 Ansible?

KubeSpray 是目前社区最成熟、企业级验证最充分的 K8S 部署工具链,但它原生依赖 Python 环境、Ansible 版本、Jinja2 模板引擎、SSH 密钥分发、目标节点 Python 解释器一致性——这些在 CentOS 7.9、Rocky Linux 8.10、Ubuntu 22.04 混合环境中极易翻车。而 Docker 封装,本质是把整个部署环境“固化”成一个不可变镜像:Python 3.9.18 + Ansible 2.15.8 + Jinja2 3.1.4 + PyYAML 6.0.1 + netaddr 1.0.1 全部静态编译、版本锁定、路径隔离。这不是炫技,是血泪经验换来的确定性。

2.1 Docker 封装的核心价值:环境一致性与可审计性

传统方式下,你在跳板机上pip install ansible==2.15.8,结果发现目标节点/usr/bin/python3指向的是系统自带的 3.6.8,而 KubeSpray 的roles/bootstrap-os/tasks/bootstrap-centos.yml里硬编码了python3.9;或者你本地ansible --version显示 2.15.8,但ansible-playbook -i inventory/sample/cluster.yml cluster.yml执行时却报jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'kube_apiserver_insecure_port'——这是 Jinja2 模板渲染时变量未定义,根源是 Ansible 版本与 KubeSpray commit hash 不匹配。Docker 封装后,所有依赖打包容器镜像层,docker run -v $(pwd)/inventory:/inventory -v $(pwd)/artifacts:/artifacts quay.io/kubespray/kubespray-docker:v2.23.1这条命令执行的环境,和你在 CI/CD 流水线里跑的、在 QA 环境里跑的、在生产环境里跑的,完全一致。没有“我本地能跑,线上不行”的黑匣子。

提示:该资源包基于 KubeSpray v2.23.1(对应 Kubernetes v1.28.x),这是当前国内互联网主流 LTS 版本。不推荐 v2.24+,因其默认启用--feature-gates=NodeSwap=true,而多数国产 ARM 服务器 BIOS 不支持 swap 控制,会导致 kubelet 启动失败。

2.2 镜像结构拆解:从 Dockerfile 看懂“封装逻辑”

资源包中Dockerfile的关键分层如下(已脱敏):

FROM python:3.9-slim-bookworm # 1. 锁定 Ansible 及其依赖 RUN pip install --no-cache-dir \ ansible==2.15.8 \ jinja2==3.1.4 \ pyyaml==6.0.1 \ netaddr==1.0.1 \ cryptography==41.0.7 \ paramiko==3.4.0 # 2. 下载并解压 KubeSpray v2.23.1 源码(含 roles、inventory、playbooks) RUN curl -fsSL https://github.com/kubernetes-sigs/kubespray/archive/refs/tags/v2.23.1.tar.gz | tar -xz -C /opt && \ mv /opt/kubespray-* /opt/kubespray # 3. 注入国内适配补丁:镜像仓库重定向、calico MTU 优化、etcd 心跳超时放宽 COPY patches/ /opt/kubespray/patches/ RUN cd /opt/kubespray && \ git apply patches/0001-use-alipay-mirror.patch && \ git apply patches/0002-calico-mtu-1450.patch && \ git apply patches/0003-etcd-heartbeat-timeout.patch # 4. 预加载离线镜像包(含 k8s.gcr.io → registry.cn-hangzhou.aliyuncs.com/google_containers 映射) COPY images/ /opt/kubespray/images/ # 5. 设置入口脚本,强制校验 inventory 格式、生成加密密钥、注入 token COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]

这段 Dockerfile 的设计逻辑非常明确:第一层解决依赖冲突,第二层解决源码版本漂移,第三层解决国内网络适配,第四层解决离线部署刚需,第五层解决安全基线合规。其中patches/0003-etcd-heartbeat-timeout.patch是关键——它把roles/etcd/defaults/main.yml中etcd_heartbeat_interval: "100"改为"500",etcd_election_timeout: "1000"改为"5000",直接规避了因内网延迟抖动导致 etcd 成员反复选举、进而触发the api server is not healthy报错的高频问题。

2.3 为什么不用 kubeadm 或 RKE?KubeSpray 的不可替代性在哪?

kubeadm 是官方推荐的“最小可行集群”工具,但它不处理高可用控制面(需手动搭 keepalived + haproxy)、不管理 etcd 集群生命周期(备份/恢复/扩缩容需额外脚本)、不提供多云统一配置(AWS/Azure/裸金属共用同一 inventory)。RKE 更偏向 Rancher 生态,对非 RKE 管理的集群缺乏长期维护承诺。而 KubeSpray 的核心优势在于:

  • etcd 作为一等公民:roles/etcd模块完整覆盖证书签发、静态 pod 部署、健康检查、快照备份(etcdctl snapshot save)、恢复(etcdctl snapshot restore)全流程;
  • 网络插件可插拔:Calico、Cilium、Weave、Flannel 全支持,且 Calico 默认启用 BGP 模式,适配国内数据中心常见三层网络架构;
  • 节点角色精细化控制:通过node['node-role.kubernetes.io/control-plane']和node['node-role.kubernetes.io/etcd']标签,允许 control-plane 与 etcd 分离部署(如 3 control-plane + 3 etcd + N worker),避免单点资源争抢;
  • 滚动升级原子性保障:upgrade-cluster.ymlplaybook 内置 drain/cordon/uncordon 逻辑,配合kube_version变量可精确控制升级节奏,支持灰度发布。

这正是“国内互联网方案一”的底层逻辑:不是追求最简,而是追求最稳、最可运维、最易审计。


3. 部署实操:从零开始跑通高可用集群(含完整 inventory 配置)

部署不是docker run一行命令就完事。你需要准备三类输入:inventory 清单、证书密钥、离线镜像包。资源包已为你准备好模板和校验工具,下面按真实操作顺序展开。

3.1 准备 inventory:一份能过校验的 hosts.yml 是成功一半

KubeSpray 的 inventory 不是简单 IP 列表,而是带角色、标签、变量的 YAML 结构。资源包中inventory/sample/hosts.yml已按国内典型拓扑预设(3 control-plane + 3 etcd + 2 worker),但你必须根据实际环境修改。关键字段说明如下:

字段必填示例值说明
all children是kube_control_plane,etcd,kube_node定义主机组继承关系,决定哪些节点参与哪些 play
kube_control_plane hosts是node1,node2,node3控制面节点,将运行 kube-apiserver/kube-controller-manager/kube-scheduler
etcd hosts是node1,node2,node3etcd 节点,建议与 control-plane 同节点(降低网络跳数)或分离(提升稳定性)
kube_node hosts是node4,node5工作节点,运行 kubelet/kube-proxy
node1 ansible_host是192.168.10.11目标节点 SSH 访问地址,必须能被容器内 Ansible 访问
node1 access_ip是192.168.10.11K8S 组件绑定的 IP,用于 API Server 的--advertise-address
node1 ip是192.168.10.11Pod 网络通信使用的 IP,calico 默认从此取值
node1 container_runtime否containerd默认值,无需修改;若用 docker,需设为docker并确保docker_version匹配

注意:access_ip和ip必须是目标节点上真实存在的、非 loopback 的 IPv4 地址。若使用双网卡(如 eth0 内网 + eth1 外网),务必确认access_ip绑定在内网接口上,否则 kube-apiserver 无法被其他 control-plane 节点访问,直接触发the api server is not healthy。

3.2 生成并注入 TLS 证书密钥:安全基线不能妥协

KubeSpray 默认使用自签名 CA,但生产环境必须满足等保三级对证书有效期、密钥长度的要求。资源包内置gen_certs.sh脚本,自动执行以下操作:

#!/bin/bash # gen_certs.sh —— 生成符合等保三级要求的 PKI openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "/CN=k8s-ca" openssl genrsa -out apiserver.key 4096 openssl req -new -key apiserver.key -out apiserver.csr -subj "/CN=kube-apiserver" -config <(cat <<EOF [req] default_bits = 4096 prompt = no default_md = sha256 req_extensions = req_ext distinguished_name = dn [dn] C = CN ST = Zhejiang L = Hangzhou O = k8s-prod OU = Platform CN = kube-apiserver [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local IP.1 = 127.0.0.1 IP.2 = 10.233.0.1 # service CIDR 第一个 IP IP.3 = 192.168.10.11 # node1 access_ip IP.4 = 192.168.10.12 # node2 access_ip IP.5 = 192.168.10.13 # node3 access_ip EOF ) openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out apiserver.crt -days 3650 -sha256 -extfile <(cat <<EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local IP.1 = 127.0.0.1 IP.2 = 10.233.0.1 IP.3 = 192.168.10.11 IP.4 = 192.168.10.12 IP.5 = 192.168.10.13 EOF )

此脚本生成的证书满足:

  • RSA 4096 位密钥(等保三级要求 ≥2048,推荐 4096);
  • 有效期 10 年(3650 天),避免频繁轮换;
  • SAN(Subject Alternative Name)包含全部 control-plane 节点 IP,解决x509: certificate is valid for 127.0.0.1, 10.233.0.1, not 192.168.10.11报错;
  • extendedKeyUsage = serverAuth明确标识为服务端证书。

生成后,将ca.crt,ca.key,apiserver.crt,apiserver.key放入inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml同级目录,并在该文件中设置:

# k8s-cluster.yml certificates_dir: "/etc/kubernetes/ssl"

KubeSpray 会自动将这些证书复制到各节点/etc/kubernetes/ssl/目录。

3.3 执行部署:一条 docker run 命令背后的完整流程

假设你已完成 inventory 编辑、证书生成、目标节点 SSH 免密配置(ssh-copy-id root@192.168.10.11),现在执行:

docker run \ --rm \ -v $(pwd)/inventory:/inventory \ -v $(pwd)/artifacts:/artifacts \ -v $(pwd)/certs:/certs \ -e "ANSIBLE_HOST_KEY_CHECKING=False" \ -e "KUBE_VERSION=v1.28.11" \ -e "CONTAINER_RUNTIME=containerd" \ quay.io/kubespray/kubespray-docker:v2.23.1 \ -i /inventory/sample/hosts.yml \ -c /opt/kubespray/cluster.yml \ --extra-vars "certificates_dir=/certs"

这条命令的含义是:

  • --rm:容器退出后自动删除,避免残留;
  • -v $(pwd)/inventory:/inventory:将本地 inventory 目录挂载到容器内/inventory;
  • -v $(pwd)/artifacts:/artifacts:挂载输出目录,KubeSpray 会把生成的 kubeconfig、证书、日志存于此;
  • -v $(pwd)/certs:/certs:挂载证书目录,供--extra-vars注入;
  • -e "ANSIBLE_HOST_KEY_CHECKING=False":关闭 SSH host key 检查,避免首次连接交互阻塞;
  • -e "KUBE_VERSION=v1.28.11":指定 Kubernetes 版本,必须与 KubeSpray v2.23.1 兼容;
  • -e "CONTAINER_RUNTIME=containerd":显式声明运行时,避免自动探测失败;
  • quay.io/kubespray/kubespray-docker:v2.23.1:镜像名,资源包已提供离线 tar 包kubespray-docker-v2.23.1.tar,可用docker load -i kubespray-docker-v2.23.1.tar加载;
  • -i /inventory/sample/hosts.yml:指定 inventory 文件路径(容器内);
  • -c /opt/kubespray/cluster.yml:指定主 playbook 路径;
  • --extra-vars "certificates_dir=/certs":传递证书目录变量。

执行后,你会看到 Ansible 逐 stage 打印日志:Gathering Facts→Bootstrap OS→Generate certs→Deploy etcd→Deploy Kubernetes→Deploy network plugin→Deploy core add-ons。整个过程约 12~18 分钟,取决于磁盘 I/O 和网络带宽。


4. 避坑指南:KubeSpray 部署中最常触发the api server is not healthy的 5 类原因及修复

the api server is not healthy after 4m0.00747357s是 KubeSpray 部署失败最典型的错误提示,它出现在roles/kubernetes/master/tasks/wait-for-apiserver.yml中,本质是curl -k https://127.0.0.1:6443/healthz返回非 200。但背后原因千差万别,以下是我在 17 次真实部署中记录的 5 类高频 root cause,每条都附带现象、原因、解决步骤:

4.1 现象:curl: (7) Failed to connect to 127.0.0.1 port 6443: Connection refused

原因:kube-apiserver static pod 未启动,根本原因是/etc/kubernetes/manifests/kube-apiserver.yaml中--advertise-address指向了一个不存在的 IP,或--etcd-servers地址无法连通。
解决:

  1. 登录任一 control-plane 节点,执行kubectl get pods -n kube-system | grep apiserver,若无输出,说明 static pod 未创建;
  2. 检查/etc/kubernetes/manifests/kube-apiserver.yaml,确认--advertise-address值等于该节点access_ip(非127.0.0.1);
  3. 检查--etcd-servers是否为https://192.168.10.11:2379,https://192.168.10.12:2379,https://192.168.10.13:2379,且每个地址telnet 192.168.10.xx 2379能通;
  4. 若 etcd 未启动,执行systemctl status etcd,查看日志journalctl -u etcd -n 100,常见原因是/var/lib/etcd目录权限为root:root但 etcd 进程以etcd用户运行,需chown -R etcd:etcd /var/lib/etcd。

4.2 现象:curl: (56) Recv failure: Connection reset by peer

原因:TLS 握手失败,通常是证书 SAN 缺失目标节点 IP,或ca.crt与apiserver.crt不匹配。
解决:

  1. 在 control-plane 节点执行openssl x509 -in /etc/kubernetes/ssl/apiserver.crt -text -noout | grep -A1 "Subject Alternative Name",确认输出包含该节点access_ip;
  2. 执行openssl verify -CAfile /etc/kubernetes/ssl/ca.crt /etc/kubernetes/ssl/apiserver.crt,若返回OK则证书链正确,否则需重新生成;
  3. 检查/etc/kubernetes/manifests/kube-apiserver.yaml中--client-ca-file和--tls-cert-file路径是否指向/etc/kubernetes/ssl/下对应文件。

4.3 现象:curl: (52) Empty reply from server

原因:kube-apiserver 进程已启动,但因内存不足被 OOM Killer 杀掉,或 CPU 被占满无法响应。
解决:

  1. 执行dmesg -T | grep -i "killed process",若看到Out of memory: Kill process 12345 (kube-apiserver),则需增加节点内存(至少 4GB)或调低--max-requests-inflight;
  2. 执行top -b -n1 | head -20,观察kube-apiserver进程 CPU 占用是否持续 >90%,若是,检查是否有大量无效 watch 请求(如旧版 Prometheus 配置了kubernetes_sd_configs但未加 namespace 过滤);
  3. 在inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml中添加:
    kube_apiserver_extra_args: max-requests-inflight: "300" max-mutating-requests-inflight: "200"

4.4 现象:curl: (7) Failed to connect to 127.0.0.1 port 6443: Connection timed out

原因:iptables/nftables 规则拦截了 6443 端口,或 firewalld 未关闭。
解决:

  1. 执行systemctl stop firewalld && systemctl disable firewalld(CentOS/RHEL)或ufw disable(Ubuntu);
  2. 执行iptables -L -n | grep 6443,若存在 DROP 规则,执行iptables -D INPUT -p tcp --dport 6443 -j DROP;
  3. 对于使用 nftables 的系统(如 Ubuntu 22.04),执行nft list ruleset | grep 6443,若有拦截,编辑/etc/nftables.conf删除相关规则。

4.5 现象:curl: (60) SSL certificate problem: unable to get local issuer certificate

原因:/etc/ssl/certs/ca-certificates.crt未包含 KubeSpray 生成的 CA,导致容器内 curl 无法验证证书。
解决:

  1. 在 control-plane 节点执行cp /etc/kubernetes/ssl/ca.crt /usr/local/share/ca-certificates/k8s-ca.crt && update-ca-certificates;
  2. 若使用 containerd,还需在/etc/containerd/config.toml中添加:
    [plugins."io.containerd.grpc.v1.cri".registry.configs."registry.cn-hangzhou.aliyuncs.com".tls] ca_file = "/etc/kubernetes/ssl/ca.crt"
  3. 重启 containerd:systemctl restart containerd。

5. 验证高可用:不只是kubectl get nodes,而是模拟节点宕机后的自愈能力

部署成功后,kubectl get nodes显示Ready只是起点。真正的高可用,体现在当一台 control-plane 节点断电后,集群仍能接受新 Pod 创建、Service 仍能正常转发流量、etcd 仍能完成读写。以下是必须执行的 4 项验证动作,每项都对应一个具体命令和预期输出。

5.1 验证 etcd 集群健康状态:etcdctl endpoint health

登录任意 control-plane 节点,执行:

export ETCDCTL_API=3 export ETCDCTL_CACERT=/etc/kubernetes/ssl/ca.crt export ETCDCTL_CERT=/etc/kubernetes/ssl/etcd-server.crt export ETCDCTL_KEY=/etc/kubernetes/ssl/etcd-server.key etcdctl --endpoints=https://192.168.10.11:2379,https://192.168.10.12:2379,https://192.168.10.13:2379 \ endpoint health --write-out=table

预期输出:

+----------------------------+--------+-------------+-------+ | ENDPOINT | HEALTH | TOOK | ERROR | +----------------------------+--------+-------------+-------+ | https://192.168.10.11:2379 | true | 10.234567ms | | | https://192.168.10.12:2379 | true | 11.345678ms | | | https://192.168.10.13:2379 | true | 12.456789ms | | +----------------------------+--------+-------------+-------+

若某 endpoint 显示false或timeout,说明该节点 etcd 实例异常,需立即检查journalctl -u etcd。

5.2 验证 kube-apiserver 负载均衡:curl -k https://<VIP>:6443/healthz

如果你配置了 keepalived + haproxy 作为外部 VIP(如192.168.10.100),执行:

curl -k https://192.168.10.100:6443/healthz # 输出应为 "ok"

然后手动关闭node1的 kube-apiserver static pod:

mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/ sleep 10 curl -k https://192.168.10.100:6443/healthz # 仍应输出 "ok",证明 VIP 自动切到 node2 或 node3

5.3 验证 DNS 与 Service 可用性:nslookup kubernetes.default.svc.cluster.local

在任一 worker 节点上,启动一个临时 busybox Pod:

kubectl run dns-test --image=busybox:1.35 --restart=Never --rm -it -- nslookup kubernetes.default.svc.cluster.local

预期输出:

Server: 10.233.0.3 Address 1: 10.233.0.3 kube-dns.kube-system.svc.cluster.local Name: kubernetes.default.svc.cluster.local Address 1: 10.233.0.1 kubernetes.default.svc.cluster.local

若解析失败,检查 CoreDNS Pod 日志:kubectl logs -n kube-system -l k8s-app=kube-dns,常见原因是Corefile中forward . /etc/resolv.conf指向了宿主机 DNS,而宿主机 DNS 不可达,需改为forward . 114.114.114.114。

5.4 验证 Pod 调度与网络连通性:跨节点 Pod 互 ping

部署一个 nginx Deployment,强制调度到不同节点:

# nginx-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25-alpine ports: - containerPort: 80 topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: nginx

应用后,获取两个 Pod 的 IP:

kubectl get pods -o wide # NAME READY STATUS IP NODE # nginx-5c7f9c8d4-abcde 1/1 Running 10.233.64.2 node4 # nginx-5c7f9c8d4-fghij 1/1 Running 10.233.65.3 node5

进入第一个 Pod,ping 第二个 Pod IP:

kubectl exec -it nginx-5c7f9c8d4-abcde -- ping -c 3 10.233.65.3 # 应收到 3 个 reply,证明 Calico BGP 路由已同步,跨节点网络打通

6. 进阶技巧:如何用这套资源包实现“灰度升级”与“配置热更新”

部署只是开始,真正的运维挑战在后续迭代。KubeSpray 原生支持滚动升级,但默认行为是“全量替换”,风险极高。资源包中我加入了两个关键增强:基于 inventory group 的分批升级策略和Ansible Vault 加密的敏感配置热注入。它们让升级不再是“赌一把”,而是可预测、可回滚、可审计的操作。

6.1 分批升级:把 3 control-plane 节点拆成两组,先升 node1,再升 node2+node3

KubeSpray 的upgrade-cluster.yml默认对kube_control_plane组内所有节点并发执行。但生产环境要求“一次只动一个 control-plane”,避免 quorum 丢失。资源包中inventory/sample/group_vars/all/all.yml新增了upgrade_batch_size: 1变量,并在roles/kubernetes/master/tasks/upgrade-control-plane.yml中重写了任务逻辑:

- name: Upgrade control plane components include_role: name: kubernetes/master vars: upgrade_kubelet: true upgrade_kubectl: true when: inventory_hostname in groups['kube_control_plane'] | list | batch(1) | first

实际操作时,你只需修改 inventory,将节点分组:

# hosts.yml all: children: kube_control_plane: hosts: node1: ansible_host: 192.168.10.11 access_ip: 192.168.10.11 node2: ansible_host: 192.168.10.12 access_ip: 192.168.10.12 node3: ansible_host: 192.168.10.13 access_ip: 192.168.10.13 upgrade_group_1: hosts: node1: upgrade_group_2: hosts: node2: node3:

然后执行两次升级命令:

# 第一批:只升级 node1 docker run ... quay.io/kubespray/kubespray-docker:v2.23.1 \ -i /inventory/sample/hosts.yml \ -c /opt/kubespray/upgrade-cluster.yml \ --limit upgrade_group_1 \ --extra-vars "kube_version=v1.29.4" # 等待 node1 Ready 后,第二批:升级 node2+node3 docker run ... quay.io/kubespray/kubespray-docker:v2.23.1 \ -i /inventory/sample/hosts.yml \ -c /opt/kubespray/upgrade-cluster.yml \ --limit upgrade_group_2 \ --extra-vars "kube_version=v1.29.4"

--limit参数精准控制作用域,比修改 inventory 更灵活。

6.2 敏感配置热更新:用 Ansible Vault 加密 etcd 备份密码,不重启服务生效

etcd 快照备份密码(如ETCD_SNAPSHOT_PASSWORD=My$tr0ngP@ssw0rd)属于高危凭证,不能明文写在 inventory 里。资源包采用 Ansible Vault 加密:

# 1. 创建加密变量文件 echo "etcd_snapshot_password: My$tr0ngP@ssw0rd" > vault_vars.yml ansible-vault encrypt vault_vars.yml # 2. 在 playbook 中引用 - name: Set etcd backup password set_fact: etcd_snapshot_password: "{{ lookup('ansible.builtin.file', '/vault_vars.yml') | from_yaml }}" no_log: true

更进一步,我编写了一个etcd-backup-rotate.ymlplaybook,它不依赖 KubeSpray 主流程,可独立运行:

--- - name: Rotate etcd snapshots hosts: etcd gather_facts: false vars_files: - /vault_vars.yml tasks: - name: Create backup directory file: path: /var/lib/etcd/backups state: directory mode: '0700' - name: Take etcd snapshot shell: | ETCDCTL_API=3 etcdctl \ --endpoints=https://{{ ansible_host }}:2379 \ --cacert=/etc/kubernetes/ssl/etcd-ca.crt \ --cert=/etc/kubernetes/ssl/etcd-client.crt \ --key=/etc/kubernetes/ssl/etcd-client.key \ snapshot save /var/lib/etcd/backups/{{ ansible_date_time.iso86 <p> <a href="https://download.csdn.net/download/m0_37814112/85218008" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 9:43:52

Bootstrap树形表格插件实战:原理、选型与高频踩坑

简介&#xff1a;Bootstrap TreeGrid 插件基于 Bootstrap 框架&#xff0c;面向 Web 前端开发者&#xff0c;主要解决表格内层级数据的展示与交互问题&#xff0c;常用于权限管理、分类目录等需要嵌套结构的页面&#xff0c;也适用于后台管理系统或内容组织场景。压缩包共 7 个…

作者头像 李华
网站建设 2026/10/14 9:43:32

TV模型与哈里斯鹰算法在图像修复中的优化应用

1. 项目概述&#xff1a;当TV模型遇上哈里斯鹰算法 作为一名长期从事图像处理研究的工程师&#xff0c;我经常遇到各种图像修复的挑战。传统TV&#xff08;Total Variation&#xff09;模型虽然在某些场景下表现不错&#xff0c;但面对复杂图像时往往力不从心。直到我发现哈里斯…

作者头像 李华
网站建设 2026/10/14 9:43:17

LiteLLM实战:统一大模型网关,告别多SDK适配烦恼

接入大模型 API 的第一个月&#xff0c;我们组差点被一堆 provider SDK 给淹没。今天换这个厂商的鉴权&#xff0c;明天改那个平台的超时参数&#xff0c;后天又发现某个模型输出格式和别家不一样&#xff0c;整个开发进度全耗在“适配”上。后来我把核心网关换成了 litellm …

作者头像 李华
网站建设 2026/10/14 9:43:15

COMSOL多物理场耦合仿真实战技巧与工程应用

1. 项目概述&#xff1a;多物理场耦合仿真的工程价值在工程仿真领域&#xff0c;真正考验软件能力的往往不是单一物理场的模拟&#xff0c;而是多个物理场之间复杂的相互作用。COMSOL Multiphysics作为业界领先的多物理场仿真平台&#xff0c;其核心优势就在于能够无缝耦合传热…

作者头像 李华
网站建设 2026/10/14 9:43:05

RocketMQ消息可靠性保障:从原理到实践

1. 消息队列可靠性问题本质剖析 当面试官抛出"RocketMQ如何保证消息不丢失"这个问题时&#xff0c;本质上是在考察我们对分布式系统可靠性的理解深度。消息队列作为系统解耦的关键组件&#xff0c;其可靠性直接关系到上下游业务的数据一致性。以电商订单场景为例&…

作者头像 李华
网站建设 2026/10/14 9:43:03

CentOS7非root用户免密管理systemctl服务的四种安全方案

1. 问题本质与真实场景还原“CentOS7下非root账号通过systemctl管理服务需要输入root密码”——这句话不是一句配置报错&#xff0c;而是一道横在运维、开发、测试多角色之间的权限认知分水岭。我第一次遇到这个现象&#xff0c;是在给某高校实验室部署一套教学用的Web服务集群…

作者头像 李华