K8s学习笔记:03-踩坑记录与知识扩展

对应章节:第三章 Service 网络 / 3.1~3.7
日期:2026年7月13日
说明:本篇的坑全部来自本人实操时真实踩到的,比顺利通关更值得回看


坑 1:--rm 打成 00rm → 残留一个卡住的 test Pod

现象

1
2
3
4
5
6
kubectl run test 00rm -it --image=busybox:1.36 --restart=Never -- sh
# error: timed out waiting for the condition

# 改对了重敲,又报:
kubectl run test --rm -it --image=busybox:1.36 --restart=Never -- sh
# Error from server (AlreadyExists): pods "test" already exists

真相

第一条把 --rm 打成了 00rm(两个零)。kubectl 不认识 00rm 这个 flag,就把它当成要传给容器的普通参数,命令语义全乱,Pod 起不来卡住,最后 timed out

关键点:**--rm 只在 Pod “正常退出”时才自动删。** 那个卡住的 test Pod 根本没跑起来,谈不上正常退出,于是残留在集群里,把 test 这个名字占住了。第二条命令名字冲突,才报 AlreadyExists

解决

1
2
3
4
kubectl delete pod test      # 手动删掉残留
kubectl get pods # 确认没了
# 再重新起,--rm 别打错
kubectl run test --rm -it --image=busybox:1.36 --restart=Never -- sh

附带诊断技巧:Pod 起不来卡住时,用 kubectl describe pod test | tail -20 看最后的 Events,能看出到底卡在拉镜像、还是调度、还是网络。


坑 2:从宿主机直接 wget ClusterIP → 一直卡住(按 Ctrl+C 才停)

现象

在虚拟机的宿主 shell(root@bote798-ubuntu)里:

1
2
wget -qO- 10.96.150.223          # 卡住,^C
wget -qO- 10.96.150.223:30935 # 卡住,^C

真相

ClusterIP(10.96.x.x)是集群内部的虚拟 IP,只有集群里面的 Pod 能访问。 你在宿主 shell 里是”集群外”,连 ClusterIP 必然不通——卡住是设计如此,不是坏了。

而且第二条 ClusterIP:30935 是把两个东西拼错了:30935 这个 NodePort 端口是开在节点上的,不是开在 ClusterIP 上的。ClusterIP 上只有 80 端口。

三个地址各自的正确用法

想从哪访问 用什么地址 通不通
集群内部(busybox Pod 里) my-nginx-npClusterIP: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
2
3
4
5
kubectl get nodes -o wide
# INTERNAL-IP = 172.18.0.2 ← 节点 IP 是个 172.x 的 Docker 内网地址

wget -qO- 172.18.0.2 # 空(80 端口没服务)
wget -qO- 172.18.0.2:30935 # ✓ 返回 nginx 页

虚拟机 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
2
3
kubectl port-forward svc/my-nginx-np 8080:80 --address 0.0.0.0
# Forwarding from 0.0.0.0:8080 -> 80
# Handling connection for 8080 ← 每来一个请求打一行,证明流量真进来了

然后物理机浏览器打开 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
2
3
4
5
nslookup my-nginx-svc
# ** server can't find my-nginx-svc.cluster.local: NXDOMAIN
# ** server can't find my-nginx-svc.svc.cluster.local: NXDOMAIN
# ** server can't find my-nginx-svc.default.svc.cluster.local: NXDOMAIN
# ...一片红

真相(两层原因叠加)

第一层:Service 名字确实不存在了。 3.5 那步做过 kubectl delete svc my-nginx-svc 把 ClusterIP 版删了,改建成 NodePort 版叫 my-nginx-np。DNS 只解析当前真实存在的 Service,删掉的名字立刻从 DNS 消失,所以查 my-nginx-svc 返回 NXDOMAIN(域名不存在)。

第二层:那一片 NXDOMAIN 其实是”搜索域试错”,不是失败。 换成存在的名字再查:

1
2
3
4
5
nslookup my-nginx-np
# ** server can't find my-nginx-np.cluster.local: NXDOMAIN ← 后缀不对,试错
# Name: my-nginx-np.default.svc.cluster.local
# Address: 10.96.150.223 ← 成功!
# ** server can't find my-nginx-np.svc.cluster.local: NXDOMAIN ← 后缀不对,试错

busybox 拿短名 my-nginx-np 按搜索域顺序挨个拼后缀去问 CoreDNS:

1
2
3
my-nginx-np.cluster.local              → 查不到(后缀不对)
my-nginx-np.default.svc.cluster.local → 查到了!10.96.150.223
my-nginx-np.svc.cluster.local → 查不到(后缀不对)

只要中间出现一行 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 svcexpose,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
2
3
4
访问 ClusterIP:80
→ 内核 iptables/ipvs 规则命中
→ DNAT 改写目标地址为某个后端 Pod IP
→ 转发到该 Pod:80
  • 负载均衡就发生在这一步:规则里挂着多个后端 Pod IP,按概率/轮询挑一个。
  • Endpoints(或 EndpointSlice)是这些规则的”数据源”——Pod 增减,Endpoints 更新,kube-proxy 立刻改写规则。这就是为什么 Pod IP 变了不要紧。

更深的数据流路径(DNAT/conntrack、CoreDNS 解析链、Kind 与真机差异)在同目录《辅助讲义-Service网络深度解析.md》里,想挖底层看那份。


本章核心认知回顾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Service = 一组 Pod 的稳定入口(固定 ClusterIP + DNS 名字)

kube-proxy 在每台节点写 iptables/ipvs 规则做转发 + 负载均衡

Endpoints 实时记录"当前匹配的 Pod IP 列表",Pod 增减自动更新

后端 Pod(IP 随便变,牛不是宠物)

三种访问方式:
- ClusterIP 对内,集群里 Pod 用名字/虚拟IP 访问
- NodePort 对外,节点IP:3xxxx(Kind 里节点是 Docker 容器,要 port-forward 补一步)
- port-forward kubectl 打的临时隧道,--address 0.0.0.0 才能让别的机器连

DNS 服务发现:<service>.<namespace>.svc.cluster.local
代码里写服务名,永远不写 IP —— 这是微服务互调的根基

K8s学习笔记:03-踩坑记录与知识扩展
https://bote798.top/2026/07/13/K8s学习笔记-03-踩坑记录与知识扩展/
作者
bote798
发布于
2026年7月13日
更新于
2026年7月16日
许可协议