控制调度、资源与权限
调度决定 Pod 能否放到合适的 Node;权限决定它能调用哪些 API;网络策略决定它能与谁通信。它们共同构成多租户和生产稳定性的基础边界。
本篇目标:能读懂 Pod 的 Pending 原因并解决调度问题,会为 Pod 创建最小权限 ServiceAccount 和 RBAC,能写出一个安全的 NetworkPolicy。

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-affinity | Pod 之间"靠近"或"远离" | 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
污点通常保护着控制面节点、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
- 给一个节点打污点
kubectl taint node <node> test=value:NoSchedule - 创建一个 Deployment(1 副本),观察 Pod 是否 Pending
- 添加对应 toleration,观察 Pod 是否成功调度
- 移除污点:
kubectl taint node <node> test=value:NoSchedule-
练习 B
- 创建一个 ServiceAccount + Role(只读 Pod)+ RoleBinding,验证权限:
kubectl auth can-i get pods --as=system:serviceaccount:learning:<sa-name> -n learning - 创建上一节中的 NetworkPolicy 示例,用
kubectl describe networkpolicy确认规则 - 启动两个标签不同的 busybox Pod,用
wget测试 NetworkPolicy 是否生效
验收清单
- 会通过 Pod events 区分资源、污点和选择器导致的 Pending
- 能解释 nodeSelector、affinity、taint/toleration 的边界和 effect 差异
- 知道 Pod 应使用最小权限 ServiceAccount
- 会创建并验证 Role + RoleBinding 权限
- 知道 Pod Security Standards 三级(privileged/baseline/restricted)的差异
- 知道 NetworkPolicy 依赖 CNI 实现,默认拒绝前必须先补齐允许规则
下一篇:日常巡检与发布。