Repository Reading Site
Ingress 与 NetworkPolicy — 流量的入口和隔离
NodePort 的问题: Ingress 的解决方案:一个统一入口,通过域名和路径分发到不同 Service。 **为什么用 NodePort 而不是 LoadBalancer?** 裸金属环境没有云厂商的 LB 服务。如果需要,可以装 MetalLB 模拟。 nginx-ingress controller 本质上是一个**监听 Ingress 资源变化
Ingress 与 NetworkPolicy — 流量的入口和隔离
Ingress — 集群的"反向代理"
为什么需要 Ingress?
NodePort 的问题:
- 每个 Service 一个端口(30000-32767),端口不好记
- 没有基于域名/路径的路由
- 没有 TLS 终结
Ingress 的解决方案:一个统一入口,通过域名和路径分发到不同 Service。
架构
外部请求 → NodePort 30080 → Ingress Controller (nginx)
│
├── app.k8s-lab.local/ → nginx-svc
├── app.k8s-lab.local/web → web-headless
├── grafana.k8s-lab.local → grafana-svc
└── harbor.k8s-lab.local → harbor-svc
安装 nginx-ingress
helm install ingress-nginx ingress-nginx/ingress-nginx \
--set controller.service.type=NodePort \
--set controller.service.nodePorts.http=30080 \
--set controller.service.nodePorts.https=30443 \
--set controller.nodeSelector.workload=general # 避开 VPN 节点
为什么用 NodePort 而不是 LoadBalancer? 裸金属环境没有云厂商的 LB 服务。如果需要,可以装 MetalLB 模拟。
Ingress 资源定义
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
namespace: dev
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定使用哪个 Ingress Controller
rules:
- host: app.k8s-lab.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-headless
port:
number: 80
验证
$ curl -H "Host: app.k8s-lab.local" http://154.9.27.60:30080/
<!DOCTYPE html>... ← nginx 欢迎页
Ingress Controller 的工作原理
nginx-ingress controller 本质上是一个监听 Ingress 资源变化的 nginx 进程:
- Watch API Server 中所有 Ingress 资源
- 根据 Ingress 规则生成 nginx.conf
- 热重载 nginx(
nginx -s reload) - 流量进入 nginx → 按 host/path 路由到后端 Service 的 Pod
面试题: "Ingress 和 Gateway API 的区别?"
- Ingress 是 K8s 的第一代入口方案,功能有限(只支持 HTTP/HTTPS)
- Gateway API 是下一代,支持 TCP/UDP/gRPC,更灵活的路由规则,跨 namespace 引用
- Gateway API 正在逐步替代 Ingress,但 Ingress 目前仍是主流
NetworkPolicy — 集群内防火墙
默认行为:全通
K8s 默认所有 Pod 之间可以互相通信,包括跨 namespace。这在生产中是不可接受的。
我们的实验
步骤 1: dev 的 Pod → prod 的 Pod = 通(默认)
步骤 2: prod 加 default-deny → dev 的 Pod → prod = 不通
步骤 3: prod 加白名单(同 namespace)→ prod 内部互通,dev 仍不通
default-deny 策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: prod
spec:
podSelector: {} # 选择所有 Pod
policyTypes:
- Ingress # 限制入站流量
# 没有 ingress 规则 = 拒绝所有入站
关键理解: NetworkPolicy 是累加的。只要有任何一条 NetworkPolicy 选中了某个 Pod,该 Pod 就从"默认全通"变为"默认拒绝 + 只允许策略中定义的流量"。
白名单:只允许同 namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: prod
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # 同 namespace 的所有 Pod
验证结果
dev web-0 → prod test-server: 不通 (exit 28, timeout) ← 跨 NS 被阻断
prod test-client → prod test-server: 通 (<!DOCTYPE html>) ← 同 NS 放行
零信任网络设计模式
生产环境推荐的模式:
1. 每个 namespace 加 default-deny-ingress + default-deny-egress
2. 按需开放:
- frontend → backend (端口 8080)
- backend → database (端口 5432)
- backend → cache (端口 6379)
- 所有 Pod → kube-dns (端口 53, UDP)
3. 禁止:
- frontend → database (直接)
- 任何 Pod → 外部互联网 (除了必要的 API)
Calico 的优势: 标准 K8s NetworkPolicy 只支持 L3/L4(IP + 端口),Calico 还支持:
- 基于 Service Account 的策略
- 全局 NetworkPolicy(跨 namespace)
- DNS 策略(按域名过滤出站)
- 应用层策略(L7,需要 Envoy sidecar)