记一次菜鸡偷懒付出的代价,以及感叹AI的强大

起因

最近在搭建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)
  1. 创建/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
    

    文件内容不做过多解释,相信可以见名知意

  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}

  3. 删除/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 示例片段
    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
      
    • 确保就绪探针的 pathport 正确指向应用健康检查接口。
  • 修复:
    # Pod 示例片段
    readinessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    

4. 网络策略(NetworkPolicy)限制
  • 现象: 网络策略可能限制仅允许通过 IP 访问,而未放行域名解析后的请求(可能性较低,但需排查)。
  • 检查:
    • 查看是否存在针对该 Service 或 Namespace 的网络策略:
      kubectl get networkpolicy -n test
      
  • 修复:
    • 调整网络策略,允许来自所有 Pod 的流量。

快速诊断步骤

  1. 使用 curl -v 查看详细请求:

    curl -v http://demoapp-svc.test.svc.cluster.local
    
    • 观察输出中是否包含 Host 头、响应状态码和 Server 头。
  2. 直接指定 Host 头测试:

    curl -H "Host: demoapp-svc.test.svc.cluster.local" 10.97.100.100
    
    • 如果成功,说明应用依赖 Host 头,需调整应用配置。
  3. 检查 Service 和 Endpoints:

    kubectl describe svc demoapp-svc -n test
    kubectl get endpoints demoapp-svc -n test
    
    • 确认 Endpoints 列表包含所有预期的 Pod IP。
  4. 检查 Pod 日志:

    kubectl logs <pod-name> -n test
    
    • 观察通过域名访问时是否有请求到达 Pod。

总结建议

优先排查应用层协议问题(如 Host 头处理),其次是 Service 端口配置。通过 curl -v 和 Pod 日志可快速定位问题根源。如果问题仍无法解决,提供 ServicePod 定义及 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 配置错误


原因分析

  1. Service 类型或配置错误

    • demoapp-svc 被误配置为 ExternalName 类型,或引用了外部端点,可能导致解析到集群外 IP。
    • 验证 Service 类型
      kubectl get svc demoapp-svc -n test -o yaml
      
      • 预期输出类型应为 ClusterIP,且 spec.clusterIP 应与之前的正确 IP(10.97.100.100)一致。
  2. 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 查询
      
  3. 集群 DNS 服务异常

    • CoreDNS 或 kube-dns 可能因配置错误、资源不足或网络策略拦截,返回了错误结果。
    • 检查 CoreDNS 日志
      kubectl logs -l k8s-app=kube-dns -n kube-system --tail=100
      
  4. 网络插件或 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.localcluster.local)来自动补全服务名称,但 10.211.55.1 是一个无效的搜索域,它会触发 DNS 解析异常。以下是具体分析:


关键问题

  1. 无效的搜索域 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 的缓存结果)。
  2. Parallels Desktop 网络配置干扰

    • 虚拟机通过 Parallels Desktop 的 NAT 或共享网络模式启动时,DHCP 服务可能自动修改了 /etc/resolv.conf,注入了宿主机的 DNS 配置(如网关 IP),与 Kubernetes 集群的 DNS 产生冲突。

解决方案

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-resolvedNetplan)可能仍然会修改 /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 配置纯净:

  1. 禁用自动 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。
  2. 强制锁定 /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 配置:

  1. 编辑 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 专用。
  2. 重启 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。通过以下两步彻底修复:

  1. 清理节点的 DNS 配置,避免 search 字段包含外部 IP。
  2. 隔离 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)直接完成,无需搜索域。

验证修复效果

  1. 在节点上测试 DNS 解析

    # 解析集群内服务
    nslookup demoapp-svc.test.svc.cluster.local
    
    # 解析外部域名
    nslookup google.com
    
  2. 在 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
    

最终建议

  1. 在所有节点上统一修复 Netplan 配置,确保无 search 字段污染。
  2. 如果仍需自定义搜索域,可合法域名(如 internal.example.com)而非 IP 地址。
  3. 若问题仍存在,检查 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 配置。

操作步骤:
  1. 列出所有受影响的 Pod

    kubectl get pods -n <namespace> -o wide
    
  2. 删除旧 Pod

    kubectl delete pod <pod-name> -n <namespace>
    
    • 示例(删除命名空间 test 下所有 Pod):
      kubectl delete pods --all -n test
      
  3. 等待控制器自动重建 Pod

    kubectl get pods -n <namespace> -w
    
  4. 验证新 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,避免服务中断。

操作步骤:
  1. 滚动重启 Deployment

    kubectl rollout restart deployment/<deployment-name> -n <namespace>
    
  2. 验证滚动重启状态

    kubectl rollout status deployment/<deployment-name> -n <namespace>
    
  3. 确认新 Pod 的 DNS 配置

    kubectl exec -it <new-pod-name> -n <namespace> -- nslookup demoapp-svc.test.svc.cluster.local
    
    • 预期输出应显示正确的 Service ClusterIP(如 10.97.100.100)。

方法 3:强制更新 Pod 注解(适用于独立 Pod)

如果 Pod 是独立创建的(无控制器管理),可通过修改注解强制触发更新(本质是删除重建):

kubectl patch pod <pod-name> -n <namespace> -p '{"metadata":{"annotations":{"force-restart":"'$(date +%s)'"}}}'

验证 DNS 解析

无论使用哪种方法,最终需验证 Pod 的 DNS 解析是否正常:

  1. 进入新 Pod 执行测试

    kubectl exec -it <new-pod-name> -n <namespace> -- sh
    
  2. 解析 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等基础知识永远是运维的“地基”,必须扎实掌握

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brahming

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值