12 KiB
01-05-节点初始化与 k3s 自动安装(Ansible 实践)
目标:给一组已经装好 OS、可以 SSH 的裸金属/虚机,一键完成基础初始化 + 安装 k3s server/worker,得到与
01-01、01-02文档一致的集群(含/storage数据盘方案)。状态:已验证(2026-03,Fedora + K3s,4 节点 61~64)。
部署环境详见00-02-部署环境说明.md。
契约与真源
- 索引:
ansible/files/01-05/README.md(执行真源为ansible/playbooks/verify/01-05.yml与deploy-lab.sh)。 - 自动:
./ansible/bin/deploy-lab.sh k3s或./ansible/bin/verify.sh run 01-05。
TL;DR
- 一键安装:
./ansible/bin/deploy-lab.sh k3s - 一键验收:
./ansible/bin/verify.sh run 01-05(或直接./ansible/bin/verify.sh full) - 关键前置:控制端可 SSH 所有节点;
ansible/inventory.ini私钥路径存在且权限正确;(可选)每台节点已挂载/storage或启用K3S_PREPARE_STORAGE=true - 成功判据:所有节点
Ready;kube-system 核心组件就绪;后续按02-05可跑入口验证 - 失败排障:见本文「排障」小节(SSH/私钥、/storage、firewalld、k3s service)
1. 适用边界与前提
- 已完成:
- 控制机(运行 ansible-playbook 的那台机器)已安装 Ansible:
- Fedora / RHEL:
sudo dnf install ansible - Debian / Ubuntu:
sudo apt install ansible - 验证:
ansible --version、ansible-playbook --version
- Fedora / RHEL:
- 每台目标机器已经安装好 Linux(如 Fedora/CentOS/Debian 等);
- 能通过 SSH 无密码/密钥登录(Ansible 能连通);
- 若使用
scripts/ssh/setup-k3s-workers-ssh.sh为每节点配置独立密钥,需在 inventory 中为各 host 指定ansible_ssh_private_key_file(见下文示例); - 使用 root SSH 连接(
group_vars/all.yml中ansible_user: root),配合scripts/ssh/setup-k3s-workers-ssh.sh为所有节点(含控制节点)配置 jack + root 的公钥; - IP 规划、主机名已大致确定,例如:
ylc61:k3s server,IP192.168.2.61ylc62~ylc64:k3s worker,IP192.168.2.62~192.168.2.64
- 数据盘:若使用
/storage方案,每台节点须将独立数据盘挂载到/storage(与/不同设备),详见00-04与下文「数据盘准备」。
- 控制机(运行 ansible-playbook 的那台机器)已安装 Ansible:
- 不覆盖:
- 从「完全裸铁 + 无系统」开始的 PXE 装机;
- 高级 HA(多 server + 外部 datastore)——仍按
01-07、03-08执行。
1.1 数据盘准备(手工,或与自动化二选一)
在运行 k3s 安装 playbook 之前,每台节点应满足:mountpoint /storage 为真,且 findmnt -n -o SOURCE / 与 findmnt -n -o SOURCE /storage 不相同。
手工示例(第二块盘为 /dev/vdb,请按 lsblk 实际设备名修改;误选设备会清空该盘):
sudo parted -s /dev/vdb mklabel gpt mkpart primary ext4 0% 100%
sudo mkfs.ext4 -F /dev/vdb1
UUID=$(sudo blkid -s UUID -o value /dev/vdb1)
echo "UUID=$UUID /storage ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mkdir -p /storage && sudo mount -a
XFS 用户将 mkfs.ext4 / fstab 类型改为 xfs 即可(Longhorn 支持 ext4/XFS)。
自动化(可选):在 group_vars/all.yml 中设置 k3s_prepare_storage: true 与 k3s_data_disk_device: /dev/vdb(四台盘符一致时一条即可;不一致则用 host_vars/<hostname>.yml 覆盖),然后执行:
ansible-playbook -i inventory.ini playbooks/verify/01-05.yml
该 playbook 在 /storage 已是独立挂载时会跳过,避免重复执行。
1.2 推荐执行顺序(10G + 32G 四节点)
- (可选)
playbooks/verify/01-05.yml playbooks/verify/01-05.yml(可在group_vars中设k3s_verify_storage_mount: true强制校验/与/storage不同源)- (可选)
playbooks/verify/03-07.yml(Helm,见03-07) - (可选)
playbooks/verify/03-05.yml,或longhorn_apply_local_path_lab: true随 Longhorn 一并应用(真源:files/kube-system/local-path-config-lab.json,见03-05)
2. 目录结构
本仓库已有 ansible/:
ansible/
ansible.cfg # host_key_checking=False 等
inventory.ini
group_vars/
all.yml
playbooks/
verify/
01-05.yml # 标准 IPv4 安装(-e k3s_do_install=true);可选准备数据盘(-e k3s_do_prepare_storage=true)
03-07.yml # 可选:Helm 安装 Longhorn
03-05.yml # 可选:仅应用 local-path 实验室 ConfigMap(-e local_path_apply_lab_config=true)
files/
longhorn/values-lab.yaml # 实验室 Helm values
kube-system/local-path-config-lab.json
3. 示例 inventory
ansible/inventory.ini:
[k3s_server]
ylc61 ansible_host=192.168.2.61 ansible_ssh_private_key_file=~/.ssh/id_ed25519_k3s_192.168.2.61
[k3s_worker]
ylc62 ansible_host=192.168.2.62 ansible_ssh_private_key_file=~/.ssh/id_ed25519_k3s_192.168.2.62
ylc63 ansible_host=192.168.2.63 ansible_ssh_private_key_file=~/.ssh/id_ed25519_k3s_192.168.2.63
ylc64 ansible_host=192.168.2.64 ansible_ssh_private_key_file=~/.ssh/id_ed25519_k3s_192.168.2.64
[k3s_nodes:children]
k3s_server
k3s_worker
提示:上面使用短主机名(如
ylc61~ylc64),应与各节点 hostname 及kubectl get nodes输出的 NAME 一致,便于配合 Cloudflare CDN;playbook 的 Init 阶段会为所有 k3s 节点写入 /etc/hosts 条目。
4. 全局变量
唯一真源:ansible/group_vars/all.yml(含 ansible_user、k3s_data_dir、k3s_server_ip、k3s_manage_* 等)。
若需安装后自动打 control-plane/worker 角色标签(供 02-05 与 03-02 的 M1/M3 使用),在同一文件中增加,例如:
k3s_manage_role_labels: truek3s_control_plane_nodenames: ["ylc61"]k3s_worker_nodenames: ["ylc62", "ylc63", "ylc64"]
节点名必须与 kubectl get nodes 输出一致(使用短主机名 ylc61~ylc64)。未配置时仅打 enablelb/lbpool,不打角色标签。
CoreDNS 上游 DNS(供 ACME 解析 Let's Encrypt,见 03-02 常见问题):若宿主机 /etc/resolv.conf 为 IPv6,Pod 网络仅 IPv4 时无法解析,ACME 会失败。playbook 默认会将 CoreDNS forward 改为 IPv4:
k3s_manage_coredns: true(默认开启)coredns_forward_servers: "223.5.5.5 8.8.8.8"(可按环境修改)
禁用时设 k3s_manage_coredns: false。
存储挂载校验(推荐实验室开启):
k3s_verify_storage_mount: true:在01-05.yml安装 k3s(-e k3s_do_install=true)之前,断言/storage为挂载点且与/不同块设备;失败时提示查阅00-04。已有「目录式假 /storage」的旧环境可临时设为false。
数据盘自动化(可选):
k3s_prepare_storage: true且k3s_data_disk_device: /dev/vdb:由01-05.yml -e k3s_do_prepare_storage=true执行(见 §1.1)。
5. 执行流程概览
playbook 依次执行:
| 顺序 | 阶段 | 内容 |
|---|---|---|
| 1 | Init | 时区、基础包、/etc/hosts、firewalld 开放 8472/udp(全部节点)与 6443/tcp(仅 server) |
| 2 | Install server | 安装 k3s server(--data-dir=/storage) |
| 3 | Install agent | 逐台安装 worker(serial: 1);随后在 server 上 kubectl wait 各 worker Ready(不在 worker 上 delegate_to server,避免 SSH 路径异常) |
| 4 | Firewalld 基线 | 等待 flannel.1/cni0 出现(最多 120s),加入 trusted zone |
| 5 | CoreDNS(可选) | 当 k3s_manage_coredns: true 时,将 forward 改为 IPv4(223.5.5.5 8.8.8.8),避免 ACME 解析 Let's Encrypt 失败 |
| 6 | Traefik 标签 | 从集群动态获取节点名,打 enablelb/lbpool 标签 |
| 7 | 角色标签(可选) | 当 k3s_manage_role_labels: true 时,为控制节点打 control-plane、工作节点打 worker |
| 8 | 验证 | 输出 kubectl get nodes、kubectl get pods -n kube-system、curl 各节点 HTTP |
关键实现点:
- 端口 8472/udp:flannel VXLAN 所需,必须在 Init 阶段开放,否则 worker 上 flannel 无法建立 overlay,
flannel.1/cni0永远不会出现; - Firewalld 基线(flannel.1/cni0 → trusted):FCOS/Fedora 默认 firewalld 转发策略较严格;K3s 不会自动配置宿主机 firewalld 的 zone 接口归类。入口 Pod(Traefik/svclb-traefik)可能调度到任意节点,回包路径会经过该节点本地的
flannel.1/cni0。若某节点上flannel.1 ↔ cni0的转发被 firewalld 拦截,该节点上的入口流量就会异常,即使其它节点正常。详见01-02-k3s-工作节点.md; - Traefik 标签:使用
kubectl get nodes -o jsonpath获取实际节点名,不依赖 inventory 主机名与 K8s 节点名一致; - CoreDNS(可选):宿主机若使用 IPv6 DNS(如运营商分配的
240e:...),Pod 网络仅 IPv4 时 CoreDNS 无法访问上游,导致 Traefik ACME 无法解析 Let's Encrypt 域名。playbook 会将forward . /etc/resolv.conf改为forward . 223.5.5.5 8.8.8.8,详见03-02常见问题。 - 角色标签(可选):playbook 默认只打 enablelb/lbpool,不打
node-role.kubernetes.io/control-plane与node-role.kubernetes.io/worker。若需03-01/03-03nginx 矩阵的 M1/M3 能调度,可开启k3s_manage_role_labels并配置控制节点/工作节点名列表(见下),或安装后在控制节点按 01-02 可选步骤手动打标。 - Agent 安装:token 在 Install server 阶段于 server 上
slurp;各 worker 本机执行get.k3s.io安装 agent。等待 worker Ready 使用独立 play(hosts: k3s_server)执行kubectl wait,与「控制机 → server」的 SSH 路径一致,避免在 worker 任务内delegate_to控制机时出现UNREACHABLE [worker -> server](如对192.168.2.61:22超时)。
6. 使用方式
6.1 SSH 前置(若未配置)
先运行 scripts/ssh/setup-k3s-workers-ssh.sh,为所有 k3s 节点(含 server)配置 jack + root 公钥及 inventory 所需的私钥。
6.2 执行 playbook
在 ansible/ 目录下执行:
cd ansible
# (可选)先准备数据盘挂载 /storage
# ansible-playbook -i inventory.ini playbooks/verify/01-05.yml
# 标准 IPv4 安装
ansible-playbook -i inventory.ini playbooks/verify/01-05.yml
# (可选)Helm 安装 Longhorn
# ansible-playbook -i inventory.ini playbooks/verify/03-07.yml
执行结束后,playbook 会输出:
kubectl get nodeskubectl get pods -n kube-system -o wide- 各节点 IP 的 curl HTTP 测试结果
6.3 手动验证(可选)
在 server(如 ylc61)上执行:
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes -o wide
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get pods -n kube-system -o wide
确认 /storage 方案:
- server 与 worker 的 k3s 数据目录均为
/storage; - token 路径为
/storage/server/token。
7. 下一步
集群就绪后,可继续阅读:
03-09-k3s-gitops-集群配置管理.md:用 Argo CD/Flux 管理 Traefik、监控、应用清单;01-01、01-02中的验证命令与入口验证。
排障
- Install k3s worker/server 长时间无输出或最终超时:任务在拉取
https://get.k3s.io并从 GitHub 下二进制;worker 需能访问外网。可在ansible/group_vars/all.yml设k3s_install_mirror: cn(走安装脚本国内镜像),或调大k3s_install_curl_max_time/k3s_install_task_timeout;curl已带--connect-timeout/--max-time,超时后会失败退出而不是无限挂住。 - worker 阶段
UNREACHABLE [ylc62 -> ylc61]/ 连192.168.2.61:22超时:多为在 worker 上下文中delegate_to控制机时连接行为与预期不符。当前01-05.yml已改为在hosts: k3s_server的独立 play 里kubectl waitworker;若仍失败,在控制机单独ssh root@<server_ip>与kubectl get nodes排查。 - Ansible 连不上节点:先在控制端跑
./ansible/bin/verify.sh preflight;检查ansible/inventory.ini主机名/IP、ansible_user、私钥路径与权限(600)。 - /storage 校验失败:确认每台节点
/storage为独立挂载点;必要时先跑K3S_PREPARE_STORAGE=true ./ansible/bin/deploy-lab.sh k3s或单独跑ansible/playbooks/verify/01-05.yml。 - kube-system 组件不就绪:在 server 上
journalctl -u k3s -n 200 --no-pager,以及kubectl -n kube-system get pods -o wide/describe查看事件。