4、多租户隔离设计:Namespace隔离、ResourceQuota与LimitRange配置、NetworkPolicy实现网络隔离
多租户隔离,说白了就是让不同用户或团队在同一个K8s集群里“各玩各的”,互不干扰。我刚开始接触K8s多租户时,觉得不就是建几个Namespace嘛,后来踩了坑才发现——隔离是个系统工程。
咱们今天聊三个核心维度:Namespace做逻辑隔离,ResourceQuota和LimitRange做资源隔离,NetworkPolicy做网络隔离。这三板斧用好了,你的vLLM推理服务才能安全稳定地跑在共享集群上。
4.1 Namespace隔离:最基础的“墙”
Namespace是K8s里最基础的隔离单元。每个Namespace就像一栋楼里的独立房间,里面的Pod、Service、ConfigMap都是自己的,别人看不见。
我个人习惯,每个租户分配一个独立的Namespace。比如租户A用tenant-a,租户B用tenant-b。这样哪怕两个租户都部署了同名的vLLM服务,也不会冲突。
核心要点:Namespace隔离的是“名字”,不是“资源”。也就是说,A租户的Pod仍然可以访问B租户的Service——除非你用NetworkPolicy拦住。
创建Namespace很简单:
kubectl create namespace tenant-a
kubectl create namespace tenant-b
嗯,这里要注意:光建Namespace是不够的。你想想看,如果A租户的Pod把集群所有CPU都吃光了,B租户怎么办?所以我们需要ResourceQuota。
4.2 ResourceQuota:给每个租户“画个圈”
ResourceQuota就是给Namespace设置资源上限。我在项目中遇到过,有个租户的vLLM推理任务因为模型加载时内存暴涨,直接把节点打挂了。从那以后,我每个Namespace必配ResourceQuota。
来看一个典型的配置:
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-a-quota
namespace: tenant-a
spec:
hard:
requests.cpu: "4"
requests.memory: "16Gi"
limits.cpu: "8"
limits.memory: "32Gi"
persistentvolumeclaims: "2"
pods: "10"
这个配置的意思是:租户A最多申请4核CPU、16Gi内存,上限是8核、32Gi内存。Pod数量不超过10个,PVC不超过2个。
我的经验:requests和limits要分开设。requests是“保证能拿到”,limits是“最多能用”。对于vLLM推理这种内存敏感型任务,我建议requests和limits设成一样,避免OOM。
检查配额是否生效:
kubectl describe resourcequota tenant-a-quota -n tenant-a
4.3 LimitRange:防止单个Pod“吃独食”
ResourceQuota管的是Namespace整体,但管不了单个Pod。比如租户A有10个Pod的配额,结果其中一个Pod申请了8核CPU,其他9个Pod就只能干瞪眼。
LimitRange就是用来解决这个问题的。它给Namespace里的每个Pod或容器设置默认的资源请求和限制。
我曾经遇到一个案例:有个租户的vLLM推理Pod没设resources字段,结果它把节点上所有可用内存都吃掉了。后来加了LimitRange,默认给每个容器设了2Gi内存上限,问题就解决了。
配置示例:
apiVersion: v1
kind: LimitRange
metadata:
name: tenant-a-limits
namespace: tenant-a
spec:
limits:
- max:
cpu: "2"
memory: "8Gi"
min:
cpu: "0.5"
memory: "1Gi"
default:
cpu: "1"
memory: "4Gi"
defaultRequest:
cpu: "0.5"
memory: "2Gi"
type: Container
这里的关键字段:
- max/min:单个容器能用的最大/最小资源
- default:如果Pod没设limits,就用这个值
- defaultRequest:如果Pod没设requests,就用这个值
注意:LimitRange只对创建后的Pod生效。已经运行的Pod不受影响。所以建议在创建Namespace时就配好LimitRange。
4.4 NetworkPolicy:真正的网络“防火墙”
前面说的Namespace和ResourceQuota,都管不了网络。默认情况下,K8s集群里所有Pod都可以互相通信——这显然不符合多租户的安全要求。
NetworkPolicy就是K8s里的网络防火墙。它基于iptables或eBPF实现,可以精确控制Pod之间的流量。
我记得第一次给客户做多租户方案时,客户问:“A租户的Pod能访问B租户的数据库吗?”我说默认可以,客户脸都绿了。后来我加了NetworkPolicy,才把这个问题解决。
来看一个典型的隔离策略:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
ingress: []
这个策略的意思是:拒绝所有进入tenant-a命名空间的流量。说白了,就是“关门打狗”——谁也别想进来。
但光拒绝不行,还得允许自己人访问。比如允许同Namespace内的Pod互相通信:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-a
如果你想让vLLM推理服务只接受来自特定前端服务的请求,可以这样:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-vllm
namespace: tenant-a
spec:
podSelector:
matchLabels:
app: vllm-inference
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8000
避坑指南:我曾经因为没配NetworkPolicy,导致一个租户的恶意Pod扫描了整个集群的Service端口。后来我强制要求每个Namespace至少配一条“拒绝所有入站”的默认策略。记住:白名单比黑名单安全得多。
4.5 知识体系总览
下面这张图总结了多租户隔离的三个层次:
4.6 实战建议:三步走策略
如果你现在要搭建多租户vLLM推理平台,我建议按这个顺序来:
- 先建Namespace:每个租户一个,命名规范如
tenant-{id} - 再配ResourceQuota和LimitRange:根据租户的SLA设定资源上限,防止“吵闹邻居”问题
- 最后加NetworkPolicy:默认拒绝所有入站,然后按需放行。特别是vLLM推理服务,只开放必要的端口给前端
总结一句话:Namespace管“你是谁”,ResourceQuota管“你能用多少”,NetworkPolicy管“你能访问谁”。三层都做好了,多租户才算真正落地。
好了,这一章的内容就到这里。记住,隔离不是目的,稳定和安全才是。下一章咱们聊聊监控和日志——毕竟隔离做得再好,出了问题也得能快速定位才行。