Kubernetes 权限、副本与网络策略
1. RBAC 基于角色的访问控制
1.1 RBAC 核心概念
RBAC(Role-Based Access Control)是 Kubernetes 中最核心的权限控制机制之一。它通过“主体(Subject)—角色(Role)—权限规则(Policy Rules)”来决定:谁可以对哪些资源执行哪些操作。
核心对象 | 作用域 | 说明 |
|---|---|---|
Role | 命名空间级别 | 定义某个命名空间内的权限规则集合 |
ClusterRole | 集群级别 | 定义可跨命名空间使用的权限规则,也可用于集群级资源 |
RoleBinding | 命名空间级别 | 将 Role 或 ClusterRole 绑定到某个命名空间内的主体 |
ClusterRoleBinding | 集群级别 | 将 ClusterRole 绑定到集群范围的主体,全局生效 |
ServiceAccount | 命名空间级别 | Pod 访问 API Server 时使用的身份 |
User / Group | 集群级别 | 外部用户或用户组,通常由证书、OIDC 等方式管理 |
关键理解
RoleBinding 可以引用 ClusterRole。
这是 Kubernetes RBAC 里非常重要的“降权”技巧:
ClusterRole定义权限内容RoleBinding决定权限只在某个命名空间生效
也就是说,权限定义可以是集群级的,但实际生效范围可以被 RoleBinding 限定到某个 namespace。
常见 verbs
动词 | 含义 |
|---|---|
get / list / watch | 只读 |
create / update / patch | 写入 |
delete / deletecollection | 删除 |
exec / portforward | 进入容器或转发端口 |
1.2 RBAC 标准任务:为 CI/CD 流水线配置命名空间级权限
场景:为 CI/CD 流水线创建一个专属 ServiceAccount,让它只在 app-team1 命名空间内拥有创建 Deployment / StatefulSet / DaemonSet 的权限。
步骤 1:查看并切换集群上下文
# 查看所有可用集群上下文
kubectl config get-contexts
# 切换到目标集群
kubectl config use-context k8s
# 验证当前上下文
kubectl config current-context
步骤 2:创建 ClusterRole
# 命令式创建
kubectl create clusterrole deployment-clusterrole \
--verb=create \
--resource=deployments.apps,statefulsets.apps,daemonsets.apps
# 验证创建结果
kubectl describe clusterrole deployment-clusterrole若需要通过 YAML 声明式创建,内容如下:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-clusterrole
rules:
- apiGroups: ["apps"] # Deployment/StatefulSet/DaemonSet 属于 apps 组
resources:
- deployments
- statefulsets
- daemonsets
verbs: ["create"]步骤 3:创建 ServiceAccount
# 在 app-team1 命名空间中创建 ServiceAccount
kubectl create serviceaccount cicd-token -n app-team1
# 验证(注意命名空间)
kubectl get serviceaccounts -n app-team1
kubectl describe serviceaccount cicd-token -n app-team1步骤 4:创建 RoleBinding
注意:使用 RoleBinding,而不是 ClusterRoleBinding,这样权限才会被限制在 app-team1 命名空间内。
# 重要:使用 RoleBinding(非 ClusterRoleBinding)来限制权限范围
kubectl create rolebinding cicd-token-binding \
--namespace=app-team1 \
--clusterrole=deployment-clusterrole \
--serviceaccount=app-team1:cicd-token
# 验证绑定关系
kubectl describe rolebinding cicd-token-binding -n app-team1步骤 5:验证权限(auth can-i)
# 验证 cicd-token 是否可以在 app-team1 创建 deployment
kubectl auth can-i create deployments \
--as=system:serviceaccount:app-team1:cicd-token \
-n app-team1
# 预期输出: yes
# 验证无法创建 pods(权限未授予,应返回 no)
kubectl auth can-i create pods \
--as=system:serviceaccount:app-team1:cicd-token \
-n app-team1
# 预期输出: no
# 验证在其他命名空间无权限(RoleBinding 的限制生效)
kubectl auth can-i create deployments \
--as=system:serviceaccount:app-team1:cicd-token \
-n default
# 预期输出: no
说明
--as=system:serviceaccount:<namespace>:<name> 是模拟某个 ServiceAccount 身份进行权限检查的标准写法。auth can-i 只做权限判断,不会真正执行资源创建操作。
1.3 进阶任务:复合 ClusterRole + 用户/ServiceAccount 绑定
场景:
创建一个更完整的 CI/CD 角色,同时支持:
命名空间内的 ServiceAccount 使用
外部用户
jenkins-user使用
1.3.1 创建复合 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pipeline-manager-clusterrole
rules:
# 核心 API 组(apiGroups 为空字符串 "")
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
# batch 组:Job 和 CronJob
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["create", "get", "update"]
# apps 组:工作负载控制器
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["create", "get", "update", "delete"]
1.3.2 资源与 API 组速查表
资源类型 | API 组 | 常用动词 | 说明 |
|---|---|---|---|
Pod / Service / ConfigMap / Secret |
| get, list, watch | 核心资源,属于空字符串 API 组 |
Deployment / StatefulSet / DaemonSet / ReplicaSet |
| create, get, update, delete | 工作负载控制器 |
Job / CronJob |
| create, get, update, delete | 一次性和周期性任务 |
HorizontalPodAutoscaler |
| create, get, update | 水平自动伸缩 |
Ingress / NetworkPolicy |
| create, get, update | 网络流量控制 |
PersistentVolume / StorageClass |
| get, list | 存储资源 |
Role / RoleBinding |
| create, get | RBAC 资源本身 |
1.3.3 RoleBinding vs ClusterRoleBinding 选择原则
绑定类型 | 引用的角色 | 权限生效范围 | 适用场景 |
RoleBinding | Role 或 ClusterRole | 仅在 RoleBinding 所在的命名空间 | CI/CD 服务账户、开发团队成员 |
ClusterRoleBinding | 只能是 ClusterRole | 整个集群所有命名空间 | 集群管理员、跨命名空间的系统组件 |
最佳实践:能用 RoleBinding 就不要用 ClusterRoleBinding。
只有当主体必须访问多个命名空间,或访问集群级资源时,才考虑 ClusterRoleBinding。
1.3.4 创建 ServiceAccount + RoleBinding(声明式)
先创建命名空间和 ServiceAccount:
# 命令式
kubectl create namespace dev-team1
kubectl create serviceaccount cicd-serviceaccount -n dev-team1
创建 RoleBinding,将 ClusterRole 绑定到 ServiceAccount,权限限制在 dev-team1 命名空间:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pipeline-manager-rolebinding
namespace: dev-team1
subjects:
- kind: ServiceAccount
name: cicd-serviceaccount
namespace: dev-team1
roleRef:
kind: ClusterRole # 注意:引用的是 ClusterRole,但生效范围由 RoleBinding 限制
name: pipeline-manager-clusterrole
apiGroup: rbac.authorization.k8s.io1.3.5 创建 ClusterRoleBinding(绑定外部用户)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pipeline-manager-clusterrolebinding
subjects:
- kind: User
name: jenkins-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: pipeline-manager-clusterrole
apiGroup: rbac.authorization.k8s.io
说明
这个 ClusterRoleBinding 会让 jenkins-user 在集群所有命名空间内都拥有 pipeline-manager-clusterrole 中定义的权限。
如果只想限制到 dev-team1,就应该改成 RoleBinding。
1.4 RBAC 验证清单
完成 RBAC 配置后,按以下清单逐项验证:
验证项 | 验证命令 | 预期结果 |
|---|---|---|
ClusterRole 已创建 |
| 显示角色名称 |
ServiceAccount 已创建 |
| 显示 SA 名称 |
RoleBinding 已创建 |
| 显示绑定名称 |
权限验证-有权限 |
| 输出 yes |
权限验证-无越权 |
| 输出 no |
跨命名空间隔离 |
| 输出 no |
2. Deployment 扩缩容操作
2.1 核心概念
Deployment 通过 ReplicaSet 管理 Pod 副本数。
扩缩容是最常见的操作,分为:
手动扩缩容
自动扩缩容(HPA)
方式 | 命令/资源 | 适用场景 | 是否实时生效 |
|---|---|---|---|
手动扩缩容 |
| 临时流量应对、测试环境 | 是 |
声明式修改 |
| GitOps、变更追踪 | 是 |
水平自动伸缩 | HPA | 生产环境动态负载 | 是(自动) |
2.2 手动扩缩容标准操作
场景: 将 loadbalancer Deployment 从 2 副本扩容到 6 副本。
步骤 1:查看当前 Deployment 状态
# 查看 Deployment 当前副本数
kubectl get deployment loadbalancer
# 预期输出:
# NAME READY UP-TO-DATE AVAILABLE AGE
# loadbalancer 2/2 2 2 33m步骤 2:执行扩容操作
# 方法一:命令式扩容
kubectl scale deployment loadbalancer --replicas=6
# 方法二:patch 方式(适合脚本自动化)
kubectl patch deployment loadbalancer -p '{"spec":{"replicas":6}}'
# 方法三:edit 交互式修改(修改 spec.replicas 字段为6)
kubectl edit deployment loadbalancer
# 步骤 3:验证扩容结果
# 查看副本数量是否变为 6
kubectl get deployment loadbalancer
# 预期:READY 6/6
# 查看 Pod 分布情况
kubectl get pods -l app=loadbalancer -o wide
# 查看扩容事件
kubectl describe deployment loadbalancer | grep -A5 Events
2.3 HPA 水平自动伸缩(生产必知)
HPA 会根据 CPU、内存或其他指标自动调整副本数,是生产环境常用方案。
2.3.1 前置条件
Metrics Server 已部署
kubectl top pods可以正常返回数据Deployment 已设置
resources.requests
2.3.2 创建 HPA
# 命令式创建(基于 CPU 利用率)
kubectl autoscale deployment loadbalancer \
--min=2 \
--max=10 \
--cpu=70%
# 或使用 YAML 声明式(更灵活,支持多指标)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: loadbalancer-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: loadbalancer
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
2.3.3 查看 HPA 状态
# 查看 HPA 当前状态(包含当前利用率和当前副本数)
kubectl get hpa loadbalancer-hpa
# 详细信息(包含扩缩容事件和冷却时间)
kubectl describe hpa loadbalancer-hpa
补充建议
生产环境里,通常会同时考虑:
HPA:负责自动扩缩容
PDB:负责保证最小可用副本数
这样能兼顾弹性和可用性。
2.4 扩缩容验证清单
验证项 | 命令 | 预期 |
|---|---|---|
副本数正确 |
| READY = 目标副本数 |
Pod 全部 Running |
| STATUS 全为 Running |
无异常事件 |
| Events 无 Warning |
Service 正常路由 |
| Endpoints 数量合理 |
3. NetworkPolicy 网络策略
NetworkPolicy 是 Kubernetes 的网络访问控制机制。
默认情况下,如果 CNI 支持并且未启用限制,Pod 之间通常是可以互通的。
一旦某个 Pod 被 NetworkPolicy 选中,就会进入“白名单模式”:只有策略明确允许的流量才能通过。
概念 | 说明 |
|---|---|
Ingress | 控制哪些流量可以进入 Pod |
Egress | 控制 Pod 可以发出的流量 |
podSelector | 选择被策略保护的 Pod |
namespaceSelector | 按命名空间标签筛选流量来源或目标 |
ipBlock | 按 CIDR 指定 IP 段 |
policyTypes | 声明策略控制 Ingress、Egress 或两者 |
关键规则
如果某个 Pod 被任意 NetworkPolicy 选中,并且策略声明了
policyTypes: [Ingress],那么这个 Pod 的入站流量默认全部拒绝Egress 同理
podSelector: {}表示选择命名空间内所有 PodNetworkPolicy 是否真正生效,取决于你的 CNI 是否支持它
3.2 基础任务:命名空间间端口隔离
场景:
创建策略 allow-port-from-namespace,只允许 corp 命名空间中的 Pod 访问 internal 命名空间中监听 80 端口的 Pod。
步骤 1:为命名空间添加标签
NetworkPolicy 依赖标签选择
# 查看 corp 命名空间现有标签
kubectl get namespace corp --show-labels
# 为 corp 命名空间添加标签
kubectl label namespace corp project=corp
# 为 internal 命名空间添加标签(备用)
kubectl label namespace internal project=internal
# 验证标签
kubectl get namespace --show-labels | grep -E "corp|internal"
步骤 2:编写并应用 NetworkPolicy YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace
namespace: internal # 策略保护 internal 命名空间中的 Pod
spec:
podSelector: {} # {} = 选中 internal 命名空间中所有 Pod
policyTypes:
- Ingress # 只管入站流量
ingress:
- from: # from 和 ports 必须对齐(同级)
- namespaceSelector:
matchLabels:
project: corp # 只允许 project=corp 标签的命名空间
ports:
- protocol: TCP
port: 80 # 只允许 80 端口
说明
namespace: internal表示策略作用于internal命名空间podSelector: {}表示选中internal命名空间所有 PodpolicyTypes: [Ingress]表示只限制入站from里的 namespaceSelector 允许project=corp的命名空间访问只放行 TCP 80
步骤 3:验证 NetworkPolicy 效果
# 查看策略详情
kubectl describe networkpolicy allow-port-from-namespace -n internal
# 获取 internal 命名空间 Pod 的 IP 地址
kubectl get pod -n internal -o wide
# 测试 1:从 corp 命名空间内发起请求(应成功)
kubectl exec -it -n corp <corp-pod-name> -- curl <internal-pod-ip>:80
# 预期:返回 nginx 欢迎页
# 测试 2:从其他命名空间发起请求(应失败)
kubectl exec -it -n default <default-pod-name> -- curl <internal-pod-ip>:80
# 预期:请求超时或连接拒绝
# 测试 3:访问非 80 端口(应失败)
kubectl exec -it -n corp <corp-pod-name> -- curl <internal-pod-ip>:8080
# 预期:请求超时
推荐做法
生产环境中,尽量通过 Service DNS 访问,而不是直接用 Pod IP。
因为 Pod IP 会随重建变化,Service 名称更稳定。
3.3 进阶任务:多命名空间多端口策略
场景:
在 internal 命名空间中,同时控制:
来自多个命名空间的 Ingress
发往多个命名空间的 Egress
流量规则汇总
方向 | 来源/目标命名空间 | 端口 | 协议 | 说明 |
|---|---|---|---|---|
Ingress | corp | 80 | TCP | HTTP 请求 |
Ingress | monitoring | 9090 | TCP | Prometheus 指标采集 |
Ingress | logging | 514 | TCP | Syslog 日志收集 |
Egress | cache | 6379 | TCP | Redis 缓存访问 |
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-multiple-ports-and-namespaces
namespace: internal
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
# 规则1:允许 corp 命名空间访问 80 端口
- from:
- namespaceSelector:
matchLabels:
project: corp
ports:
- protocol: TCP
port: 80
# 规则2:允许 monitoring 命名空间访问 9090 端口(Prometheus)
- from:
- namespaceSelector:
matchLabels:
project: monitoring
ports:
- protocol: TCP
port: 9090
# 规则3:允许 logging 命名空间访问 514 端口(Syslog)
- from:
- namespaceSelector:
matchLabels:
project: logging
ports:
- protocol: TCP
port: 514
egress:
# 规则4:允许访问 cache 命名空间的 6379 端口(Redis)
- to:
- namespaceSelector:
matchLabels:
project: cache
ports:
- protocol: TCP
port: 6379
3.4 高级场景:AND 与 OR 逻辑的正确写法
NetworkPolicy 的 from/to 规则支持 AND(与)和 OR(或)逻辑,这是最容易混淆的知识点。
3.4.1 OR 逻辑(两个条件满足其一即可)
多个 - 条目表示 OR。
ingress:
- from:
- namespaceSelector: # 条件1
matchLabels:
project: corp
- podSelector: # 条件2(与条件1是 OR 关系)
matchLabels:
app: frontend
# 以上:来自 project=corp 命名空间 OR 带有 app=frontend 标签的 Pod 均可访问
意思是:
来自
project=corp的命名空间,或者来自
app=frontend的 Pod
都可以访问。
3.4.2 AND 逻辑(必须同时满足所有条件)
同一个 - 条目下同时写 namespaceSelector 和 podSelector,表示 AND。
ingress:
- from:
- namespaceSelector: # 条件1
matchLabels:
project: corp
podSelector: # 条件2(与条件1是 AND 关系,注意缩进对齐!)
matchLabels:
app: frontend
# 以上:必须来自 project=corp 命名空间 AND 带有 app=frontend 标签的 Pod
意思是:
必须来自
project=corp命名空间并且 Pod 标签必须是
app=frontend
两个条件同时满足,才允许访问。
判断技巧
两个独立的
-条目:OR同一个条目里同时写多个 selector:AND
3.5 DNS 解析放通
当 Pod 配置了 Egress 策略后,DNS 解析也可能被阻断。
因此生产环境里通常要显式放通 DNS。
推荐放行到 kube-system 命名空间中 DNS 服务所在的 Pod,并允许 UDP/TCP 53。
egress:
# 放通 DNS(必须!否则域名解析失败)
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# 其他 Egress 规则...
- to:
- namespaceSelector:
matchLabels:
project: cache
ports:
- protocol: TCP
port: 6379
3.6 NetworkPolicy 验证清单
验证项 | 命令 | 预期结果 |
|---|---|---|
命名空间标签存在 |
| 目标命名空间有正确标签 |
策略已应用 |
| 显示正确的 Ingress/Egress 规则 |
允许流量可通过 |
| 正常返回响应 |
拒绝流量被阻断 |
| 超时或 Connection refused |
DNS 解析正常 |
| 返回 IP 地址 |
4. 常见故障排查指南
4.1 RBAC 故障排查
故障现象 | 可能原因 | 排查命令 | 解决方法 |
|---|---|---|---|
| RoleBinding 未创建或绑定错误 |
| 检查并重建 RoleBinding |
| ClusterRole 中缺少对应 verb |
| 在 ClusterRole rules 中补充 verb |
ServiceAccount 无法访问 | SA 名称或命名空间错误 |
| 确认 |
| 尝试修改已存在绑定的 roleRef |
| 删除后重建 RoleBinding |
4.2 NetworkPolicy 故障排查
故障现象 | 可能原因 | 排查步骤 |
|---|---|---|
所有流量都被拒绝 | 命名空间缺少标签 |
|
DNS 解析失败 | Egress 策略未放通 53 端口 | 添加 UDP/TCP 53 egress 规则 |
策略不生效(全部放通) | CNI 不支持 NetworkPolicy | 检查是否使用支持 NetworkPolicy 的 CNI |
AND 条件失效(变成 OR) |
| 检查 |
4.3 常用诊断命令速查
RBAC 诊断
kubectl auth can-i <verb> <resource> -n <ns> --as=system:serviceaccount:<ns>:<sa>
kubectl get clusterrole,clusterrolebinding | grep <keyword>
kubectl get role,rolebinding -n <namespace>
kubectl describe clusterrole <name>NetworkPolicy 诊断
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <name> -n <namespace>
kubectl get namespace --show-labelsDeployment 诊断
kubectl rollout status deployment/<name>
kubectl rollout history deployment/<name>
kubectl get events -n <ns> --sort-by=.lastTimestamp5 技巧
5.1 快速生成 YAML 模板命令
生成 ClusterRole YAML 模板
kubectl create clusterrole <name> \
--verb=get,list \
--resource=pods \
--dry-run=client -o yaml > clusterrole.yaml生成 RoleBinding YAML 模板
kubectl create rolebinding <name> \
--clusterrole=<cr> \
--serviceaccount=<ns>:<sa> -n <ns> \
--dry-run=client -o yaml > rolebinding.yaml查看 NetworkPolicy 字段
kubectl explain networkpolicy.spec.ingress
kubectl explain networkpolicy.spec.egress生成 Deployment 模板
kubectl create deployment <name> --image=nginx --replicas=3 \
--dry-run=client -o yaml > deploy.yaml5.2 必备命令速查表
操作 | 命令 | 说明 |
|---|---|---|
切换集群 |
| 必做 |
查看当前集群 |
| 确认上下文 |
查看所有集群 |
| 列出所有可用集群 |
权限检查 |
| 验证 RBAC 是否生效 |
查看 API 资源 |
| 查看资源名 |
查看字段说明 |
| 查看 YAML 字段含义 |
强制删除 Pod |
| 快速删除卡住的 Pod |
查看日志 |
| 查看上一次容器日志 |