K8s学习笔记:03-踩坑记录与知识扩展
对应章节:第三章 Service 网络 / 3.1~3.7
日期:2026年7月13日
说明:本篇的坑全部来自本人实操时真实踩到的,比顺利通关更值得回看
坑 1:--rm 打成 00rm → 残留一个卡住的 test Pod
现象
1 | |
真相
第一条把 --rm 打成了 00rm(两个零)。kubectl 不认识 00rm 这个 flag,就把它当成要传给容器的普通参数,命令语义全乱,Pod 起不来卡住,最后 timed out。
关键点:**--rm 只在 Pod “正常退出”时才自动删。** 那个卡住的 test Pod 根本没跑起来,谈不上正常退出,于是残留在集群里,把 test 这个名字占住了。第二条命令名字冲突,才报 AlreadyExists。
解决
1 | |
附带诊断技巧:Pod 起不来卡住时,用
kubectl describe pod test | tail -20看最后的 Events,能看出到底卡在拉镜像、还是调度、还是网络。
坑 2:从宿主机直接 wget ClusterIP → 一直卡住(按 Ctrl+C 才停)
现象
在虚拟机的宿主 shell(root@bote798-ubuntu)里:
1 | |
真相
ClusterIP(10.96.x.x)是集群内部的虚拟 IP,只有集群里面的 Pod 能访问。 你在宿主 shell 里是”集群外”,连 ClusterIP 必然不通——卡住是设计如此,不是坏了。
而且第二条 ClusterIP:30935 是把两个东西拼错了:30935 这个 NodePort 端口是开在节点上的,不是开在 ClusterIP 上的。ClusterIP 上只有 80 端口。
三个地址各自的正确用法
| 想从哪访问 | 用什么地址 | 通不通 |
|---|---|---|
| 集群内部(busybox Pod 里) | my-nginx-np 或 ClusterIP:80 |
✓ |
| 集群外部(虚拟机 shell / 别的机器) | 节点IP:NodePort(如 172.18.0.2:30935) |
✓(Kind 见坑 3) |
| ClusterIP + NodePort 端口拼一起 | ClusterIP:30935 |
✗ 永远不通 |
记忆:ClusterIP 对内,NodePort 对外;NodePort 那个大端口只认节点 IP,不认 ClusterIP。
坑 3:Kind 里 NodePort 用哪个 IP?为什么物理机浏览器打不开
现象
1 | |
虚拟机 shell 里 172.18.0.2:30935 通了,但物理机(Windows)浏览器打开 192.168.40.133:30935 却打不开。
真相
Kind 的”节点”其实是一个 Docker 容器,它的 IP(172.18.0.2)属于 Docker 内网 172.18.0.0/16。
- 虚拟机自己和这个 Docker 网络直连,所以
172.18.0.2:30935通; - 出了虚拟机(物理机)就找不到 172.18.0.2 这个地址,所以浏览器打不开。
这就是讲义 3.5 说的 “Kind 的坑”:NodePort 在真实集群里物理机直接连节点 IP 就行,在 Kind 里节点藏在 Docker 内网,要多一步。(与第一章坑 3、坑 4 一脉相承:Kind 网络模型和真机有差异。)
补充:wget -qO- 172.18.0.2(不带端口)默认访问 80,而节点容器的 80 上没有服务(nginx 跑在 Pod 里不是跑在节点上),所以返回空。30935 是”门”,80 是”门后服务自己的端口”。
解决:port-forward 打隧道给物理机
1 | |
然后物理机浏览器打开 http://192.168.40.133:8080 即可。
--address 0.0.0.0是关键:默认 port-forward 只绑127.0.0.1(只有虚拟机自己能连),加了它才绑到所有网卡,物理机才连得进来。这正是第一章坑 4 的同一个道理。- 这个终端会前台占住(别 Ctrl+C),用完再按 Ctrl+C 停。
坑 4:nslookup 查到一堆 NXDOMAIN → 以为 DNS 坏了
现象
1 | |
真相(两层原因叠加)
第一层:Service 名字确实不存在了。 3.5 那步做过 kubectl delete svc my-nginx-svc 把 ClusterIP 版删了,改建成 NodePort 版叫 my-nginx-np。DNS 只解析当前真实存在的 Service,删掉的名字立刻从 DNS 消失,所以查 my-nginx-svc 返回 NXDOMAIN(域名不存在)。
第二层:那一片 NXDOMAIN 其实是”搜索域试错”,不是失败。 换成存在的名字再查:
1 | |
busybox 拿短名 my-nginx-np 按搜索域顺序挨个拼后缀去问 CoreDNS:
1 | |
只要中间出现一行 Name: / Address: 就是成功。 那些 NXDOMAIN 是拼错后缀的中间产物,nslookup 会把每次尝试都打出来,看着吓人其实正常。
关键认知
| 现象 | 含义 |
|---|---|
| 全是 NXDOMAIN,没有 Name/Address | 名字真的不存在(删了 / 拼错 / namespace 不对) |
| 夹着一行 Name/Address | 解析成功,其余 NXDOMAIN 是搜索域试错 |
Server: 10.96.0.10 有响应 |
CoreDNS 本身是活的,能查(能力正常) |
正确后缀 default.svc.cluster.local 的含义:<service名>.<namespace>.svc.cluster.local = “default 命名空间里名叫 xxx 的 Service”。
扩展知识:Service 删了重建,ClusterIP 会变吗?
会变。kubectl delete svc 再 expose,K8s 会从 Service 网段里重新分配一个 ClusterIP,通常和原来不同。所以:
- 删掉
my-nginx-svc(假设 10.96.200.94)重建成my-nginx-np,ClusterIP 变成了 10.96.150.223; - 这也再次印证了”别记 IP,记名字“——IP 会因为重建而变,DNS 名字只要 Service 名不变就稳定。
如果确实需要固定 ClusterIP,可以在 Service YAML 里显式写 spec.clusterIP: 10.96.x.x(但一般没必要,用名字就好)。
扩展知识:kube-proxy 是怎么把 ClusterIP”变”出来的
ClusterIP 是个虚拟 IP,集群里根本没有哪张网卡叫这个地址。它能通,是因为每台节点上的 kube-proxy 往内核里写了转发规则(iptables 或 ipvs):
1 | |
- 负载均衡就发生在这一步:规则里挂着多个后端 Pod IP,按概率/轮询挑一个。
- Endpoints(或 EndpointSlice)是这些规则的”数据源”——Pod 增减,Endpoints 更新,kube-proxy 立刻改写规则。这就是为什么 Pod IP 变了不要紧。
更深的数据流路径(DNAT/conntrack、CoreDNS 解析链、Kind 与真机差异)在同目录《辅助讲义-Service网络深度解析.md》里,想挖底层看那份。
本章核心认知回顾
1 | |