实验基线:Kubernetes v1.37.0、kubectl v1.37.0。先在测试环境执行,记录变更前状态与回滚点;生产集群不得直接照抄节点地址、网段、存储类或资源额度。
从 EndpointSlice 开始理解 Service
Service 通过标签选择后端 Pod,控制器生成 EndpointSlice,数据面组件据此转发。Service 可用但访问失败时,要依次检查 selector、Pod Ready、EndpointSlice、端口映射和网络策略。
kubectl expose deployment web -n lab --port=80 --target-port=80
kubectl get service web -n lab -o wide
kubectl get endpointslice -n lab -l kubernetes.io/service-name=web
kubectl run curl -n lab --rm -it --restart=Never --image=curlimages/curl -- \
curl -fsS http://web.lab.svc.cluster.local
DNS 排障顺序
kubectl exec -n lab <client-pod> -- cat /etc/resolv.conf
kubectl exec -n lab <client-pod> -- nslookup web.lab.svc.cluster.local
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100先验证完整域名,再验证短名称;跨命名空间应显式写 service.namespace。Ingress 资源只有安装对应控制器后才生效;新项目也可评估 Gateway API,但控制器实现仍是必要条件。
默认拒绝与 DNS 放行
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: default-deny-egress, namespace: lab}
spec:
podSelector: {}
policyTypes: [Egress]NetworkPolicy 只有在 CNI 支持策略时才有效。应用默认拒绝 egress 后,DNS 也会被阻断;必须根据集群 DNS 的命名空间、标签和 UDP/TCP 53 端口添加精确放行,再逐项允许业务目的地。
端口字段一次说清
| 字段 | 含义 |
|---|---|
| containerPort | 文档与命名用途,不会自动开放防火墙 |
| Service port | 客户端访问 Service 的端口 |
| targetPort | 转发到 Pod 的端口或命名端口 |
| nodePort | NodePort 类型在节点暴露的端口 |
逐层连通性验证
- 在 Pod 内访问
127.0.0.1:容器端口,确认进程监听。 - 从同命名空间测试 Pod IP。
- 检查 EndpointSlice 是否包含 Ready 地址。
- 访问 Service ClusterIP 和 DNS 名。
- 最后验证 Ingress/Gateway、负载均衡器和外部 DNS。
kubectl get pod -n lab -l app=web -o wide
kubectl get svc web -n lab -o yaml
kubectl get endpointslice -n lab -l kubernetes.io/service-name=web -o yaml
kubectl run netcheck -n lab --rm -it --restart=Never --image=curlimages/curl -- sh
# 容器内执行:curl -v http://web.lab.svc.cluster.local
NetworkPolicy 分阶段上线
先确认 CNI 支持策略,再记录现有流量。第一阶段只在测试命名空间启用 ingress 默认拒绝并添加明确允许;第二阶段处理 egress,先放行 DNS,再放行数据库和外部 API。每条策略同时做“应通”和“应拒绝”测试。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: allow-web-from-gateway, namespace: lab}
spec:
podSelector: {matchLabels: {app: web}}
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: gateway}}
ports:
- {protocol: TCP, port: 80}namespaceSelector 与 podSelector 在同一数组项中表示“同时满足”,分成两个数组项则表示“任一满足”,这是常见的放大授权错误。
DNS 故障判断
若 IP 可通但域名不通,检查 resolv.conf、CoreDNS、Service/EndpointSlice 与 egress 策略;若域名解析正常但连接拒绝,检查 targetPort、进程监听地址和 readiness。不要一看到超时就重启 CoreDNS。
Service 类型与入口边界
| 类型 | 用途 | 注意 |
|---|---|---|
| ClusterIP | 集群内部服务 | 默认选择 |
| NodePort | 每节点暴露端口 | 通常由更上层 LB 使用 |
| LoadBalancer | 云/控制器创建外部入口 | 依赖具体实现与费用 |
| ExternalName | 返回外部 CNAME | 没有代理与健康检查 |
Ingress/Gateway 负责 HTTP/TCP 入口路由,但资源对象本身不转发流量;必须安装兼容控制器,并确认它已更新 status 和后端健康。
默认拒绝后放行 DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: allow-dns, namespace: lab}
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to:
- namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: kube-system}}
podSelector: {matchLabels: {k8s-app: kube-dns}}
ports:
- {protocol: UDP, port: 53}
- {protocol: TCP, port: 53}不同发行版的 DNS Pod 标签可能不同,应用前先查询 kubectl get pod -n kube-system --show-labels。如果使用 NodeLocal DNSCache,放行目标可能是节点本地地址,必须按发行版文档调整。
抓取网络证据
kubectl get networkpolicy -n lab -o yaml
kubectl get endpointslice -n lab -o wide
kubectl exec -n lab netcheck -- nslookup web.lab.svc.cluster.local
kubectl exec -n lab netcheck -- curl -sv --connect-timeout 3 http://web:80DNS 超时、TCP timeout、connection refused 和 HTTP 5xx 是不同层的问题,应保留原始错误而不是统称“网络不通”。
可复现记录模板
每次实验记录:集群版本、容器运行时、CNI/CSI 版本、命名空间、使用的 YAML Git 提交、开始与结束时间。命令输出至少保留对象状态、事件、关键日志和回滚结果。文中的占位符必须替换成自己的值,生产执行前应由第二人复核。
故障处理原则
- 先缩小影响面,不删除现场。
- 按对象状态—事件—日志—依赖顺序收集证据。
- 提出可证伪假设,一次只改变一个变量。
- 验证恢复后清理临时权限、调试 Pod、端口转发和测试数据。
完成检查
- 命令退出码为 0,目标对象状态与预期一致。
- 保存执行前后 YAML、事件与关键日志,确认没有把测试命名空间以外的对象改动。
- 故障演练完成后执行清理或回滚,再进行下一章。