🛡️ 第12课:NetworkPolicy

📌 课程阶段:安全与监控(2/5)|预计时间:60分钟|难度:⭐⭐⭐☆☆

一、为什么需要NetworkPolicy?

K8s默认网络是全开放的——任何Pod可以访问任何Pod。NetworkPolicy是K8s的"网络防火墙",实现微隔离(Micro-segmentation),控制Pod间的网络流量。

┌─────── 默认:全开放 ───────┐   ┌───── NetworkPolicy:微隔离 ─────┐
│                              │   │                                    │
│  [frontend] ←→ [backend]    │   │  [frontend] → [backend]          │
│      ↕           ↕          │   │      ✗           ↕                │
│  [db]       ←→ [cache]     │   │              [db] ← [backend]    │
│      ↕           ↕          │   │               ✗                   │
│  [monitor] ←→ [logger]     │   │  [monitor] → [所有](只读)      │
│                              │   │                                    │
│  所有Pod互相可访问            │   │  只允许必要的流量路径              │
│  ❌ 不安全!                  │   │  ✅ 零信任网络                    │
└──────────────────────────────┘   └────────────────────────────────────┘

NetworkPolicy关键特性:
  🔹 命名空间级资源,只影响同namespace的Pod
  🔹 基于Pod标签选择器匹配Pod
  🔹 控制Ingress(入站)和Egress(出站)流量
  🔹 需要CNI插件支持(Calico/Cilium/Weave等)
  🔹 多个NetworkPolicy对同一Pod是累加关系

二、NetworkPolicy语法详解

# networkpolicy-syntax.yaml - 完整语法
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: example-policy
  namespace: default
spec:
  # Pod选择器:策略应用到哪些Pod
  podSelector:
    matchLabels:
      app: backend               # 匹配app=backend的Pod
    # {} 匹配所有Pod
  
  # 策略类型
  policyTypes:
  - Ingress                      # 控制入站流量
  - Egress                       # 控制出站流量
  
  # 入站规则(白名单)
  ingress:
  - from:                        # 允许的来源(OR关系)
    # 来源选择器之间是AND关系
    - podSelector:               # 同namespace的Pod
        matchLabels:
          app: frontend
    - namespaceSelector:         # 其他namespace
        matchLabels:
          env: production
    - ipBlock:                   # IP段
        cidr: 10.0.0.0/8
        except:
        - 10.0.1.0/24           # 排除子网
    ports:                       # 允许的端口
    - protocol: TCP
      port: 8080
    - protocol: TCP
      port: 443
  
  # 出站规则(白名单)
  egress:
  - to:                          # 允许的目标
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 3306
  - to:                          # 允许DNS解析
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

三、常见NetworkPolicy模式

3.1 默认拒绝所有入站

# default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: default
spec:
  podSelector: {}                # 匹配所有Pod
  policyTypes:
  - Ingress                      # 拒绝所有入站(无ingress规则=全部拒绝)

# ✅ 验证通过 - 所有Pod无法被外部访问
kubectl apply -f default-deny-ingress.yaml
# 测试:从其他Pod无法访问default命名空间的Pod

3.2 默认拒绝所有出站

# default-deny-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress                       # 拒绝所有出站

# ⚠️ 注意:这会阻止DNS解析!需要额外规则允许DNS

3.3 默认拒绝所有流量

# default-deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress                       # 拒绝所有入站+出站

3.4 三层微服务网络策略

# 三层架构:frontend → backend → database

# 1. Frontend:只允许外部入站80端口,允许出站到backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes: [Ingress, Egress]
  ingress:
  - ports:
    - port: 80
      protocol: TCP
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - port: 8080
      protocol: TCP
  - to:                          # 允许DNS
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - port: 53
      protocol: UDP

---
# 2. Backend:只允许frontend入站,只允许出站到database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes: [Ingress, Egress]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - port: 8080
      protocol: TCP
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - port: 3306
      protocol: TCP
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - port: 53
      protocol: UDP

---
# 3. Database:只允许backend入站3306,无出站需求
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes: [Ingress]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - port: 3306
      protocol: TCP

# ✅ 验证通过 - 验证隔离效果
# Frontend可以访问Backend
kubectl exec frontend-pod -- curl -s backend-service:8080/health
# OK

# Frontend不能直接访问Database
kubectl exec frontend-pod -- curl -s database-service:3306
# Connection timed out ✅ 隔离生效

3.5 跨命名空间策略

# 允许dev命名空间访问prod的只读API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dev-readonly
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: [Ingress]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          env: development       # 需要给namespace打标签
    ports:
    - port: 8080
      protocol: TCP

# 给namespace打标签
kubectl label namespace development env=development
kubectl label namespace production env=production

四、CiliumNetworkPolicy(高级)

# Cilium提供增强版NetworkPolicy
# 支持L7层(HTTP/gRPC/Kafka等)策略
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-policy
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: GET            # 只允许GET请求
          path: "/api/.*"        # 只允许/api/路径
        - method: POST
          path: "/api/data"

五、故障排查实战

5.1 NetworkPolicy不生效

# 检查CNI是否支持NetworkPolicy
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave'
# Flannel默认不支持!需要用Calico或Cilium

# 检查NetworkPolicy是否存在
kubectl get networkpolicy -A

# 检查Pod标签是否匹配
kubectl get pods --show-labels | grep backend

5.2 DNS解析失败

# 现象:Pod无法解析域名
# 原因:Egress策略阻止了到DNS Pod的流量

# 解决:添加DNS放行规则
egress:
- to:
  - namespaceSelector: {}
    podSelector:
      matchLabels:
        k8s-app: kube-dns
  ports:
  - port: 53
    protocol: UDP
  - port: 53
    protocol: TCP

六、练习

  1. 部署Calico/Cilium CNI,验证NetworkPolicy功能
  2. 创建默认拒绝策略,然后逐步放行必要流量
  3. 实现三层微服务网络隔离:frontend→backend→database
  4. 创建跨命名空间NetworkPolicy,只允许特定namespace访问
  5. (进阶)使用CiliumNetworkPolicy实现HTTP层精细控制

🏆 第12课成就解锁

下一课预告:第13课深入Prometheus监控——K8s可观测性基石。

📌 补充知识

12-networkpolicy补充要点K8s生产实践扩展

🔹 资源配额(ResourceQuota):限制命名空间总资源
  apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: compute-quota
    namespace: production
  spec:
    hard:
      requests.cpu: "20"
      requests.memory: 40Gi
      limits.cpu: "40"
      limits.memory: 80Gi
      pods: "50"
      services: "10"

🔹 LimitRange:设置默认资源限制
  apiVersion: v1
  kind: LimitRange
  metadata:
    name: default-limits
  spec:
    limits:
    - type: Container
      default:
        cpu: "200m"
        memory: 256Mi
      defaultRequest:
        cpu: "100m"
        memory: 128Mi
      max:
        cpu: "2"
        memory: 4Gi

🔹 Pod优先级与抢占
  apiVersion: scheduling.k8s.io/v1
  kind: PriorityClass
  metadata:
    name: high-priority
  value: 1000000
  globalDefault: false
  ---
  spec:
    preemptionPolicy: PreemptLowerPriority

🔹 优雅处理Pod中断
  • PDB保证最小可用副本
  • preStop钩子处理连接排空
  • terminationGracePeriodSeconds充足
  • 应用必须处理SIGTERM信号

🔹 生产环境Checklist
  ✅ 设置resources requests/limits
  ✅ 配置liveness/readiness探针
  ✅ 使用PDB保护关键服务
  ✅ 实现优雅关闭(SIGTERM)
  ✅ 配置HPA自动伸缩
  ✅ 使用NetworkPolicy隔离
  ✅ 开启RBAC最小权限
  ✅ 日志结构化输出
  ✅ 指标暴露/metrics端点
  ✅ 配置PVC数据备份

📎 扩展阅读与生产实践

12-networkpolicy生产环境进阶要点

🔹 性能优化关键参数
  • kubelet: --max-pods=110 --pods-per-core=10
  • kube-apiserver: --max-requests-inflight=800
  • etcd: --quota-backend-bytes=8589934592
  • kube-scheduler: --percentage-of-nodes-to-score=50

🔹 集群容量规划
  • 控制平面:3节点,8C16G起步
  • Worker节点:按应用类型分组
  • etcd:SSD磁盘,<2ms延迟
  • 网络带宽:10Gbps+集群内互联

🔹 故障自愈最佳实践
  1. Pod: livenessProbe自动重启
  2. Deployment: ReplicaSet保证副本数
  3. Node: kubelet自注册+健康检查
  4. Cluster: Cluster Autoscaler增减节点
  5. Multi-Cluster: Karmada联邦容灾

🔹 K8s版本升级策略
  • 每次只升一个minor版本
  • 先升级控制平面,再升级Worker
  • 使用kubeadm upgrade plan预检
  • 准备回滚方案
  • 在staging环境验证后再升级prod