Files
cs-note/hhs/MS/05-部署运维/02-Kubernetes/06-资源与安全管控.md
T
2026-05-24 11:42:38 +08:00

6.0 KiB

tags, create time
tags create time
kubernetes
resource-quota
limit-range
network-policy
security
2026-05-18 00:30

K8s 资源与安全管控 — Quota、LimitRange & NetworkPolicy

概述

多人共享集群或多租户环境中,需要两道防线来保障稳定:资源管控防止单个团队耗尽集群,网络策略防止横向越权访问。这两者构成了 K8s 多环境的安全基线。

ResourceQuota — 命名空间资源总量上限

apiVersion: v1
kind: ResourceQuota
metadata:
  name: production-quota
  namespace: production
spec:
  hard:
    requests.cpu: "16"              # 所有 Pod 的 CPU request 总和不超过 16核
    requests.memory: 32Gi           # 内存 request 不超过 32G
    limits.cpu: "32"                # 所有 Pod 的 CPU limit 不超过 32核
    limits.memory: 64Gi             # 内存 limit 不超过 64G
    pods: "50"                      # 最多 50 个 Pod
    services: "20"                  # 最多 20 个 Service
    persistentvolumeclaims: "10"    # 最多 10 个 PVC

[!warning] 配额打满怎么办?

当某个命名空间的配额被占满时,该 namespace 内的新创建请求会直接失败(Return Error)。解决方法:清理不再使用的资源,或申请管理员增加配额 (kubectl edit quota <name> -n <namespace>)。

LimitRange — 单容器资源边界

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
  # 默认 Limits/Requests(不指定的 Pod 自动套用)
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "250m"
      memory: "256Mi"
    # 单个容器的边界
    max:
      cpu: "2"
      memory: "4Gi"
    min:
      cpu: "50m"
      memory: "64Mi"

[!info] Quota vs LimitRange — 别搞混

  • ResourceQuota = namespace 总量天花板(整个房间能住多少人)
  • LimitRange = 单容器边界(每人占多大床位)

两者配合使用,既能防止个体乱配资源,又能防止群体耗尽配额。

NetworkPolicy — 网络安全策略

默认情况下,K8s 集群内所有 Pod 可以自由互访(零信任缺失)。NetworkPolicy 提供 L3/L4 层的双向流量控制:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-service-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: order-service
  policyTypes:
  - Ingress
  - Egress
  
  ingress:
  # 允许来自 Ingress Controller 和 user-service 的流量
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-ns
    - podSelector:
        matchLabels:
          app: user-service
    ports:
    - protocol: TCP
      port: 8080
  
  egress:
  # 允许 outbound DB 连接和 DNS 查询
  - to:
    - podSelector:
        matchLabels:
          app: mysql
    ports:
    - protocol: TCP
      port: 3306
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53                    # DNS(必备!否则 Pod 无法解析域名)

NetworkPolicy 最佳实践

原则 说明
默认拒绝全部 先用 podSelector: {} + 空 ingress/egress 拦截一切
白名单精确匹配 每个 Policy 只放开一个方向的流量
DNS 永远放行 没有 egress DNS 规则,Service 发现全部失效
跨命名空间要显式声明 namespaceSelector 为空 {} 表示允许所有命名空间

支持 NetworkPolicy 的网络插件

[!warning] NetworkPolicy 生效前提

NetworkPolicy 需要集群网络插件支持。默认的 Kubenet / Flannel 不一定支持,推荐使用:

  • Calico — 功能最完整,支持 L7 策略(与 Istio 配合)
  • Cilium — 基于 eBPF,性能最优,原生支持 L7 过滤
  • Antrea — VMware 出品,兼容性好

补充:Zero-Trust 默认策略模板

# ========== 全局:默认拒绝所有入站 ==========
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all-ingress
  namespace: production
spec:
  podSelector: {}               # 选择所有 Pod
  policyTypes:
  - Ingress

---
# ========== 全局:默认拒绝所有出站 ==========
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress

[!tip] 渐进式实施 NetworkPolicy

不要在已有集群上一夜之间切换所有策略——这会立刻打飞所有服务。正确的做法:

  1. 先以 audit 模式运行 Calico/Cilium,观察现有流量
  2. 对每个服务编写 allowlist Policy,在 测试环境 验证
  3. 逐步推广到生产,从非关键服务开始
  4. 最终启用 deny-all 作为兜底

补充:SecurityContext — 容器级安全加固

spec:
  containers:
  - name: order-service
    securityContext:
      runAsNonRoot: true         # 禁止 root 运行
      readOnlyRootFilesystem: true  # 根文件系统只读
      allowPrivilegeEscalation: false  # 禁止提权
      capabilities:
        drop: ["ALL"]            # 丢弃所有内核能力
        add: ["NET_BIND_SERVICE"] # 仅保留绑定 <1024 端口需要的能力
  
  # Pod 级别的 DNS 配置
  dnsPolicy: ClusterFirstWithHostNet     # DNS 策略
  automountServiceAccountToken: false     # 不挂载 SA Token(不需要 API 时)

[!warning] readOnlyRootFilesystem 的坑

某些应用(如 Python 的 pip 缓存、Java 的 temp 目录)会尝试写入 /tmp 或应用目录。解决方案:

volumeMounts:
- name: tmp-volume
  mountPath: /tmp
volumes:
- name: tmp-volume
  emptyDir: {}

通过 emptyDir 挂载临时卷,既保持了根文件系统只读,又给了应用必要的写权限。

关联笔记