Appearance
Kubespray 部署
kubeadm 适合理解组件关系、手工搭建小规模集群。当需要在 30 台机器上反复交付和升级 K8s 集群时,逐台 SSH 和执行命令的方式会出很多操作一致性上的问题。
Kubespray 用 Ansible 把集群安装变成可重复执行的 playbook——一样的动作在 30 台机器上自动重复,inventory 和 group_vars 作为集群配置的唯一真实来源。
| 场景 | 说明 |
|---|---|
| 多节点裸机 / 虚拟机 | 统一初始化系统、安装运行时和 K8s 组件 |
| 多控制平面 | inventory 里声明 kube_control_plane、etcd、kube_node 三种角色 |
| 离线或半离线环境 | 可以提前准备镜像和二进制包 |
| 后续扩容升级 | 通过 Ansible playbook 重复执行,参数在 group_vars 里管理 |
学习组件关系还是 kubeadm 清楚;真正要在一批机器上反复交付集群时,Kubespray 的可重复性更好。
目录和 inventory
bash
git clone https://github.com/kubernetes-sigs/kubespray.git
cd kubespray
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp -rfp inventory/sample inventory/myclusterinventory 写成 YAML,角色清楚:
yaml
# inventory/mycluster/hosts.yaml
all:
hosts:
k8s-master01:
ansible_host: 192.168.10.11
ip: 192.168.10.11
access_ip: 192.168.10.11
k8s-master02:
ansible_host: 192.168.10.12
ip: 192.168.10.12
access_ip: 192.168.10.12
k8s-master03:
ansible_host: 192.168.10.13
ip: 192.168.10.13
access_ip: 192.168.10.13
k8s-node01:
ansible_host: 192.168.10.21
ip: 192.168.10.21
access_ip: 192.168.10.21
children:
kube_control_plane:
hosts:
k8s-master01:
k8s-master02:
k8s-master03:
etcd:
hosts:
k8s-master01:
k8s-master02:
k8s-master03:
kube_node:
hosts:
k8s-node01:
k8s_cluster:
children:
kube_control_plane:
kube_node:
calico_rr:
hosts: {}kube_control_plane、etcd、kube_node 三种角色可以重叠(stacked etcd),也可以拆开(external etcd)。
关键 group_vars
集群级配置:
text
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
inventory/mycluster/group_vars/k8s_cluster/k8s-net-calico.yml
inventory/mycluster/group_vars/all/containerd.ymlyaml
# k8s-cluster.yml
kube_version: v1.36.0
container_manager: containerd
kube_network_plugin: calico
kube_service_addresses: 10.96.0.0/12
kube_pods_subnet: 10.244.0.0/16
dns_mode: coredns
helm_enabled: true
metrics_server_enabled: true控制平面入口:
yaml
# all.yml
apiserver_loadbalancer_domain_name: "k8s-api.example.local"
loadbalancer_apiserver:
address: 192.168.10.100
port: 6443外部已有 HAProxy/Keepalived 或云负载均衡时,把 address 填成 VIP。
安装前检查
最容易漏的:节点时间不同步、DNS 解析不一致、系统源不可用、镜像仓库不可达、机器里残留旧 kubelet/containerd 配置:
bash
ansible -i inventory/mycluster/hosts.yaml all -m ping
ansible -i inventory/mycluster/hosts.yaml all -m shell -a 'hostname; date; df -h /'
ansible -i inventory/mycluster/hosts.yaml all -m shell -a 'ip route; ping -c 2 192.168.10.11'执行安装
bash
ansible-playbook -i inventory/mycluster/hosts.yaml \
--become --become-user=root \
cluster.ymlcluster.yml 实际执行的分阶段:系统初始化→安装 containerd→安装 kubelet/kubeadm→初始化第一台控制平面→安装 CNI→加入其他控制平面→加入工作节点→安装附加组件(CoreDNS、metrics-server 等)。
| 参数 | 说明 |
|---|---|
--become / -b | 提权执行系统级操作 |
--limit | 限制执行主机,扩容或修复时常用 |
-vvv | 输出更详细日志 |
安装完成后取 kubeconfig:
bash
scp root@192.168.10.11:/etc/kubernetes/admin.conf ./kubeconfig
export KUBECONFIG=$PWD/kubeconfig
kubectl get nodes -o wide
kubectl get pods -A -o wide离线环境和镜像
国内或内网环境把默认镜像仓库改成内部 registry:
yaml
# k8s-cluster.yml
registry_host: "registry.example.local"实际项目中还需要同步 kube-apiserver、etcd、pause、CoreDNS、Calico、metrics-server 等系统镜像。离线环境先在一台联网机器上生成镜像清单再同步到 Harbor,比安装现场临时拉外网镜像可靠。
扩容节点
新增工作节点时,在 inventory 加主机并加入 kube_node,然后执行:
bash
ansible-playbook -i inventory/mycluster/hosts.yaml \
--become --become-user=root \
scale.yml \
--limit k8s-node02扩容前确认新节点的内核、系统源、DNS、镜像仓库、时间同步和已有节点一致。节点差异太多,后面排查会很难判断是 K8s 问题还是系统问题。
升级
升级先改 kube_version,再执行:
bash
ansible-playbook -i inventory/mycluster/hosts.yaml \
--become --become-user=root \
upgrade-cluster.yml升级前固定检查:
bash
kubectl get nodes
kubectl get pods -A
kubectl -n kube-system get pods升级不是只升 K8s 版本,还要看 containerd、CNI、CSI、Gateway Controller、Prometheus Operator、metrics-server 和业务组件兼容性。Kubespray 能执行升级动作,不能替代版本兼容性判断。
常见问题
| 现象 | 常见原因 | 处理方向 |
|---|---|---|
| Ansible ping 失败 | SSH、sudo、Python 环境 | 先跑 ansible all -m ping |
| 任务卡在拉镜像 | 外网慢、仓库认证失败 | 配内部 registry,提前同步镜像 |
| 节点 Join 失败 | Token、证书、API 入口不可达 | kubelet 日志和 API Server 入口 |
| CNI Pod 不正常 | Pod CIDR、镜像、内核模块 | Calico/Cilium 日志 |
| 重跑失败 | 节点残留旧配置 | 按 Kubespray reset 流程清理 |
Kubespray 的可重复性建立在 inventory 和 group_vars 也被当成代码管理上。手工改一堆节点再跑 playbook,最后会失去自动化的意义。