Skip to content

05 · 接入 Rancher(Virtualization Management)与内外网分离解析

目标:让 Harvester 集群(192.168.150.0/24virbr10)用内网地址访问 Rancher (RKE2 三节点 192.168.122.20/21/22virbr0),从而被 Rancher 导入并在 Virtualization Management 页面统一管理;宿主机/公网侧仍走 https://ai-ear.cn:30443(frp 隧道)。

本文全部为实测结果(2026-09-06)。相关故障根因见 02-故障排查与修复记录.md 案例 24~27, 一键脚本为 deploy/scripts/99-rancher-internal-net.sh


1. 最终结果(实测)

项目
Rancher 集群名harvester-hci,id c-vd78l
providerharvester(label provider.cattle.io: harvester,因此归入 Virtualization Management)
状态state=activenodeCount=3Provisioned/Connected/Ready 均为 True
agentcattle-system/cattle-cluster-agent ×2 Running;cattle-fleet-system/fleet-agent Running
agent 入口CATTLE_SERVER=https://ai-ear.cn443,不带端口)、CATTLE_CA_CHECKSUM=""
证书DigiCert CN=ai-ear.cn节点系统信任curl 不加 -k 即返回 pong
agent 镜像192.168.122.156:30000/rancher/rancher-agent:v2.14.3(Rancher 的 system-default-registry
UI 数据面GET /k8s/clusters/c-vd78l/v1/harvester/nodescount=3

2. ★ 为什么"只配 DNS"不够:三件事缺一不可

#障碍实测现象
1跨网桥转发被拒libvirt 给每个 NAT 网络插入 FORWARD REJECTvirbr10 ↔ virbr0 双向都不通harvester-01 → 192.168.122.20:443/22 全超时,而 → 192.168.150.1(宿主机)正常
2没有内网解析harvester 网络的 dnsmasq 无 ai-ear.cn 记录,节点解析到公网 8.153.84.140;而公网 443 是文档站,Rancher 只在公网 30443
3CoreDNS 随机上游(最隐蔽)节点 resolv.conf 并列 192.168.150.1223.5.5.5 时,Harvester 的 CoreDNS 是 forward . /etc/resolv.conf 且默认 policy=random:直查 CoreDNS 20 次,10 次返回公网 IP

第 3 条的后果:cattle-cluster-agentwss://ai-ear.cn/v3/connect/register 时 拿到的是 VitePress 首页 HTML,报 websocket: bad handshake,集群一度 state=error (CoreDNS cache 30 + 上游 TTL 过期后会自愈,但反复抖动)。 收敛为单一内网 DNS 后,20/20 全部内网

详见 02 案例 24。这也是为什么装机配置里的 dns_nameservers 也要收敛(§4)。


3. 一键修复:99-rancher-internal-net.sh 的 A~F 六步

bash
sudo bash scripts/99-rancher-internal-net.sh check      # 只看不动(含节点侧巡检)
sudo bash scripts/99-rancher-internal-net.sh apply      # 应用,幂等,可反复跑
sudo bash scripts/99-rancher-internal-net.sh rollback   # 回滚 A/C/D(E/F 不回滚,见下)
步骤位置内容关键点
A宿主机iptables -I FORWARD 1 -i virbr10 -o virbr0 -j ACCEPT(及反向)必须插在 libvirt 的 REJECT 之前;先 iptables -C 探测避免重复
B宿主机把放行块追加/etc/libvirt/hooks/network先备份原文件、只追加不覆盖;带 MARKER 幂等;网络/宿主重启后自动重插
C宿主机virsh net-update harvester add dns-hostai-ear.cn192.168.122.20/21/22--live --config 持久化到网络 XML
D节点 ×3nmcli con mod bridge-mgmt ipv4.dns 192.168.150.1 + nmcli device reapply mgmt-br★ 用 device reapply 不断链;仅在真改动时才 rollout restart CoreDNS
E节点 ×3certs.d/192.168.122.156:30000/hosts.tomlcontainerd config_path 已启用 → 动态生效免重启
FHarvester API设置 containerd-registry官方持久机制:控制器据此在各节点渲染 /etc/rancher/rke2/registries.yaml,rke2 再重写 certs.d

⚠️ rollback 不动 E/F:删掉私仓配置后 cattle-cluster-agent 将再也拉不到镜像。

内外域名分离:VM 内网直连 ingress;宿主机/公网仍走 frp:30443,互不影响。


4. 装机配置同步收敛(否则重装后又引入随机上游)

50-gen-configs.shconfigs/http/configs/ 下的 config-node0*.yamldns_nameservers 只保留宿主 dnsmasq

yaml
os:
  # 只写宿主 dnsmasq:它既提供内网静态解析(ai-ear.cn -> RKE2 ingress 192.168.122.20/21/22),
  # 也会把其它域名转发到公网。不要并列公网 DNS:Harvester 的 CoreDNS 用
  # 「forward . /etc/resolv.conf」且默认随机选上游,实测约 50% 概率把 ai-ear.cn
  # 解析到公网(公网 443 是文档站),导致 cattle-cluster-agent 间歇连不上 Rancher。
  dns_nameservers:
    - 192.168.150.1

原文件已备份为 *.bak-dnsconfigs/http/configs/ 各 3 份)。

去掉公网 DNS 无副作用:宿主 dnsmasq 自身会转发公网域名(实测 www.baidu.com 正常解析)。


5. 导入 Rancher 的实际步骤(API 方式,本次已执行)

bash
TOK=$(cat /tmp/rancher.token)     # Rancher API Token(admin)

# 1) 建「导入集群」;provider 会由 Rancher 事后从下游节点标签识别为 harvester
curl -sk -X POST -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
     -d '{"name":"harvester-hci"}' https://ai-ear.cn:30443/v3/clusters      # → id: c-vd78l

# 2) 取注册 manifest URL(server-url 是 https://ai-ear.cn,所以 URL **不带端口**)
curl -sk -H "Authorization: Bearer $TOK" \
     https://ai-ear.cn:30443/v3/clusters/c-vd78l/clusterRegistrationTokens
#   → https://ai-ear.cn/v3/import/<token>_c-vd78l.yaml

# 3) 在 Harvester 上设置 cluster-registration-url(注意 value 本身是一段 JSON 字符串)
ssh rancher@192.168.150.11 'sudo /var/lib/rancher/rke2/bin/kubectl \
  --kubeconfig /etc/rancher/rke2/rke2.yaml patch settings.harvesterhci.io \
  cluster-registration-url --type merge -p \
  "{\"value\":\"{\\\"url\\\":\\\"https://ai-ear.cn/v3/import/<token>_c-vd78l.yaml\\\",\\\"insecureSkipTLSVerify\\\":false}\"}"'

Harvester 收到设置后自动完成:3 个节点各跑一个 apply-system-agent-upgrader-on-harvester-0N-with-* Job → 部署 cattle-cluster-agent(2 副本) → Rancher 侧 Provisioned/Connected/Ready 依次转 Truestateinitializingactive, 并自动装上 fleet-agentcattle-impersonation-system

💡 不要用 harvesterconfig / harvestercredentialconfig:那是"用 Harvester 当基础设施 provider 去创建下游 K8s 集群"的路径。导入已有 Harvester 走标准 POST /v3/clusters, provider 由 Rancher 自动识别(02 案例 27)。


6. 验证命令

6.1 节点侧(任一 Harvester 节点)

bash
getent hosts ai-ear.cn                       # 期望 192.168.122.20/21/22
curl -s https://ai-ear.cn/ping               # 期望 pong(★ 故意不加 -k,验证证书被系统信任)

# ★ DNS 收敛是否真的生效:只应出现内网 IP;出现 8.153.84.140 说明步骤 D 未生效
for i in $(seq 1 20); do dig +short ai-ear.cn @10.53.0.10 | tr '\n' ' '; echo; done \
  | sort | uniq -c

# ★ 私仓是否可用(绝对路径 + 显式 runtime-endpoint,见 02 案例 27)
sudo /var/lib/rancher/rke2/bin/crictl \
  --runtime-endpoint unix:///run/k3s/containerd/containerd.sock \
  pull 192.168.122.156:30000/rancher/rancher-agent:v2.14.3     # 期望 Image is up to date

6.2 Rancher 侧

bash
curl -sk -H "Authorization: Bearer $TOK" https://ai-ear.cn:30443/v3/clusters/c-vd78l \
  | jq '{state,provider,nodeCount}'          # 期望 active / harvester / 3

curl -sk -H "Authorization: Bearer $TOK" \
  https://ai-ear.cn:30443/k8s/clusters/c-vd78l/v1/harvester/nodes | jq '.count,[.data[].id]'
                                             # 期望 3 / ["harvester-01","harvester-02","harvester-03"]

7. Rancher UI 数据面的代理路径(复用价值高)

/k8s/clusters/<clusterId>/v1/harvester/...

这就是 Rancher Virtualization Management 页面所用的代理路径 (dashboard 插件里拼作 "/k8s/clusters/" + clusterId + "/v1/harvester"local 集群则省略前缀)。

经该隧道同样能取到 KubeVirt 资源,例如:

/k8s/clusters/c-vd78l/v1/harvester/apis/kubevirt.io/v1/namespaces/default/virtualmachines

用途:在 Rancher 侧做统一巡检/自动化时,不需要再单独维护一套 Harvester kubeconfig。


8. 本节踩坑索引(详见 02

案例一句话根因
24CoreDNS forward . /etc/resolv.conf + policy=random → 域名约 50% 概率解析到公网 → agent websocket: bad handshake
25私仓是 HTTP 且节点上不了 docker.io → crictl pullhttp: server gave HTTP response to HTTPS client
26手写 registries.yaml 会被控制器回收(167B → 0B)→ 必须改 containerd-registry 设置;JSON 字段名从 rancherd 二进制 struct tag 反查
27三个操作细节:CoreDNS forward 只在启动时读 resolv.conf;kubectl/crictl/ctr 必须绝对路径 + --runtime-endpoint;节点 SSH host key 变过要 UserKnownHostsFile=/dev/null