跳到主要内容

控制调度、资源与权限

调度决定 Pod 能否放到合适的 Node;权限决定它能调用哪些 API;网络策略决定它能与谁通信。它们共同构成多租户和生产稳定性的基础边界。

本篇目标:能读懂 Pod 的 Pending 原因并解决调度问题,会为 Pod 创建最小权限 ServiceAccount 和 RBAC,能写出一个安全的 NetworkPolicy。

Kubernetes 调度、权限与网络安全边界


1. 调度时发生什么​

调度器会根据资源请求、节点状态、污点、亲和规则、拓扑约束等条件为未调度 Pod 选择 Node。Pending 并不等于"集群坏了",它表示某项约束当前无法满足。

kubectl describe pod <pod-name> -n learning
# 重点查看 Events 中的 FailedScheduling 原因

常见原因:CPU/内存不足、节点污点未容忍、nodeSelector 无匹配节点、PVC 无法绑定、Namespace 配额耗尽。


2. 节点选择、亲和与污点​

2.1 三种调度控制手段​

机制解决的问题方向
nodeSelector简单地只允许调度到带某标签的节点Pod 选择节点
node affinity"必须"或"尽量"靠近某类节点,表达式更丰富Pod 选择节点
pod affinity / anti-affinityPod 之间"靠近"或"远离"Pod 之间相互影响
taint / toleration节点主动排斥一般 Pod,只有被容忍的工作负载可进入节点排斥 Pod
topology spread constraints在节点、可用区等拓扑域均匀分布副本Pod 之间按拓扑均匀分布

2.2 Node Affinity 完整示例​

spec:
affinity:
nodeAffinity:
# 硬约束:必须在 GPU 节点上,且是 A100 型号
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values:
- nvidia-a100
# 软偏好:优先选 ap-guangzhou-3 可用区
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- ap-guangzhou-3

requiredDuringScheduling 不满足就不调度(Pod 一直 Pending);preferredDuringScheduling 不满足就退而求其次。IgnoredDuringExecution 表示"已经在跑的 Pod 不受后续节点标签变更影响"。

2.3 Taint 与 Toleration​

节点上的污点阻止不合规的 Pod 调度上来,Pod 上的容忍允许它"忍受"特定污点:

# 给节点打污点:专用 GPU 节点,拒绝普通 Pod
kubectl taint node gpu-node-01 accelerator=nvidia-a100:NoSchedule

# 查看节点的污点
kubectl describe node gpu-node-01 | grep Taints

三种 taint effect:

effect行为
NoSchedule新 Pod 不会被调度到该节点;已有 Pod 不受影响
PreferNoSchedule尽量不调度,但不强制——是软约束
NoExecute新 Pod 不会调度,已在运行的 Pod 也会被驱逐(除非有对应 toleration 且 tolerationSeconds 未到期)
# Pod 要容忍 GPU 节点的污点才能调度上去
spec:
tolerations:
- key: accelerator
operator: Equal
value: nvidia-a100
effect: NoSchedule
# 容忍控制面污点(如果需要跑在控制面节点上)
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
不要为了"让 Pod 立刻跑起来"盲目加 toleration

污点通常保护着控制面节点、GPU 节点、内存优化节点等专用资源。随意容忍所有污点会绕过平台隔离策略,把普通应用调度到不该去的地方。


3. ServiceAccount 与 RBAC​

Pod 不应使用人类管理员 kubeconfig。它通过 ServiceAccount 获取 API 身份,再由 Role / ClusterRole 和 Binding 授权:

3.1 最小权限示例​

# 1. 创建专属 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: api
namespace: learning
---
# 2. 定义只能读 ConfigMap 的 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: config-reader
namespace: learning
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
# 也可以限定资源名称:
# resourceNames: ["api-config"]
---
# 3. 把 Role 绑定到 ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: api-config-reader
namespace: learning
subjects:
- kind: ServiceAccount
name: api
roleRef:
kind: Role
name: config-reader
apiGroup: rbac.authorization.k8s.io
---
# 4. Pod 使用该 ServiceAccount
apiVersion: v1
kind: Pod
metadata:
name: api
namespace: learning
spec:
serviceAccountName: api
# 如果不需要访问 API Server,关闭默认 token 挂载
automountServiceAccountToken: false
containers:
- name: api
image: registry.example.com/api:1.4.2

3.2 验证权限​

# 验证 ServiceAccount 能否执行某个操作
kubectl auth can-i list configmaps -n learning \
--as=system:serviceaccount:learning:api

# 验证当前用户自己能不能做某操作
kubectl auth can-i delete namespaces

# 查看某个 Role 的权限详情
kubectl describe role config-reader -n learning

3.3 RBAC 实践要点​

  • 优先使用 Namespace 范围的 Role,除非资源确实属于集群级别(如 Node、PV、StorageClass);
  • 不要因为一项权限不足就授予 cluster-admin——那是集群 root;
  • 定期审计高权限 Binding:kubectl get clusterrolebinding -o wide | grep cluster-admin;
  • 为 CI/CD、监控、GitOps 工具各自创建独立 ServiceAccount,不混用。

4. Pod 安全标准(Pod Security Standards)​

从 Kubernetes 1.25 起,PodSecurityPolicy 被移除,改用内置的 Pod Security Standards(PSS):

级别含义适合
privileged无限制系统组件(CNI、CSI、kube-proxy)
baseline禁止已知提权手段(hostPath、hostNetwork、privileged 等)大多数业务应用
restricted最严格,强制 runAsNonRoot、readOnlyRootFilesystem、drop ALL capabilities安全要求最高的应用
# 为 Namespace 设置安全策略标签
kubectl label ns learning \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/warn=restricted
  • enforce:违反策略的 Pod 会被拒绝创建;
  • warn:违反时仅发出警告,不拒绝;
  • audit:违反时记录审计日志。

5. NetworkPolicy​

NetworkPolicy 可以限制 Pod 的入站和出站流量,但是否生效取决于 CNI 是否支持(Calico、Cilium 支持;Flannel 默认不支持)。

5.1 最小示例:允许同 Namespace 入站 + DNS 出站​

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-policy
namespace: learning
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: api
policyTypes:
- Ingress
- Egress
# 入站:允许同 Namespace 中带 frontend 标签的 Pod 访问 8080 端口
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: frontend
ports:
- protocol: TCP
port: 8080
# 出站:只允许 DNS 和同 Namespace 内通信
egress:
# 允许 DNS 查询
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# 允许访问同 Namespace 中带 database 标签的 Pod
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: database
ports:
- protocol: TCP
port: 5432

5.2 默认拒绝所有流量​

# 1. 先创建默认拒绝所有入站的策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: learning
spec:
podSelector: {} # 匹配所有 Pod
policyTypes:
- Ingress
---
# 2. 再逐服务添加允许规则(如上面的 api-policy)
启用默认拒绝前,先补齐允许规则

默认拒绝会切断所有 Pod 间通信——DNS、监控采集、入口网关、健康检查全部中断。必须先确认所有必要的 ingress/egress 规则都已就绪,再启用默认拒绝策略。建议先在 staging 环境验证一周,再上 production。


6. 生产基线​

  • 所有工作负载定义 requests / limits,并设置 Namespace ResourceQuota 和 LimitRange;
  • 使用专属 ServiceAccount,禁用不必要的 automountServiceAccountToken;
  • RBAC 最小权限,定期审计高权限 Binding;
  • 为 Namespace 启用 pod-security.kubernetes.io/enforce=baseline;
  • 通过准入策略限制特权容器、hostPath、未签名镜像和 latest;
  • 网络策略从可观察、灰度启用开始——不要直接全局拒绝。

7. 练习​

练习 A

  1. 给一个节点打污点 kubectl taint node <node> test=value:NoSchedule
  2. 创建一个 Deployment(1 副本),观察 Pod 是否 Pending
  3. 添加对应 toleration,观察 Pod 是否成功调度
  4. 移除污点:kubectl taint node <node> test=value:NoSchedule-

练习 B

  1. 创建一个 ServiceAccount + Role(只读 Pod)+ RoleBinding,验证权限:kubectl auth can-i get pods --as=system:serviceaccount:learning:<sa-name> -n learning
  2. 创建上一节中的 NetworkPolicy 示例,用 kubectl describe networkpolicy 确认规则
  3. 启动两个标签不同的 busybox Pod,用 wget 测试 NetworkPolicy 是否生效

验收清单

  • 会通过 Pod events 区分资源、污点和选择器导致的 Pending
  • 能解释 nodeSelector、affinity、taint/toleration 的边界和 effect 差异
  • 知道 Pod 应使用最小权限 ServiceAccount
  • 会创建并验证 Role + RoleBinding 权限
  • 知道 Pod Security Standards 三级(privileged/baseline/restricted)的差异
  • 知道 NetworkPolicy 依赖 CNI 实现,默认拒绝前必须先补齐允许规则

下一篇:日常巡检与发布。