剛接手公司K8s集羣時,我發現所有Pod之間都能隨意通信。有次開發環境的測試Pod誤連了生產數據庫,雖然沒造成損失,但讓我意識到必須給Pod間的網絡加道"門"——這就是NetworkPolicy的用武之地。

為什麼需要NetworkPolicy?

Kubernetes默認的網絡策略是"全部允許",任何Pod都能訪問其他Pod,這在複雜系統裏很危險。想象一下:如果黑客入侵了一個邊緣服務的Pod,就能直接訪問核心數據庫,後果不堪設想。NetworkPolicy就像網絡防火牆,能基於標籤精細控制Pod間的流量。

基礎概念與前提

使用NetworkPolicy有個前提:集羣網絡插件必須支持它,比如Calico、Cilium,而Flannel這類簡單插件是不支持的。可以用這個命令檢查:

kubectl get networkpolicy --all-namespaces

如果返回"the server doesn't have a resource type "networkpolicy"",説明當前插件不支持,得先換插件。

NetworkPolicy的核心是"選擇器":通過Pod標籤和命名空間標籤來指定規則適用的對象,然後定義入站(ingress)和出站(egress)規則。

常用規則示例

1. 默認拒絕所有入站流量

在生產命名空間創建默認拒絕規則,這是最安全的起點:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}  # 匹配命名空間下所有Pod
  policyTypes:
  - Ingress

2. 允許特定服務訪問數據庫

假設數據庫Pod有標籤app: mysql,只允許帶app: backend標籤的Pod訪問3306端口:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mysql-allow-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 3306

3. 限制Pod的出站流量

阻止前端Pod訪問除API服務外的其他資源:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-restrict-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080

實際應用中的坑

上週配置規則時,發現新規則沒生效,排查後發現是標籤寫錯了。Pod的標籤是app: api-service,但規則裏寫成了app: api,這種細節很容易出錯。

另一個教訓是:創建默認拒絕規則後,一定要先配置允許規則再部署應用,否則新Pod會完全斷網。我一般先在測試命名空間用kubectl apply -f policy.yaml驗證,沒問題再推到生產。

最佳實踐

  1. 遵循"最小權限原則":只允許必要的流量
  2. 先創建默認拒絕規則,再逐步添加允許規則
  3. 給Pod打清晰的標籤,比如appenvrole,方便規則匹配
  4. 定期用kubectl describe networkpolicy <name>檢查規則狀態

NetworkPolicy看似簡單,實則是K8s安全體系的重要一環。合理配置後,既能防止內部服務越權訪問,也能在發生安全事件時縮小影響範圍。就像給每個Pod裝了智能門鎖,該放的放,該攔的攔,整個集羣的網絡才真正可控。