Service、Ingress、NetworkPolicy
目标
能够区分并指定 Service 的三类端口,并能用清单编写命名端口、Headless Service、StatefulSet DNS、Ingress 路由和 NetworkPolicy 白名单。
为什么重要
Service 相关错误几乎都来自两点:选择器与 Pod 标签不一致,以及混淆三个端口。选择器不匹配时不会报错,但 Endpoint 会为空,客户端只能看到连接被拒绝。养成检查 kubectl get endpoints 是否为空的习惯,就能节省大部分排障时间。
按方向记忆端口便不会混淆。port 是进入的一侧(客户端连接 Service 的端口),targetPort 是离开的一侧(Service 连接 Pod 的端口),nodePort 是从外部进入的一侧(节点上开放的端口)。
Headless Service 是选择放弃负载均衡。它不创建虚拟 IP,DNS 会直接返回 Pod IP 列表;与 StatefulSet 配合后,每个 Pod 都会拥有唯一名称。需要由客户端指定特定实例的工作负载(DB 主节点、分片)会使用这种方式。
NetworkPolicy 可概括为两句话:默认允许,附加策略后使用白名单。因此,实际工作中通常先对整个命名空间设置默认拒绝,再只开放必要通信。还要记住,多项策略不会相互覆盖,而是以并集方式叠加。
步骤
- 创建命名空间
ckad-net。创建 Deploymentfrontend(副本数 2、标签app=frontend、镜像nginx:1.27、容器端口80命名为http)和 Servicefrontend(ClusterIP、port: 80、targetPort: 80、选择器app=frontend)。 - 创建 Deployment
backend(副本数 2、标签app=backend、镜像nginx:1.27、容器端口8080命名为api)和 Servicebackend(ClusterIP、port: 80、targetPort: api——使用名称、选择器app=backend)。 - 创建 Service
frontend-np。类型NodePort,port: 80、targetPort: 80、nodePort: 30080,选择器app=frontend。 - 创建 Headless Service
cache-hs(clusterIP: None、port: 6379、选择器app=cache)和 StatefulSetcache(副本数 3、serviceName: cache-hs、标签app=cache、镜像nginx:1.27)。然后把编号 0 Pod 的完整 DNS 名称单独一行写入/root/ckad-net/dns.txt。 - 创建 Ingress
shop。ingressClassName: nginx,主机shop.ckad.local,路径/(pathTypePrefix)→ Servicefrontend端口 80,路径/api(pathTypePrefix)→ Servicebackend端口 80。 - 创建 NetworkPolicy
backend-allow-frontend。目标是app=backendPod,policyTypes: [Ingress],允许来源为app=frontendPod,端口为 TCP8080。 - 创建 NetworkPolicy
default-deny-ingress。podSelector: {}(整个命名空间)、policyTypes: [Ingress],不设置 ingress 规则。此时确认 Servicebackend的选择器实际选中了至少 2 个 Pod,使用kubectl get pods -n ckad-net -l app=backend进行检查。
参考
- 使用
kubectl create deployment frontend --image=nginx:1.27 --replicas=2 -n ckad-net --dry-run=client -o yaml生成骨架,再为ports添加名称。 kubectl expose deployment frontend --port=80 --target-port=80 -n ckad-net会自动填充选择器。- 第 4 步 DNS 名称格式:
<파드이름>.<서비스이름>.<네임스페이스>.svc.cluster.local - 常见错误 1:在 NetworkPolicy 中写反
podSelector(应用目标)和from[].podSelector(允许来源)。 - 常见错误 2:将
nodePort指定为小于 30000。默认允许范围是 30000~32767。 - 常见错误 3:
targetPort使用名称时,应填写容器的端口名称,而不是 Service 的名称。 - 此环境没有 Ingress 控制器和真实 CNI 数据平面,因此无法确认路由与策略是否真正生效。目标是准确编写对象。
Deployment 与 ClusterIP Service
创建命名空间 ckad-net。创建 Deployment frontend(副本数 2、标签 app=frontend、镜像 nginx:1.27、容器端口 80 命名为 http)和 Service frontend(ClusterIP、port: 80、targetPort: 80、选择器 app=frontend)。
可以使用 kubectl expose deployment,也可以直接编写 Service。Service 选择器必须与 Pod 标签完全一致,才能生成 Endpoint。提前为容器端口命名,会方便下一步操作。
通过 named port 连接 targetPort
创建 Deployment backend(副本数 2、标签 app=backend、镜像 nginx:1.27、容器端口 8080 命名为 api)和 Service backend(ClusterIP、port: 80、targetPort: api——使用名称、选择器 app=backend)。
将容器 ports[].name 中设置的名称作为字符串写入 Service 的 targetPort。名称不超过 15 个字符,只能包含小写字母、数字和连字符。
使用 NodePort 对外开放
创建 Service frontend-np。类型 NodePort,port: 80、targetPort: 80、nodePort: 30080,选择器 app=frontend。
将类型设为 NodePort,并直接指定 nodePort。允许范围为 30000~32767;如果不指定,会自动分配。port 和 targetPort 仍需保留。
Headless Service 与 StatefulSet
创建 Headless Service cache-hs(clusterIP: None、port: 6379、选择器 app=cache)和 StatefulSet cache(副本数 3、serviceName: cache-hs、标签 app=cache、镜像 nginx:1.27)。然后把编号 0 Pod 的完整 DNS 名称单独一行写入 /root/ckad-net/dns.txt。
Headless Service 使用 clusterIP: None。必须在 StatefulSet 的 serviceName 中填写该 Service 名称,才能生成各 Pod 的 DNS 名称。命名规则依次为 Pod 名称、Service 名称、命名空间,并以点分隔。
使用 Ingress 按主机与路径路由
创建 Ingress shop。ingressClassName: nginx,主机 shop.ckad.local,路径 /(pathType Prefix)→ Service frontend 端口 80,路径 /api(pathType Prefix)→ Service backend 端口 80。
使用 networking.k8s.io/v1,后端通过 service.name 和 service.port.number 指定。每条路径都必须包含 pathType。规则结构为 rules[].host 和 rules[].http.paths[]。
使用 NetworkPolicy 只允许前端访问
创建 NetworkPolicy backend-allow-frontend。目标是 app=backend Pod,policyTypes: [Ingress],允许来源为 app=frontend Pod,端口为 TCP 8080。
podSelector 指向策略应用的目标,ingress[].from[].podSelector 指向允许的来源。二者很容易写反,请注意。同时限制端口。
综合:默认拒绝策略与选择器检查
创建 NetworkPolicy default-deny-ingress。podSelector: {}(整个命名空间)、policyTypes: [Ingress],不设置 ingress 规则。此时确认 Service backend 的选择器实际选中了至少 2 个 Pod,使用 kubectl get pods -n ckad-net -l app=backend 进行检查。
空的 podSelector: {} 表示命名空间中的所有 Pod。不设置任何 ingress 规则便构成默认拒绝。同时使用 kubectl get pods -l 直接确认 Service 选择器能选中真实 Pod。