kubernetes原生支持多租户,但命名空间仅为逻辑隔离起点,必须配合resourcequota、networkpolicy、rbac等显式配置才能实现真正安全隔离;缺一不可,否则租户间仍可互相访问或争抢资源。

直接说结论:Kubernetes原生支持多租户,但“开箱即用”不等于“开箱即安全”——命名空间只是隔离起点,不配ResourceQuota、不设NetworkPolicy、不绑RoleBinding,租户之间照样能互相踩脚。
命名空间不是租户,只是隔离容器
很多人误以为创建一个Namespace就完成了租户划分,其实它只提供资源作用域边界,不带任何强制约束。Pod可以跨命名空间通信,CPU内存不限制,RBAC默认全放行。
- 必须显式创建
Namespace并打上tenant: xxx这类标签,后续策略才好按标筛选 -
Namespace本身不消耗资源,但它是所有配额、网络策略、权限绑定的锚点,漏建等于没隔离 - 避免用
default或kube-system等系统命名空间承载租户工作负载,它们默认无配额且权限宽松
Go服务部署时如何绑定租户上下文
Go业务代码本身不感知Kubernetes租户,但可以通过环境变量、配置注入、HTTP Header等方式把租户标识带进应用逻辑,尤其在共享数据库场景下,这是数据隔离的最后一道防线。
评估 Kubernetes 集群安全态势,覆盖 RBAC、工作负载安全、网络策略、基础设施即代码(IaC)、运行时监控和密钥管理等 30 项控制项……
- 在Deployment中通过
env注入租户ID:valueFrom: {fieldRef: {fieldPath: metadata.namespace}},让Go程序启动时就知道自己跑在哪个租户空间 - 若使用gRPC或HTTP网关,建议从
X-Tenant-IDHeader提取租户标识,比依赖Pod元数据更可控、可测试 - 不要在Go里硬编码
tenant_id字段名,用配置项统一管理,比如TENANT_ID_HEADER_KEY和TENANT_ID_ENV_VAR分开控制 - 数据库中间件(如sqlx + 拦截器)需检查是否已自动追加
WHERE tenant_id = ?,否则共享表模式下极易数据越界
ResourceQuota和LimitRange必须成对出现
只设ResourceQuota会卡死Pod调度(因为没声明默认request/limit),只设LimitRange又无法限制对象总数——两者缺一不可。
-
ResourceQuota管“总量上限”:比如pods: "20"、services: "10"、requests.cpu: "4" -
LimitRange管“单个容器底线”:定义默认requests和limits,避免开发者漏写导致调度失败 - Go服务镜像通常内存波动大,建议
requests.memory设为实际观测P95值,limits.memory留20%余量,防止OOMKilled频繁重启 - 注意
ResourceQuota不继承,每个新命名空间都得单独部署,CI流程里漏掉这步,新租户上线就失控
NetworkPolicy是租户间网络隔离的实际执行者
默认Kubernetes网络模型允许所有Pod互通,NetworkPolicy才是让“命名空间隔离”真正生效的关键配置。
- 必须明确指定
podSelector: {}(匹配本命名空间所有Pod),再用namespaceSelector限定只允许同租户通信 - Go服务若依赖外部中间件(如Redis、MySQL),需在
egress规则中显式放行目标Service的namespace和labels,不能只靠DNS名称 - 避免用
ipBlock做白名单——宿主集群节点IP可能动态变化,且vcluster等虚拟集群场景下完全失效 - 启用
NetworkPolicy前确认CNI插件支持(Calico、Cilium可,Flannel默认不支持)
真正麻烦的不是写几份YAML,而是让每份YAML在租户创建、扩缩容、故障恢复时都自动同步到位——手动运维迟早出错,建议把Namespace+ResourceQuota+LimitRange+NetworkPolicy+RoleBinding打包成Kustomize base或Helm chart,用GitOps驱动落地。










