K8s集群DNS被Mihomo劫持导致 Zabbix Web 无法 Ready
ENV
| 类别 | 信息 |
|---|---|
| 操作系统 | Ubuntu 20.04 LTS |
| 节点 | 单节点 K8s,igo-k8s-node01(1/1 Ready) |
| 容器运行时 | containerd |
| CNI | Calico(Pod 网段 192.168.0.0/16) |
| Service CIDR | 10.96.0.0/12 |
| 存储 | local-path(StorageClass) |
| 应用 | Zabbix Helm 4.4.1 / PostgreSQL 15 / Zabbix Web 6.0 |
| 命名空间 | igo-zabbix |
| 代理 | Mihomo(Clash Meta,自 Clash Verge deb 提取) |
| 上游代理 | HTTP Squid 10.80.238.40:3128 |
| DNS 模式 | TUN + fake-ip(198.18.0.0/16) |
现象
部署 Zabbix 后 Pod 状态异常:
zabbix-postgresql-0 1/1 Running (初期曾 Pending,PVC 绑定后恢复)
zabbix-zabbix-server-xxx 2/2 Running
zabbix-zabbix-web-xxx 0/1 Running (多次 Restart)
zabbix-zabbix-webservice-xxx 1/1 Running
- Web 探针报
connection refused(8080) - Web 日志循环:
PostgreSQL server is not available. Waiting 5 seconds... - PostgreSQL Service / Endpoint 正常:
10.102.122.177:5432→ Pod192.168.x.x:5432
结论与根因
结论: 问题不在 PostgreSQL 本身,而是 Mihomo TUN 的 dns-hijack: any:53 劫持了 Pod 到 CoreDNS 的 DNS 流量,集群内部域名被解析为 fake-ip(198.18.x.x),导致 Web 连库失败。
根因: dns-hijack: any:53 拦截所有 53 端口查询(含 Pod → 10.96.0.10 CoreDNS),*.svc.cluster.local 返回假 IP;TCP 5432 连假 IP 失败 → nginx 未启动 → Readiness 探针失败。
定位推导
1. Web 连不上数据库
kubectl logs zabbix-zabbix-web-xxx -n igo-zabbix --tail=60
关键输出:
**** PostgreSQL server is not available. Waiting 5 seconds...
Service / Endpoint 正常,排除 PG 未启动:
kubectl get svc,endpoints -n igo-zabbix -o wide | grep postgresql
service/zabbix-postgresql ClusterIP 10.102.122.177 ... 5432/TCP
endpoints/zabbix-postgresql 192.168.x.x:5432
2. DNS 返回 fake-ip
Pod 内解析(修复前):
kubectl exec -n igo-zabbix zabbix-postgresql-0 -- getent hosts zabbix-postgresql
198.18.0.30 zabbix-postgresql.zabbix.svc.cluster.local # 修复前
10.102.122.177 zabbix-postgresql.zabbix.svc.cluster.local # 修复后
节点 resolv.conf 含代理 DNS 198.18.0.2;CoreDNS Pod 直连查询亦返回 fake-ip:
dig @192.168.x.x zabbix-postgresql.igo-zabbix.svc.cluster.local +short
# 198.18.0.30
3. 形成原因推测
Mihomo 按 TUN 全局分流方案 部署,dns-hijack: any:53 在网卡层劫持全部 DNS。K8s Pod 使用 nameserver 10.96.0.10,该流量同样被劫持;fake-ip-filter / nameserver-policy 无法可靠绕过。rules 中 10.0.0.0/8 DIRECT 仅影响流量路由,不影响 DNS 解析阶段 的 fake-ip 分配。
方案
核心配置变更(/etc/mihomo/config.yaml)
tun:
auto-route: true
auto-detect-interface: true
# 【改】排除 K8s 网段,集群内流量不走 TUN
route-exclude-address:
- 10.96.0.0/12 # Service CIDR
- 192.168.0.0/16 # Pod CIDR(Calico)
# 【改】仅劫持本机 systemd-resolved,不劫持 Pod → CoreDNS
dns-hijack:
- 127.0.0.53:53 # 原值: any:53
| 参数 | 当前值(问题配置) | 建议值 | 原因 | 预期效果 |
|---|---|---|---|---|
dns-hijack |
any:53 |
127.0.0.53:53 |
避免劫持 Pod→CoreDNS | Pod 内解析得真实 ClusterIP |
route-exclude-address |
无 | Service + Pod CIDR | 集群内流量绕过 TUN | 降低劫持与延迟 |
fake-ip-filter(曾尝试) |
无 / 不完整 | 不必依赖 | 无法根本解决 hijack | — |
已移除无效的
fake-ip-filter、nameserver-policy补丁,保持配置简洁。
部署步骤
备份:
sudo cp /etc/mihomo/config.yaml /etc/mihomo/config.yaml.bak.$(date +%Y%m%d%H%M%S)
写入配置后校验并重启:
sudo /usr/local/bin/mihomo -t -d /etc/mihomo && sudo systemctl restart mihomo
⚠️ 重启 mihomo 时 TUN 分流短暂中断 1~2 秒。
重启 Web:
kubectl rollout restart deployment zabbix-zabbix-web -n igo-zabbix
验证
Pod 内 DNS(核心验证):
sleep 3
kubectl exec -n igo-zabbix zabbix-postgresql-0 -- getent hosts zabbix-postgresql
预期:10.102.122.177 zabbix-postgresql...
全组件状态:
kubectl get pods -n igo-zabbix
预期:全部 1/1 或 2/2 Running,web 无 Restart。
Web 日志:
kubectl logs -n igo-zabbix -l app.kubernetes.io/name=zabbix-web --tail=20
预期:无 PostgreSQL server is not available。
后续预防
- K8s 节点禁止
dns-hijack: any:53,改用127.0.0.53:53仅劫持宿主机 DNS。 - 必须配置
route-exclude-address,覆盖 Service CIDR 与 Pod CIDR;CIDR 变更后同步更新。 - 部署 Zabbix 前做 DNS 冒烟测试:
kubectl exec -n igo-zabbix <任意 Running Pod> -- getent hosts zabbix-postgresql
若出现 198.18.x.x 或无输出,先修 mihomo 再部署应用。
- Service CIDR 非默认时,先确认再写入 exclude:
kubectl cluster-info dump 2>/dev/null | grep -m1 service-cluster-ip-range
- 文档参考:Ubuntu 20.04 Mihomo TUN 分流部署 — 适用于无 K8s 的纯服务器;K8s 节点需额外增加本文 exclude 与 dns-hijack 收窄。
附:初期 PostgreSQL Pending(已自愈)
| 阶段 | 现象 | 原因 |
|---|---|---|
| 初期 | zabbix-postgresql-0 Pending,PVC Pending |
local-path WaitForFirstConsumer,Pod 与 PVC 互相等待 |
| 中期 | 删除 PVC 后重建 | 短暂 FailedScheduling: pvc is being deleted |
| 后期 | PG 1/1 Running |
PVC 绑定完成,Pod 调度成功 |
PG Pending 与 Web 问题独立;Web 根因始终是 DNS fake-ip。
附录:覆盖完整配置
备份现有配置:
sudo cp /etc/mihomo/config.yaml /etc/mihomo/config.yaml.bak.$(date +%Y%m%d%H%M%S)
覆盖写入完整配置(K8s 节点适用版):
⚠️ 会覆盖
/etc/mihomo/config.yaml;写入后需重启 mihomo,TUN 分流短暂中断 1~2 秒。
sudo tee /etc/mihomo/config.yaml > /dev/null <<'EOF'
mixed-port: 7890
allow-lan: false
bind-address: '*'
mode: rule
log-level: info
ipv6: false
external-controller: 127.0.0.1:9090
tun:
enable: true
stack: system
auto-route: true
auto-detect-interface: true
route-exclude-address:
- 10.96.0.0/12
- 192.168.0.0/16
dns-hijack:
- 127.0.0.53:53
dns:
enable: true
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
respect-rules: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- 223.5.5.5
- 119.29.29.29
proxy-server-nameserver:
- 223.5.5.5
- 119.29.29.29
fallback:
- 8.8.8.8
- 1.1.1.1
fallback-filter:
geoip: true
geoip-code: CN
proxies:
- name: igoproxy
type: http
server: 10.80.238.40
port: 3128
proxy-groups:
- name: PROXY
type: select
proxies:
- igoproxy
- DIRECT
rules:
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- IP-CIDR,::1/128,DIRECT,no-resolve
- AND,((NETWORK,UDP),(DST-PORT,443)),REJECT
- DOMAIN-SUFFIX,cursor.com,DIRECT
- DOMAIN-SUFFIX,igozhang.cn,DIRECT
- DOMAIN-SUFFIX,igozhang.cc,DIRECT
- GEOIP,CN,DIRECT,no-resolve
- MATCH,PROXY
EOF
校验并重启:
sudo /usr/local/bin/mihomo -t -d /etc/mihomo && sudo systemctl restart mihomo