起因
最近在搭建Kubernetes集群时,我遇到了一个看似简单却令人困惑的问题:ClusterIP类型的Service可以通过IP访问,但域名解析却突然失败。作为新手,我曾以为这只是简单的配置错误,但排查过程却意外地“曲折”,也让我深刻体会到“细节决定成败”的道理。
问题复盘:DNS污染引发的连锁反应
现象很简单:nslookup
能解析Service的域名和IP,但curl通过域名访问时却返回“Empty reply”。通过DeepSeek的逐步引导,我意识到问题不在Kubernetes本身,而是节点的DNS配置被宿主机网络污染——Netplan中误将IP地址填入search字段,导致Pod的/etc/resolv.conf
被注入非法搜索域,最终引发解析混乱。
重点
为了让遇到同样问题的同学可以快速获得有用参考信息,这里快速概括,即
- Ubuntu Server 22.04系统安装后如何配置网络(配置IP等信息、禁用init-cloud)
-
创建
/etc/netplan/01-netcfg.yaml
文件(文件名可以自定义):network: renderer: networkd ethernets: enp0s5: addresses: - 10.211.55.52/24 nameservers: addresses: - 10.211.55.1 routes: - to: default via: 10.211.55.1 version: 2
文件内容不做过多解释,相信可以见名知意
-
根据已存在的
/etc/netplan/50-cloud-init.yaml
中的注释信息,# This file is generated from information provided by # the datasource. Changes to it will not persist across an instance. # To disable cloud-init's network configuration capabilities, write a file # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: # network: {config: disabled}
创建
/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
并写入:
network: {config: disabled}
-
删除
/etc/netplan/50-cloud-init.yaml
,执行netplan apply
使配置生效
我因为不熟悉netplan和cloud-init,想快速搭建起测试环境,遂直接上网找了大家的例子,其中有一个的配置有误,他将search也指向了网关的IP地址。我就按照错误的配置了,直到今天测试不成功,折腾了好久才发现
DeepSeek解决过程
以下是我向AI求助的过程,可以看到我几乎是以一个纯小白的语气在提问,他会一步步引导我解决问题👍
没有找到好的分享会话的办法,直接复制吧,各角色的发言我使用二级标题分开了
我:
在k8s集群内部测试访问一个ClusterIP类型的Service时,可以通过Service的服务IP访问,但是无法通过域名访问,以下是测试的过程,请分析问题名给出解决方案:
/ # nslookup -type=A demoapp-svc.test.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: demoapp-svc.test.svc.cluster.local
Address: 10.97.100.100
/ # curl 10.97.100.100
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.71, ServerName: demoapp-7c58cd6bb-txmlg, ServerIP: 10.244.2.77!
/ # curl 10.97.100.100
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.71, ServerName: demoapp-7c58cd6bb-nc44h, ServerIP: 10.244.4.29!
/ # curl 10.97.100.100
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.71, ServerName: demoapp-7c58cd6bb-knmn8, ServerIP: 10.244.4.28!
/ # curl 10.97.100.100
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.71, ServerName: demoapp-7c58cd6bb-7kfqj, ServerIP: 10.244.3.38!
/ # curl demoapp-svc.test.svc.cluster.local
curl: (52) Empty reply from server
AI:
问题分析
根据测试结果,域名解析正常(nslookup
成功返回 Service IP),且通过 ClusterIP 直接访问 Service 正常,但通过域名访问失败(Empty reply from server
)。这表明 DNS 解析和 Service 网络层通信正常,但应用层协议交互存在问题。可能的原因包括:
可能原因及解决方案
1. 应用协议与端口配置不匹配
- 现象: 当使用域名访问时,应用协议(如 HTTP/HTTPS)的交互可能因端口配置错误而失败。
- 检查:
- 确认 Service 的
targetPort
和 Pod 容器的containerPort
完全匹配。 - 确保 Service 定义的端口协议(如
TCP
)与 Pod 监听的协议一致。
- 确认 Service 的
- 修复:
# Service 示例片段 spec: ports: - name: http port: 80 protocol: TCP targetPort: 8080 # 必须与 Pod 的 containerPort 一致
2. 应用层协议不兼容域名访问
- 现象: 应用可能未正确处理域名请求中的
Host
头(如 HTTP 服务)或 TLS 的 SNI 扩展(如 HTTPS 服务)。 - 验证:
- 使用
curl -v
查看请求详细信息,检查Host
头是否传递正确:curl -v http://demoapp-svc.test.svc.cluster.local
- 如果输出显示
Host: demoapp-svc.test.svc.cluster.local
,但应用未配置处理该 Host,可能返回空响应。
- 使用
- 修复:
- 在应用代码中允许处理任意
Host
头。 - 或使用
curl
手动指定Host
头测试:curl -H "Host: dummy-host" demoapp-svc.test.svc.cluster.local
- 在应用代码中允许处理任意
3. Pod 就绪探针(Readiness Probe)配置错误
- 现象: 部分 Pod 未就绪,导致 Service 仅将流量转发到部分 Pod,而这些 Pod 可能存在异常。
- 检查:
- 查看 Pod 状态和就绪探针配置:
kubectl get pods -n test kubectl describe pod <pod-name> -n test
- 确保就绪探针的
path
和port
正确指向应用健康检查接口。
- 查看 Pod 状态和就绪探针配置:
- 修复:
# Pod 示例片段 readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10
4. 网络策略(NetworkPolicy)限制
- 现象: 网络策略可能限制仅允许通过 IP 访问,而未放行域名解析后的请求(可能性较低,但需排查)。
- 检查:
- 查看是否存在针对该 Service 或 Namespace 的网络策略:
kubectl get networkpolicy -n test
- 查看是否存在针对该 Service 或 Namespace 的网络策略:
- 修复:
- 调整网络策略,允许来自所有 Pod 的流量。
快速诊断步骤
-
使用
curl -v
查看详细请求:curl -v http://demoapp-svc.test.svc.cluster.local
- 观察输出中是否包含
Host
头、响应状态码和 Server 头。
- 观察输出中是否包含
-
直接指定 Host 头测试:
curl -H "Host: demoapp-svc.test.svc.cluster.local" 10.97.100.100
- 如果成功,说明应用依赖
Host
头,需调整应用配置。
- 如果成功,说明应用依赖
-
检查 Service 和 Endpoints:
kubectl describe svc demoapp-svc -n test kubectl get endpoints demoapp-svc -n test
- 确认 Endpoints 列表包含所有预期的 Pod IP。
-
检查 Pod 日志:
kubectl logs <pod-name> -n test
- 观察通过域名访问时是否有请求到达 Pod。
总结建议
优先排查应用层协议问题(如 Host
头处理),其次是 Service 端口配置。通过 curl -v
和 Pod 日志可快速定位问题根源。如果问题仍无法解决,提供 Service
、Pod
定义及 curl -v
输出可进一步分析。
我:
使用curl -v的结果如下:
* Trying 198.18.17.99:80...
* Connected to demoapp-svc.test.svc.cluster.local (198.18.17.99) port 80 (#0)
> GET / HTTP/1.1
> Host: demoapp-svc.test.svc.cluster.local
> User-Agent: curl/7.79.1
> Accept: */*
>
* Empty reply from server
* Closing connection 0
curl: (52) Empty reply from server
这里的198.18.17.99IP地址是什么?
AI:
问题定位:DNS 解析异常导致域名指向错误 IP
根据 curl -v
输出,域名 demoapp-svc.test.svc.cluster.local
被解析到 198.18.17.99
,但该地址 不属于 Kubernetes 集群的 Service CIDR 范围(如默认的 10.96.0.0/12
)。这表明存在 DNS 解析错误 或 Service 配置错误。
原因分析
-
Service 类型或配置错误
- 若
demoapp-svc
被误配置为ExternalName
类型,或引用了外部端点,可能导致解析到集群外 IP。 - 验证 Service 类型:
kubectl get svc demoapp-svc -n test -o yaml
- 预期输出类型应为
ClusterIP
,且spec.clusterIP
应与之前的正确 IP(10.97.100.100
)一致。
- 预期输出类型应为
- 若
-
DNS 污染或缓存问题
- 测试容器可能缓存了旧 DNS 记录,或
/etc/hosts
文件被修改,强制将域名映射到198.18.17.99
。 - 检查 DNS 解析来源:
# 进入测试容器执行 cat /etc/resolv.conf # 确认 DNS 服务器是否为集群 DNS(如 10.96.0.10) cat /etc/hosts # 检查是否有手动绑定的记录 nslookup demoapp-svc.test.svc.cluster.local 10.96.0.10 # 强制指定集群 DNS 查询
- 测试容器可能缓存了旧 DNS 记录,或
-
集群 DNS 服务异常
- CoreDNS 或 kube-dns 可能因配置错误、资源不足或网络策略拦截,返回了错误结果。
- 检查 CoreDNS 日志:
kubectl logs -l k8s-app=kube-dns -n kube-system --tail=100
-
网络插件或 CNI 配置错误
- 网络插件(如 Calico、Flannel)可能错误地分配了 Service IP 范围,或路由规则异常。
解决方案
1. 修正 Service 配置
- 如果 Service 类型或
spec.clusterIP
异常,重新创建 Service:kubectl delete svc demoapp-svc -n test kubectl apply -f demoapp-svc.yaml # 确保 YAML 中类型为 ClusterIP
2. 清理 DNS 缓存
- 在测试容器中刷新 DNS 缓存(若容器 OS 支持):
# 例如,Alpine Linux 可使用以下命令 killall -HUP dnsmasq # 或重启 DNS 服务
3. 验证集群 DNS 服务
- 执行临时 DNS 查询测试:
kubectl run -it --rm --restart=Never dns-test --image=alpine:3.13 -n test \ -- sh -c 'nslookup demoapp-svc.test.svc.cluster.local 10.96.0.10'
- 预期应返回正确的 ClusterIP(
10.97.100.100
)。
4. 检查 Service CIDR 配置
- 确认集群的 Service CIDR 范围(如
10.96.0.0/12
):kubectl cluster-info dump | grep -i service-cluster-ip-range
- 若
198.18.17.99
不在该范围内,说明解析结果异常,需排查 DNS 污染或网络插件配置。
5. 排查网络策略
- 检查是否存在 NetworkPolicy 拦截 DNS 查询或 Service 流量:
kubectl get networkpolicy -n test
关键结论
异常 IP 198.18.17.99
是 DNS 解析错误的直接表现,需逐步排查 Service 定义、集群 DNS 服务、网络插件及容器环境配置。优先通过强制指定集群 DNS(10.96.0.10
)验证解析结果,缩小问题范围。
我:
我在/etc/resolv.conf中发现了可疑问题:
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local 10.211.55.1
options ndots:5
我需要说明一下测试环境:macOS下通过Parallels Desktop安装了5个Ubuntu Server 22.04虚拟机进行测试,2个master,3个worker,而上面resolv.conf 文件中的10.211.55.1是我Parallels Desktop中配置的虚拟机网关,是宿主机(我的macOS系统)的一个IP
AI:
问题根源分析
根据你的描述,/etc/resolv.conf
中的 search
字段被错误地注入了宿主机的网关 IP 10.211.55.1
,这导致 DNS 查询路径被污染。Kubernetes 集群的 DNS 解析依赖 search
字段中的域名后缀(如 svc.cluster.local
、cluster.local
)来自动补全服务名称,但 10.211.55.1
是一个无效的搜索域,它会触发 DNS 解析异常。以下是具体分析:
关键问题
-
无效的搜索域
10.211.55.1
search
字段中的10.211.55.1
是一个 IP 地址,而非合法的域名后缀。当 Pod 尝试解析demoapp-svc.test.svc.cluster.local
时,DNS 客户端会依次尝试以下查询:demoapp-svc.test.svc.cluster.local.default.svc.cluster.local demoapp-svc.test.svc.cluster.local.svc.cluster.local demoapp-svc.test.svc.cluster.local.cluster.local demoapp-svc.test.svc.cluster.local.10.211.55.1 # 无效的查询
- 最终由于无效的查询,可能回退到宿主机网络 DNS,导致解析到外部 IP
198.18.17.99
(如宿主机网关或外部 DNS 的缓存结果)。
-
Parallels Desktop 网络配置干扰
- 虚拟机通过 Parallels Desktop 的 NAT 或共享网络模式启动时,DHCP 服务可能自动修改了
/etc/resolv.conf
,注入了宿主机的 DNS 配置(如网关 IP),与 Kubernetes 集群的 DNS 产生冲突。
- 虚拟机通过 Parallels Desktop 的 NAT 或共享网络模式启动时,DHCP 服务可能自动修改了
解决方案
1. 修复 Pod 的 DNS 配置
Kubernetes 默认通过 dnsPolicy: ClusterFirst
为 Pod 注入集群 DNS 配置,但虚拟机层面的 DHCP 或网络管理工具(如 systemd-resolved
)可能覆盖了 /etc/resolv.conf
。需在 虚拟机节点 上执行以下操作:
步骤 1: 禁用 Parallels Desktop 的 DNS 注入
- 编辑 Parallels Desktop 的虚拟机网络配置,关闭 DHCP 的 DNS 自动推送功能(具体路径:虚拟机配置 > 硬件 > 网络 > 高级设置)。
- 或切换虚拟机网络模式为 Bridged(桥接模式),避免 NAT 模式下的 DNS 干扰。
步骤 2: 锁定虚拟机的 /etc/resolv.conf
- 在 Ubuntu 虚拟机上,禁止 DHCP 修改
/etc/resolv.conf
:# 停止并禁用 systemd-resolved sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved # 手动配置 DNS sudo rm /etc/resolv.conf # 删除符号链接 sudo tee /etc/resolv.conf <<EOF nameserver 10.96.0.10 # 集群 DNS(CoreDNS) search svc.cluster.local cluster.local # 仅保留 Kubernetes 相关搜索域 options ndots:5 EOF
- 重启虚拟机节点 使配置生效。
2. 修复 Kubernetes 集群 DNS 配置
确保 CoreDNS 配置正确,避免搜索域污染:
检查 CoreDNS 配置
kubectl -n kube-system get configmap coredns -o yaml
- 预期输出应包含 Kubernetes 集群域配置:
Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { # 确保域名匹配 pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf # 确保外部查询转发正确 cache 30 loop reload loadbalance }
修复 Service 域名解析
如果问题仅存在于特定 Pod,可临时修改 Pod 的 dnsConfig
覆盖搜索域:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- 10.96.0.10
searches:
- test.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "5"
3. 验证修复结果
在修复后的 Pod 中执行:
# 检查 /etc/resolv.conf 是否已修正
cat /etc/resolv.conf
# 执行 DNS 解析测试
nslookup demoapp-svc.test.svc.cluster.local
# 再次通过域名访问 Service
curl -v http://demoapp-svc.test.svc.cluster.local
预期结果:
nslookup
返回正确的 ClusterIP(如10.97.100.100
)。curl
能正常获取响应,不再出现Empty reply
。
总结
根本原因是 虚拟机网络配置(Parallels Desktop DHCP)污染了 Pod 的 DNS 搜索域,导致集群内域名解析被错误转发到宿主机网络。通过修复虚拟机的 DNS 配置并锁定 /etc/resolv.conf
,可确保 Kubernetes 集群 DNS 的隔离性。若问题仍存在,可进一步检查 CoreDNS 日志和 Service 定义。
我:
这5个ubuntu系统使用了Parallels Desktop中的共享网络模式,但是并没有使用dhcp,而是我手动配置的ip地址与网关、DNS信息,我将网关和DNS指向了10.211.55.1,这样便于固定下他们各自的IP地址便于我测试,但是我的疑问是,在k8s集群中创建的Pod,为什么他们的/etc/resolv.conf中会有"search default.svc.cluster.local svc.cluster.local cluster.local 10.211.55.1"这行信息呢
AI:
原因解析
在 Kubernetes 集群中,Pod 的 /etc/resolv.conf
文件由 kubelet 根据集群 DNS 策略(dnsPolicy
)和节点的 /etc/resolv.conf
生成。你观察到的 search default.svc.cluster.local svc.cluster.local cluster.local 10.211.55.1
中的 10.211.55.1
是宿主机网关 IP,它的出现是由于以下原因:
1. 节点(Ubuntu 虚拟机)的 /etc/resolv.conf
被污染
- 虽然你手动配置了节点的静态 IP 和网关,但 Ubuntu 的 网络管理服务(如
systemd-resolved
或Netplan
)可能仍然会修改/etc/resolv.conf
,注入search 10.211.55.1
。 - 验证节点本身的
/etc/resolv.conf
:
如果输出包含# 在任意节点上执行 cat /etc/resolv.conf
search ... 10.211.55.1
,说明节点的 DNS 配置已被污染。
2. kubelet 错误继承节点的 DNS 配置
- 默认情况下,kubelet 使用节点的
/etc/resolv.conf
作为模板生成 Pod 的 DNS 配置(尤其是search
字段)。 - 当节点的
/etc/resolv.conf
包含search 10.211.55.1
时,kubelet 会将其合并到 Pod 的search
域中,导致污染。
3. kubelet 的 --resolv-conf
参数未正确配置
- kubelet 有一个关键参数
--resolv-conf
,用于指定生成 Pod DNS 配置时使用的resolv.conf
文件路径。 - 如果未显式配置,kubelet 默认使用
/etc/resolv.conf
,导致继承节点的污染配置。 - 检查 kubelet 配置:
如果输出中未显示# 在节点上执行 ps aux | grep kubelet | grep resolv-conf
--resolv-conf=/run/systemd/resolve/resolv.conf
,则说明配置有误。
解决方案
步骤 1:修复节点的 /etc/resolv.conf
在 每个节点 上执行以下操作,确保节点的 DNS 配置纯净:
-
禁用自动 DNS 修改
编辑 Netplan 配置文件(如/etc/netplan/00-installer-config.yaml
):network: version: 2 ethernets: eth0: addresses: [10.211.55.x/24] # 你的静态 IP gateway4: 10.211.55.1 nameservers: addresses: [10.211.55.1] # 这里仅配置 nameserver,不设置 search 域 routes: - to: default via: 10.211.55.1
- 关键点:不要在 Netplan 中配置
search
字段,避免污染 DNS。
- 关键点:不要在 Netplan 中配置
-
强制锁定
/etc/resolv.conf
sudo rm /etc/resolv.conf sudo tee /etc/resolv.conf <<EOF nameserver 10.96.0.10 # 指向集群 DNS(CoreDNS) search svc.cluster.local cluster.local # 仅保留 Kubernetes 相关搜索域 options ndots:5 EOF sudo chattr +i /etc/resolv.conf # 设置为不可修改(谨慎操作)
步骤 2:修正 kubelet 的 --resolv-conf
参数
在 每个节点 上修改 kubelet 配置,确保其使用独立的 DNS 配置:
-
编辑 kubelet 服务文件
sudo systemctl edit kubelet
在打开的编辑器中添加以下内容:
[Service] Environment="KUBELET_RESOLV_CONF=--resolv-conf=/run/k8s-resolv.conf" ExecStartPre=/bin/bash -c 'echo "nameserver 10.96.0.10\nsearch svc.cluster.local cluster.local\noptions ndots:5" > /run/k8s-resolv.conf'
- 创建一个干净的
/run/k8s-resolv.conf
,供 kubelet 专用。
- 创建一个干净的
-
重启 kubelet
sudo systemctl daemon-reload sudo systemctl restart kubelet
步骤 3:验证 Pod 的 DNS 配置
重新创建测试 Pod 并检查其 /etc/resolv.conf
:
kubectl run -it --rm --restart=Never test-pod --image=alpine:3.13 -- sh
cat /etc/resolv.conf
预期输出应仅包含集群 DNS 配置,无 10.211.55.1
:
nameserver 10.96.0.10
search test.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
总结
问题的根源是 节点的 DNS 配置污染被 kubelet 继承到了 Pod。通过以下两步彻底修复:
- 清理节点的 DNS 配置,避免
search
字段包含外部 IP。 - 隔离 kubelet 的 DNS 配置,使其使用独立的
resolv.conf
,与节点环境解耦。
此方案可确保 Pod 的 DNS 解析完全受 Kubernetes 控制,避免宿主机网络配置的干扰。
我:
通过ps aux | grep kubelet | grep resolv-conf
检查了kubelet参数,命令输出为空,证明kubelet配配置无误,但是节点的resolv.conf
确实有错误,以下是我在其中一个节点中的数据:
我的/etc/resolv.conf
:
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 127.0.0.53
options edns0 trust-ad
search 10.211.55.1
我的/etc/netplan/01-netcfg.yaml
:
network:
renderer: networkd
ethernets:
enp0s5:
addresses:
- 10.211.55.61/24
nameservers:
addresses:
- 10.211.55.1
search:
- 10.211.55.1
routes:
- to: default
via: 10.211.55.1
version: 2
我认为netplan配置应该也没问题。另外需要补充的是,在安装这五个Ubuntu操作系统时,默认存在/etc/netplan/50-cloud-init.yaml
文件,其中有如下的注释信息:
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
我按照注释将其删除了,并且创建了/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
并写入了注释中说明的内容network: {config: disabled}
此外,还创建了/etc/netplan/01-netcfg.yaml
进行静态IP配置,其他没有修改了,是不是我在这里做网络配置的时候遗漏了某些步骤导致节点的resolve.conf
不正确呢?
AI:
根本原因分析
问题出在 Netplan 配置中的 nameservers.search
字段被错误地设置为 IP 地址 10.211.55.1
,而 search
字段本应接收的是 域名后缀(如 cluster.local
)。这一配置导致 systemd-resolved
在生成 /etc/resolv.conf
时,将 search 10.211.55.1
注入到 DNS 搜索域中,进而污染了 Kubernetes Pod 的 DNS 解析。
详细修复步骤
1. 修正 Netplan 配置
编辑 /etc/netplan/01-netcfg.yaml
,删除 nameservers.search
中的无效 IP 地址,并仅保留必要的 DNS 配置:
network:
renderer: networkd
ethernets:
enp0s5:
addresses:
- 10.211.55.61/24
nameservers:
addresses:
- 10.211.55.1 # 指定 DNS 服务器 IP(Parallels 网关)
# 删除 search 字段(关键修复点!)
routes:
- to: default
via: 10.211.55.1
version: 2
2. 应用新的 Netplan 配置
sudo netplan apply
3. 强制刷新 systemd-resolved 配置
# 重启 systemd-resolved 服务
sudo systemctl restart systemd-resolved
# 查看解析状态,确保 search 域为空或仅包含合法域名
resolvectl status
4. 验证节点的 /etc/resolv.conf
cat /etc/resolv.conf
预期输出(不应包含 search 10.211.55.1
):
nameserver 127.0.0.53
options edns0 trust-ad
# search 字段应为空或仅包含合法域名
补充说明
1. 为何 Netplan 的 search
字段会导致问题?
nameservers.search
的用途是为非完全限定域名(如demoapp-svc
)自动添加后缀(如demoapp-svc.cluster.local
)。- 当
search
被设置为 IP 地址时,DNS 客户端会尝试将服务名解析为demoapp-svc.10.211.55.1
,这显然是非法的,导致解析失败或污染。
2. 为何 systemd-resolved
会生成错误的 search
域?
- Netplan 将配置转换为
systemd-networkd
规则时,错误地将nameservers.search: 10.211.55.1
传递给了systemd-resolved
。 systemd-resolved
无条件接受该配置,导致/etc/resolv.conf
被污染。
3. 为何删除 search
字段是安全的?
- Kubernetes 集群内的服务解析依赖 CoreDNS 自动处理域名后缀(如
.svc.cluster.local
),无需手动配置search
。 - 外部域名解析(如
google.com
)可通过节点的 DNS 服务器(10.211.55.1
)直接完成,无需搜索域。
验证修复效果
-
在节点上测试 DNS 解析:
# 解析集群内服务 nslookup demoapp-svc.test.svc.cluster.local # 解析外部域名 nslookup google.com
-
在 Pod 内检查
/etc/resolv.conf
:kubectl run -it --rm --restart=Never test-pod --image=alpine:3.13 -- sh cat /etc/resolv.conf
预期输出:
nameserver 10.96.0.10 search test.svc.cluster.local svc.cluster.local cluster.local options ndots:5
最终建议
- 在所有节点上统一修复 Netplan 配置,确保无
search
字段污染。 - 如果仍需自定义搜索域,可合法域名(如
internal.example.com
)而非 IP 地址。 - 若问题仍存在,检查
systemd-resolved
的完整配置:resolvectl domain resolvectl dns
我:
所有节点都已经修复该问题,如何更新pod,使其可以正确解析service呢
AI:
在 Kubernetes 中,Pod 的 DNS 配置在创建时由 kubelet 根据节点配置生成。如果节点已修复 DNS 问题,但现有 Pod 仍然使用旧的 DNS 配置,你需要 重建 Pod 以触发 DNS 配置更新。以下是具体操作步骤:
方法 1:直接删除 Pod(适用于由控制器管理的 Pod)
如果 Pod 由 Deployment、StatefulSet、DaemonSet 等控制器管理,删除 Pod 后控制器会自动重建新的 Pod,新 Pod 会使用修复后的 DNS 配置。
操作步骤:
-
列出所有受影响的 Pod:
kubectl get pods -n <namespace> -o wide
-
删除旧 Pod:
kubectl delete pod <pod-name> -n <namespace>
- 示例(删除命名空间
test
下所有 Pod):kubectl delete pods --all -n test
- 示例(删除命名空间
-
等待控制器自动重建 Pod:
kubectl get pods -n <namespace> -w
-
验证新 Pod 的 DNS 配置:
kubectl exec -it <new-pod-name> -n <namespace> -- cat /etc/resolv.conf
- 预期输出(已无
10.211.55.1
):nameserver 10.96.0.10 search test.svc.cluster.local svc.cluster.local cluster.local options ndots:5
- 预期输出(已无
方法 2:滚动重启控制器(推荐)
通过触发控制器的滚动重启(如 Deployment),可以优雅地重建所有关联的 Pod,避免服务中断。
操作步骤:
-
滚动重启 Deployment:
kubectl rollout restart deployment/<deployment-name> -n <namespace>
-
验证滚动重启状态:
kubectl rollout status deployment/<deployment-name> -n <namespace>
-
确认新 Pod 的 DNS 配置:
kubectl exec -it <new-pod-name> -n <namespace> -- nslookup demoapp-svc.test.svc.cluster.local
- 预期输出应显示正确的 Service ClusterIP(如
10.97.100.100
)。
- 预期输出应显示正确的 Service ClusterIP(如
方法 3:强制更新 Pod 注解(适用于独立 Pod)
如果 Pod 是独立创建的(无控制器管理),可通过修改注解强制触发更新(本质是删除重建):
kubectl patch pod <pod-name> -n <namespace> -p '{"metadata":{"annotations":{"force-restart":"'$(date +%s)'"}}}'
验证 DNS 解析
无论使用哪种方法,最终需验证 Pod 的 DNS 解析是否正常:
-
进入新 Pod 执行测试:
kubectl exec -it <new-pod-name> -n <namespace> -- sh
-
解析 Service 域名:
nslookup demoapp-svc.test.svc.cluster.local # 或 curl -v http://demoapp-svc.test.svc.cluster.local
关键总结
- 根本逻辑:Pod 的 DNS 配置在创建时固化,需重建 Pod 以应用新的节点 DNS 配置。
- 推荐操作:优先使用 滚动重启控制器(如
kubectl rollout restart
),确保服务不中断。 - 例外处理:若 Pod 无控制器管理,直接删除或通过注解触发重建。
总结
这次经历让我对DeepSeek的能力刮目相看。它不仅快速定位到search字段配置错误这一核心问题,还给出了从Netplan修正到Pod重建的全链路解决方案。更难得的是,DeepSeek的回答始终紧扣上下文:
- 精准分析:结合resolv.conf和netplan配置,直接指出“IP作为搜索域”的荒谬之处
- 实操指导:提供netplan apply、systemd-resolved重启等具体命令,避免我盲目操作
- 延伸思考:提醒我检查所有节点、验证Pod重建逻辑,培养系统化排查思维
这次踩坑让我明白,云原生技术的复杂性不仅在于架构,更在于对底层细节的掌控。一个小小的IP字段,竟能让整个集群“翻车”
保持好奇心:不放过任何异常日志,哪怕它看起来“无关紧要”
善用工具:像DeepSeek这样的AI助手,能快速将问题抽象为知识盲点,节省大量搜索时间
敬畏基础:网络、DNS等基础知识永远是运维的“地基”,必须扎实掌握