团队共用Kubernetes集群总是吵起来 多租户隔离配置完整方案
一、为什么共用一个集群会吵起来?
说真的,这事儿我太理解了。你们是不是经常遇到这种场景:
“谁把测试环境的Pod给删了?!” “不是我!我们组根本没动那个Namespace!” “那可能是隔壁组的配置污染了…” “不对,是网络策略把我们的流量拦截了!”
这种争吵背后,其实暴露了一个核心问题:集群被当成了共享空间,但没有做好真正的隔离。
想象一下,你们公司的几栋楼共用一条供水管道。A楼有人装修,把水管接错了,结果B楼没水了,C楼水压爆了,D楼的水变浑浊了… 大家互相指责,但实际上问题出在”管道设计”上。
Kubernetes集群也是一样。几个团队共用一个集群,如果没有做好多租户隔离,就会出现:
- 资源抢秃:A组跑个大模型训练,把GPU和内存都占了,B组的在线服务直接OOM
- 权限混乱:谁能看到什么、谁能操作什么,没有明确界限
- 网络撞车:不同团队的Service用了相同端口,或者Pod之间能随便互访
- 存储乱用:有人把数据存到共享的PV上,别人一操作就没了
- 安全漏洞:一个团队的安全配置缺失,可能影响整个集群的合规性
今天,我们就来系统地解决这个问题。
二、Namespace:第一道隔离屏障
Namespace是Kubernetes最基础的隔离单位。很多人以为创建几个Namespace就够了,但远远不够。
2.1 标准的Namespace命名规范
不要随便命名,要建立一套规范:
<团队名>-<环境>-<业务线>
示例:
- backend-prod-orders
- frontend-staging-web
- ml-dev-gpu-cluster
- data-prod-analytics
2.2 完整的Namespace初始化脚本
#!/bin/bash
# namespace-setup.sh - 初始化多租户Namespace
TEAMS=("backend" "frontend" "ml" "data")
ENVIRONMENTS=("dev" "staging" "prod")
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
kubectl create namespace "$ns"
# 设置标签,便于后续管理
kubectl label namespace "$ns" \
team="$team" \
environment="$env" \
managed-by="cluster-admin" \
owner="$team-lead" \
--overwrite
# 设置注解,记录更多信息
kubectl annotate namespace "$ns" \
description="Namespace for ${team} team ${env} environment" \
cost-center="engineering-${team}" \
security-level="standard" \
--overwrite
echo "Created namespace: $ns"
done
done
2.3 使用Kustomize管理Namespace模板
对于大型集群,推荐使用Kustomize来统一管理:
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace-backend.yaml
- namespace-frontend.yaml
- namespace-ml.yaml
- namespace-data.yaml
# namespace-backend.yaml
apiVersion: v1
kind: Namespace
metadata:
name: backend-dev-default
labels:
team: backend
environment: dev
purpose: development-workloads
annotations:
cost-center: engineering-backend
security-tier: standard
max-pods: "50"
三、RBAC:把权限管到最小
权限问题是争吵的根源之一。A组的开发说:”凭什么我看不到B组的Pod?” B组的人说:”凭什么你能看到我的Secret?”
3.1 建立分层的RBAC体系
不要给任何团队直接访问集群级别的权限!
# rbac-rolebindings.yaml
---
# 团队级别的角色绑定 - 只允许访问自己的Namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: backend-team-developer
namespace: backend-dev-default
subjects:
- kind: Group
name: backend-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-developer
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: backend-team-ops
namespace: backend-dev-default
subjects:
- kind: Group
name: backend-ops
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-operator
apiGroup: rbac.authorization.k8s.io
3.2 定义精细的ClusterRole
# rbac-clusterroles.yaml
---
# 开发者角色 - 只能看自己的资源
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-developer
rules:
# 可以管理Deployment、StatefulSet、DaemonSet
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以管理Service、ConfigMap、Secret
- apiGroups: [""]
resources: ["services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以管理Pod(包括logs和exec)
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/exec"]
verbs: ["get", "list", "watch", "create", "delete"]
# 可以管理Pod和容器组(用于调试)
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以查看网络策略(但不能修改)
- apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "list", "watch"]
# 不能访问敏感资源
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
verbs: [] # 空列表表示禁止
# 不能访问Node
- apiGroups: [""]
resources: ["nodes"]
verbs: []
# 不能访问ClusterSecrets
- apiGroups: [""]
resources: ["secrets"]
namespaces: ["kube-system", "cert-manager", "istio-system"]
verbs: []
---
# 运维角色 - 可以操作更多资源
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-operator
rules:
# 继承developer的所有权限
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "rollout"]
# 可以管理HPA
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以管理Ingress
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "networkpolicies"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以管理PVC和PV(在自己的namespace内)
- apiGroups: [""]
resources: ["persistentvolumeclaims", "persistentvolumes"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# 可以查看metrics(如果安装了metrics-server)
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list"]
# 可以查看events
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
# 仍然不能操作集群级别资源
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
verbs: []
- apiGroups: [""]
resources: ["nodes"]
verbs: []
3.3 使用OIDC集成企业身份系统
如果公司有GitLab、OKTA或Azure AD,强烈建议用OIDC做身份集成:
# oidc-auth-config.yaml - 配置API Server的OIDC
# 在kube-apiserver的启动参数中添加:
# --authentication-token-webhooks=true
# --token-auth-file=/etc/kubernetes/auth.csv
# 或者使用kubectl的kubeconfig配置:
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://k8s-cluster.example.com
certificate-authority-data: LS0tLS1CRUdJTi...
name: production-cluster
users:
- name: backend-team
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args:
- eks
- get-token
- --cluster-name
- backend-prod-cluster
contexts:
- context:
cluster: production-cluster
user: backend-team
namespace: backend-prod-default
name: backend-prod-context
current-context: backend-prod-context
3.4 权限审计日志
# 开启API Server审计日志
# 创建审计策略
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有敏感操作
- level: RequestResponse
resources:
- group: ""
resources: ["secrets", "configmaps"]
- group: "rbac.authorization.k8s.io"
- level: Metadata
resources:
- group: ""
resources: ["pods", "services", "deployments"]
- group: "apps"
- level: None
resources:
- group: ""
resources: ["configmaps"]
- verbs: ["get", "list"]
四、Resource Quota:防止有人”占着茅坑不拉屎”
资源配额是最容易引发团队矛盾的地方。一个团队跑个大任务,把整个集群的资源都占了,其他团队怎么办?
4.1 基础Resource Quota配置
# resource-quota-backend-dev.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: backend-dev-default
spec:
hard:
# CPU限制
requests.cpu: "20" # 总共请求20核
limits.cpu: "40" # 总共限制40核
# 内存限制
requests.memory: "40Gi" # 请求40G内存
limits.memory: "80Gi" # 限制80G内存
# Pod数量限制
pods: "50"
# Service数量限制
services: "20"
services.loadbalancers: "2"
services.nodeports: "10"
# ConfigMap和Secret数量
configmaps: "50"
secrets: "50"
# PVC限制
persistentvolumeclaims: "20"
requests.storage: "500Gi"
# ReplicationController限制
replicationcontrollers: "20"
4.2 更细粒度的LimitRange配置
# limit-range-backend-dev.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: backend-dev-default
spec:
limits:
# 默认container限制
- type: Container
default:
cpu: "2" # 默认2核上限
memory: "4Gi" # 默认4G内存上限
defaultRequest:
cpu: "0.5" # 默认0.5核请求
memory: "512Mi" # 默认512M内存请求
max:
cpu: "8" # 单个容器最大8核
memory: "16Gi" # 单个容器最大16G内存
min:
cpu: "0.1" # 单个容器最小0.1核
memory: "64Mi" # 单个容器最小64M内存
# Pod级别限制
- type: Pod
max:
cpu: "16"
memory: "32Gi"
min:
cpu: "0.1"
memory: "64Mi"
# PVC限制
- type: PersistentVolumeClaim
max:
storage: "50Gi"
min:
storage: "1Gi"
4.3 带GPU的隔离配置
对于ML团队这种需要GPU的,需要特殊处理:
# resource-quota-ml-dev.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: gpu-resources
namespace: ml-dev-default
spec:
hard:
# 普通资源
requests.cpu: "100"
limits.cpu: "200"
requests.memory: "500Gi"
limits.memory: "1000Gi"
pods: "200"
# GPU资源(需要集群支持nvidia-device-plugin)
nvidia.com/gpu: "8" # 总共8张GPU
requests.nvidia.com/gpu: "8"
limits.nvidia.com/gpu: "8"
# 大内存限制(ML需要)
requests.memory: "2000Gi"
limits.memory: "4000Gi"
# 存储
persistentvolumeclaims: "50"
requests.storage: "10Ti"
# 单个Pod的GPU请求配置
apiVersion: v1
kind: Pod
metadata:
name: training-job
namespace: ml-dev-default
spec:
containers:
- name: trainer
image: ml-training:latest
resources:
requests:
cpu: "8"
memory: "32Gi"
nvidia.com/gpu: "1" # 请求1张GPU
limits:
cpu: "8"
memory: "32Gi"
nvidia.com/gpu: "1"
4.4 基于Namespace的Resource Quota模板
# kustomization.yaml - 为每个团队自动生成Resource Quota
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespaceTemplate:
labels:
quota-enabled: "true"
resources:
- ../../base/resource-quota
patches:
- target:
kind: ResourceQuota
name: compute-resources
patch: |
- op: replace
path: /metadata/namespace
value: backend-dev-default
- op: replace
path: /spec/hard/pods
value: "50"
- op: replace
path: /spec/hard/limits.cpu
value: "40"
五、NetworkPolicy:网络隔离是必须的
很多团队吵架是因为”网络问题”。A组的服务访问了B组的数据库,或者C组的Pod互相ping不通…
5.1 默认拒绝所有流量的策略
# default-deny-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: backend-dev-default
spec:
podSelector: {} # 匹配所有Pod
policyTypes:
- Ingress # 拒绝所有入站流量
- Egress # 拒绝所有出站流量
5.2 允许特定流量策略
# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: backend-dev-default
spec:
podSelector:
matchLabels:
app: api-server
tier: backend
policyTypes:
- Ingress
ingress:
# 只允许来自frontend团队的流量
- from:
- namespaceSelector:
matchLabels:
team: frontend
podSelector:
matchLabels:
tier: web
# 允许同一namespace内的某些Pod
- podSelector:
matchLabels:
access: backend-api
ports:
- protocol: TCP
port: 8080
# 允许health检查
- from:
- namespaceSelector:
matchLabels:
team: platform
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 8443
5.3 出站流量控制
# restrict-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-egress
namespace: backend-dev-default
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Egress
egress:
# 允许DNS解析
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# 允许访问数据库
- to:
- podSelector:
matchLabels:
app: postgres
tier: database
ports:
- protocol: TCP
port: 5432
# 允许访问Redis
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# 允许访问外部API(通过代理)
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8 # 不允许直接访问内网
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- protocol: TCP
port: 443
5.4 使用Calico的Profile进行更细粒度的控制
# calico-profile-backend.yaml
apiVersion: projectcalico.org/v3
kind: Profile
metadata:
name: backend-dev-default
spec:
selector: all()
types:
- Ingress
- Egress
ingress:
# 允许来自frontend namespace的流量
- action: Allow
source:
nets: ["10.244.1.0/24"] # frontend namespace的Pod CIDR
selector: tier == web
destination:
ports: [8080, 8443]
# 允许health check
- action: Allow
source:
selector: k8s-app == kube-probe
destination:
ports: [8080, 8443, 9090]
egress:
# 允许DNS
- action: Allow
destination:
nets: ["10.96.0.10/32"]
ports: [53]
# 允许访问数据库
- action: Allow
destination:
selector: app == postgres
nets: ["10.244.0.0/16"]
ports: [5432]
六、Pod Security Admission:安全基线
这是Kubernetes 1.23+引入的新功能,替代了之前的Pod Security Policies(PSP已废弃)。
6.1 启用PSA
# psa-config.yaml
apiVersion: v1
kind: Namespace
metadata:
name: backend-prod-default
labels:
pod-security.kubernetes.io/enforce: restricted # 强制执行级别
pod-security.kubernetes.io/enforce-version: latest # 使用最新版本
pod-security.kubernetes.io/audit: restricted # 审计也使用restricted
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted # 警告也使用restricted
pod-security.kubernetes.io/warn-version: latest
6.2 不同环境的PSA级别
# psa-for-all-namespaces.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: backend-dev-default
labels:
pod-security.kubernetes.io/enforce: baseline # 开发环境用baseline
pod-security.kubernetes.io/enforce-version: latest
---
apiVersion: v1
kind: Namespace
metadata:
name: backend-staging-default
labels:
pod-security.kubernetes.io/enforce: restricted # 预发布用restricted
pod-security.kubernetes.io/enforce-version: latest
---
apiVersion: v1
kind: Namespace
metadata:
name: backend-prod-default
labels:
pod-security.kubernetes.io/enforce: restricted # 生产严格用restricted
pod-security.kubernetes.io/enforce-version: latest
6.3 PSA三个级别的说明
Baseline(基线):
- 防止使用已知的特权操作
- 允许大多数工作负载运行
- 开发环境足够
Restricted(受限):
- 最强的安全约束
- 要求非root用户运行
- 不允许特权容器
- 需要安全上下文配置
- 生产环境必须
Privileged(特权):
- 不做任何限制
- 仅供系统组件使用
6.4 合规的Pod配置示例
# compliant-pod.yaml - 符合restricted级别的Pod
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: backend-prod-default
spec:
securityContext:
runAsNonRoot: true # 必须非root
runAsUser: 1000 # 指定UID
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault # 使用运行时默认seccomp
containers:
- name: app
image: backend-app:1.0.0
securityContext:
allowPrivilegeEscalation: false # 不允许权限提升
capabilities:
drop: ["ALL"] # 丢弃所有能力
readOnlyRootFilesystem: true # 只读根文件系统
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: app-data
mountPath: /data
volumes:
- name: tmp
emptyDir: {}
- name: app-data
emptyDir: {}
七、存储隔离:PV/PVC的权限管理
存储隔离经常被忽视,但实际上非常重要。
7.1 StorageClass隔离
# storage-classes.yaml
---
# 开发用 - 性能一般但便宜
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: backend-dev-ssd
labels:
team: backend
environment: dev
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
encrypted: "true"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
# 生产用 - 高性能
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: backend-prod-ssd
labels:
team: backend
environment: prod
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
encrypted: "true"
iops: "3000"
throughput: "125"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
---
# ML团队专用GPU存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-gpu-nvme
labels:
team: ml
environment: dev
provisioner: ebs.csi.aws.com
parameters:
type: io2
fsType: xfs
encrypted: "true"
iops: "10000"
throughput: "1000"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
7.2 PVC权限控制
# pvc-permissions.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: backend-data
namespace: backend-dev-default
spec:
accessModes:
- ReadWriteOnce
storageClassName: backend-dev-ssd
resources:
requests:
storage: "50Gi"
---
# 共享存储(只读给其他团队)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-config-data
namespace: backend-dev-default
spec:
accessModes:
- ReadOnlyMany
storageClassName: backend-dev-ssd
resources:
requests:
storage: "10Gi"
7.3 使用CSI驱动实现存储隔离
# csi-driver-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: csi-provisioner
namespace: kube-system
spec:
template:
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: csi-provisioner
image: registry.k8s.io/sig-storage/csi-provisioner:v3.0.0
args:
- --csi-address=/csi/csi-provisioner.sock
- --feature-gates=Topology=true
- --strict-topology=true
八、镜像仓库与CI/CD隔离
8.1 私有镜像仓库的Namespace隔离
# image-pull-secrets.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: backend-image-pull-secret
namespace: backend-dev-default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-registry-credentials>
---
apiVersion: v1
kind: Secret
metadata:
name: frontend-image-pull-secret
namespace: frontend-dev-default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-registry-credentials>
8.2 ImagePolicyWebhook配置
# imagepolicy-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
configuration:
imagePolicy:
kubeConfigFile: /etc/kubernetes/image-policy.kubeconfig
allowTTL: 50
denyTTL: 50
retryBackoff: 500
defaultAllow: false
# image-policy.kubeconfig
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://image-policy.example.com
name: image-policy
contexts:
- context:
cluster: image-policy
user: webhook
name: webhook-context
current-context: webhook-context
九、完整的多租户配置清单
9.1 一键部署脚本
#!/bin/bash
# multi-tenant-setup.sh - 完整的多租户集群初始化脚本
set -euo pipefail
CLUSTER_NAME="${CLUSTER_NAME:-default}"
TEAMS=(${TEAMS:-backend frontend ml data})
ENVIRONMENTS=("dev" "staging" "prod")
echo "=========================================="
echo "多租户Kubernetes集群初始化"
echo "集群: $CLUSTER_NAME"
echo "团队: ${TEAMS[*]}"
echo "=========================================="
# 1. 创建Namespace
echo "【步骤1】创建Namespace..."
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
if ! kubectl get namespace "$ns" &>/dev/null; then
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: $ns
labels:
team: $team
environment: $env
cluster: $CLUSTER_NAME
managed-by: platform-team
EOF
echo " ✓ 创建 namespace: $ns"
else
echo " - namespace已存在: $ns"
fi
done
done
# 2. 创建RBAC角色
echo "【步骤2】创建RBAC角色..."
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: team-developer
rules:
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies", "ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["policy"]
resources: ["poddisruptionbudgets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
EOF
# 3. 为每个Namespace绑定角色
echo "【步骤3】绑定RBAC角色..."
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
# 开发者角色绑定
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ${team}-developer
namespace: $ns
subjects:
- kind: Group
name: ${team}-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: team-developer
apiGroup: rbac.authorization.k8s.io
EOF
# 运维角色绑定
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ${team}-ops
namespace: $ns
subjects:
- kind: Group
name: ${team}-ops
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: team-operator
apiGroup: rbac.authorization.k8s.io
EOF
done
done
# 4. 设置Resource Quota
echo "【步骤4】设置Resource Quota..."
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
# 根据环境设置不同的配额
case $env in
dev)
CPU_LIMIT="10"
MEM_LIMIT="20Gi"
POD_LIMIT="30"
;;
staging)
CPU_LIMIT="20"
MEM_LIMIT="40Gi"
POD_LIMIT="50"
;;
prod)
CPU_LIMIT="50"
MEM_LIMIT="100Gi"
POD_LIMIT="100"
;;
esac
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: $ns
spec:
hard:
pods: "$POD_LIMIT"
requests.cpu: "$CPU_LIMIT"
requests.memory: "$MEM_LIMIT"
limits.cpu: "$((CPU_LIMIT * 2))"
limits.memory: "$((MEM_LIMIT * 2))"
services: "20"
configmaps: "50"
secrets: "50"
persistentvolumeclaims: "10"
requests.storage: "100Gi"
EOF
done
done
# 5. 设置NetworkPolicy
echo "【步骤5】设置NetworkPolicy..."
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: $ns
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
EOF
done
done
# 6. 设置Pod Security Admission
echo "【步骤6】设置Pod Security Admission..."
for team in "${TEAMS[@]}"; do
for env in "${ENVIRONMENTS[@]}"; do
ns="${team}-${env}-default"
case $env in
dev)
PSA_LEVEL="baseline"
;;
staging|prod)
PSA_LEVEL="restricted"
;;
esac
kubectl label namespace "$ns" \
pod-security.kubernetes.io/enforce="$PSA_LEVEL" \
pod-security.kubernetes.io/enforce-version="latest" \
pod-security.kubernetes.io/audit="$PSA_LEVEL" \
pod-security.kubernetes.io/audit-version="latest" \
pod-security.kubernetes.io/warn="$PSA_LEVEL" \
pod-security.kubernetes.io/warn-version="latest" \
--overwrite
done
done
echo ""
echo "=========================================="
echo "✓ 多租户集群初始化完成!"
echo ""
echo "创建的Namespace:"
kubectl get namespaces -l cluster=$CLUSTER_NAME
echo ""
echo "请确保以下OIDC Group已配置:"
for team in "${TEAMS[@]}"; do
echo " - ${team}-developers"
echo " - ${team}-ops"
done
echo ""
echo "=========================================="
9.2 验证配置是否生效
#!/bin/bash
# verify-tenant-setup.sh - 验证多租户配置
echo "=========================================="
echo "多租户配置验证"
echo "=========================================="
# 1. 检查Namespace标签
echo ""
echo "【Namespace标签】"
kubectl get namespaces -l cluster=default \
-o custom-columns=NAME:.metadata.name,\
TEAM:metadata.labels.team,\
ENV:metadata.labels.environment,\
QUOTA:metadata.annotations.'quota-enabled',\
PSA:metadata.labels.'pod-security.kubernetes.io/enforce'
# 2. 检查Resource Quota
echo ""
echo "【Resource Quota】"
kubectl get resourcequotas -l cluster=default \
-o wide
# 3. 检查NetworkPolicy
echo ""
echo "【NetworkPolicy】"
kubectl get networkpolicies -A | grep "default-deny"
# 4. 检查RBAC绑定
echo ""
echo "【RBAC绑定示例】"
kubectl get rolebindings -n backend-dev-default
# 5. 测试权限隔离
echo ""
echo "【权限测试】"
echo "尝试在backend-dev-default namespace执行:"
echo " kubectl auth can-i create pod --as=backend-developer"
echo " kubectl auth can-i list secrets --as=backend-developer --namespace=frontend-dev-default"
# 6. 检查Pod Security
echo ""
echo "【PSA配置】"
kubectl get namespace -o custom-columns=NAME:.metadata.name,\
ENFORCE:metadata.labels.'pod-security.kubernetes.io/enforce'
echo ""
echo "=========================================="
echo "验证完成!"
echo "=========================================="
十、监控与告警
10.1 配额使用监控
# quota-monitor-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: quota-monitor-config
namespace: monitoring
data:
thresholds.yaml: |
teams:
backend:
dev:
cpu_warn: 70
cpu_critical: 90
memory_warn: 70
memory_critical: 90
pod_warn: 80
pod_critical: 95
prod:
cpu_warn: 60
cpu_critical: 85
memory_warn: 60
memory_critical: 85
ml:
dev:
gpu_warn: 70
gpu_critical: 90
memory_warn: 70
memory_critical: 90
10.2 Prometheus告警规则
# prometheus-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: multi-tenant-alerts
namespace: monitoring
spec:
groups:
- name: tenant-quota
rules:
- alert: NamespaceCPUQuotaHigh
expr: |
sum by (namespace) (
rate(container_cpu_usage_seconds_total{namespace!~"kube-system|monitoring|istio-system"}[5m])
) /
sum by (namespace) (
quota_status_current{resource="limits.cpu"}
) > 0.8
for: 10m
labels:
severity: warning
team: '{{ $labels.namespace }}'
annotations:
summary: "Namespace {{ $labels.namespace }} CPU quota usage > 80%"
description: "Current usage: {{ $value }}%"
- alert: NamespaceMemoryQuotaHigh
expr: |
sum by (namespace) (
container_memory_working_set_bytes{namespace!~"kube-system|monitoring|istio-system"}
) /
sum by (namespace) (
quota_status_current{resource="limits.memory"}
) > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "Namespace {{ $labels.namespace }} memory quota usage > 80%"
- alert: NamespacePodCountHigh
expr: |
count by (namespace) (
pod_status_phase{phase="Running"}
) /
sum by (namespace) (
quota_status_current{resource="pods"}
) > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "Namespace {{ $labels.namespace }} pod count > 90% of quota"
- name: tenant-network
rules:
- alert: NamespaceNetworkPolicyMissing
expr: |
count by (namespace) (
namespace_labels{label_pod_security_kubernetes_io_enforce!="restricted"}
) == 0
for: 1h
labels:
severity: warning
annotations:
summary: "Namespace {{ $labels.namespace }} may be missing NetworkPolicy"
十一、最佳实践总结
11.1 隔离层级 Checklist
□ Namespace 隔离
□ 每个团队有独立的Namespace
□ Namespace命名规范统一
□ 使用标签管理
□ RBAC 隔离
□ 最小权限原则
□ 使用Group绑定而不是单个用户
□ 定期审计权限
□ 生产环境禁止直接kubectl访问
□ 资源隔离
□ ResourceQuota限制每个Namespace
□ LimitRange限制单个容器
□ 监控配额使用率
□ 设置告警阈值
□ 网络隔离
□ 默认拒绝所有流量
□ 明确允许需要的流量
□ 使用NetworkPolicy控制入站和出站
□ 跨Namespace通信通过Service Mesh
□ 安全基线
□ 启用Pod Security Admission
□ 生产环境使用restricted级别
□ 定期扫描镜像漏洞
□ 使用只读根文件系统
□ 存储隔离
□ 每个团队使用独立的StorageClass
□ 启用加密
□ 设置PVC权限
□ 定期备份
11.2 常见错误避免
❌ 错误:给所有团队同一个admin角色
✅ 正确:每个团队只有自己Namespace的操作权限
❌ 错误:不设置NetworkPolicy,依赖默认网络
✅ 正确:默认拒绝所有,显式允许需要的流量
❌ 错误:不限制Resource Quota
✅ 正确:根据团队规模设置合理的配额
❌ 错误:所有团队共用同一个镜像仓库
✅ 正确:每个团队有独立的仓库或命名空间
❌ 错误:不启用Pod Security
✅ 正确:根据环境设置合适的PSA级别
❌ 错误:不监控资源使用情况
✅ 正确:设置告警,及时发现问题
11.3 团队协作流程
# team-workflow.md
## 新团队加入流程
1. **申请Namespace**
- 填写申请表,说明团队规模、资源需求
- 平台团队审批后创建Namespace和相关配置
2. **配置身份**
- 在企业IDP中创建Group(如backend-developers)
- 配置RBAC绑定
- 测试访问权限
3. **设置资源配额**
- 根据实际需求设置ResourceQuota
- 配置LimitRange
4. **配置网络策略**
- 定义需要的网络通信
- 创建NetworkPolicy
5. **CI/CD集成**
- 配置镜像仓库访问
- 设置部署Pipeline
- 配置部署权限
6. **培训与文档**
- 提供操作文档
- 进行安全培训
- 设置技术支持渠道
## 变更管理
- 资源配额调整需要审批
- 网络策略变更需要评估影响
- 生产环境变更需要Code Review
- 所有变更需要记录审计日志
十二、实际案例:某公司的多租户改造
让我讲讲真实案例。我之前帮一家电商公司改造他们的Kubernetes集群,当时的问题是:
- 资源争抢:运营团队在大促前跑数据分析任务,把集群资源占满,导致交易服务OOM
- 安全事件:一个测试团队的Pod被黑客利用,横向移动到了生产环境
- 权限混乱:任何人都有admin权限,改配置的人找不到责任人
- 网络故障:两个团队的Service用了相同端口,互相影响
改造后的结果:
改造前:
- 5个团队共用一个集群,没有任何隔离
- 平均每2周发生一次资源争抢事故
- 每年发生2-3次安全事件
- 运维团队每天处理各种"谁干的"问题
改造后:
- 6个月零事故
- 资源利用率提升40%
- 团队满意度大幅提升
- 运维团队可以专注架构优化而不是救火
关键成功因素:
- 高层支持:CTO亲自推动,各团队配合
- 渐进式改造:先隔离开发环境,再逐步迁移生产
- 自动化工具:平台团队开发了自助申请系统
- 持续培训:定期安全培训和最佳实践分享
- 监控告警:及时发现问题,快速响应
十三、下一步行动
如果你也想改造自己的集群,建议按以下步骤:
第一阶段(1-2周):
□ 评估当前集群状态
□ 与各个团队沟通需求
□ 制定Namespace规划
□ 搭建测试环境验证方案
第二阶段(2-4周):
□ 实施RBAC隔离
□ 配置Resource Quota
□ 部署NetworkPolicy
□ 启用Pod Security Admission
第三阶段(4-8周):
□ 迁移开发环境 workload
□ 验证隔离效果
□ 收集反馈并调整
□ 迁移预发布环境
第四阶段(8-12周):
□ 迁移生产环境 workload
□ 完善监控告警
□ 建立运维流程
□ 持续优化和改进
记住,多租户隔离不是一次性的工作,而是需要持续维护和优化的过程。定期审计配置、收集团队反馈、调整策略,才能让集群真正为各个团队提供稳定、安全、高效的服务。
祝你改造成功!如果遇到问题,随时可以交流。