1. 为什么单集群多租户绕不开 Namespaces刚接触容器编排那会儿我总觉得 Namespace 就是个给资源起名字的“文件夹”跟电脑桌面上建个新目录差不多无非是看着整齐一点。直到有一次在测试环境里两个团队同时往同一个集群部署服务结果一方把另一方同名的 Service 给覆盖了排查了大半天才发现是命名冲突。那次之后我才真正意识到Namespace 远不止是“分类标签”它是整个集群里做逻辑隔离、权限切分和资源配额的基础单元。简单说Namespace 解决的是“一个集群怎么给多拨人用”的问题。你可以把它理解成一栋写字楼里的不同楼层大家共用同一套水电总闸、同一部电梯但每个楼层有自己的门禁、自己的工位编号、自己的用电额度。K8s 里的 Namespace 就是这层“楼层”的概念它把集群里的资源Pod、Service、ConfigMap、PVC 等按逻辑划分到不同空间里让名字可以重复、权限可以隔离、资源可以限额。这篇文章适合谁看如果你正在维护一个多人协作的集群或者准备把开发、测试、预发环境塞进同一个集群又或者你只是对kubectl get pods -n xxx里的那个-n参数一直似懂非懂那这篇内容应该能帮你把 Namespace 从“会用”推进到“用明白”。我会从设计思路讲到实操细节再把我自己踩过的坑和排查经验一并摊开尽量让你看完就能直接上手。2. Namespace 的整体设计与隔离逻辑拆解2.1 它到底隔离了什么又没隔离什么很多人对 Namespace 有个误解以为加了 Namespace 就等于“完全隔离”。实际上它隔离的是命名作用域和部分资源的可见范围而不是物理层面的隔离。我习惯用一个类比来解释Namespace 像是给每个团队发了一本独立的通讯录你们可以各自有“张三”“李四”互不冲突但大家用的还是同一部电话交换机交换机本身是共享的。具体来说Namespace 能做到这些名称隔离不同 Namespace 里可以存在同名的 Deployment、Service、Pod互不干扰。权限隔离配合 RBAC可以让某个用户只能操作指定 Namespace 下的资源。资源配额隔离通过 ResourceQuota 限制某个 Namespace 能用的 CPU、内存、Pod 数量上限。默认资源限制通过 LimitRange 给 Namespace 内的容器设定默认的 requests/limits。但它做不到的也很关键网络隔离默认情况下跨 Namespace 的 Pod 是可以直接互相访问的Namespace 本身不提供网络隔离这需要 NetworkPolicy 来补。节点隔离Pod 调度到哪个节点跟 Namespace 没关系除非你用 nodeSelector、亲和性等手段。存储隔离PV 是集群级别的资源不属于任何 Namespace只有 PVC 才属于 Namespace。提示如果你以为建了 Namespace 就安全了那大概率会在某次跨命名空间访问测试里被现实教育。网络层面的隔离一定要单独用 NetworkPolicy 处理。2.2 哪些资源属于 Namespace哪些不属于这是实操中最容易搞混的地方。我整理了一张表把常见资源的归属列清楚省得你每次都要去翻文档。资源类型是否属于 Namespace说明Pod是最典型的命名空间级资源Service是服务发现的作用域在命名空间内Deployment / StatefulSet / DaemonSet是工作负载控制器ConfigMap / Secret是配置与密钥PVC是存储声明但绑定的 PV 是集群级ServiceAccount是权限身份ResourceQuota / LimitRange是配额与默认限制Namespace 本身否它是集群级资源Node否集群级PV否集群级ClusterRole / ClusterRoleBinding否集群级权限StorageClass否集群级CustomResourceDefinition否集群级这张表建议你记牢尤其是 PV 和 PVC 的区别。我见过有人删 Namespace 的时候以为 PV 也会跟着删结果数据卷还挂在那儿白白占着存储。2.3 为什么用 Namespace 而不是直接开多个集群这是架构选型时绕不过去的问题。多开集群当然隔离更彻底但代价也明显每个集群都要独立的控制平面、独立的监控、独立的入口运维成本成倍上升。而 Namespace 是在“隔离性”和“运维成本”之间取的一个平衡点。我的经验是按这个思路判断如果团队之间需要强安全隔离比如涉及不同信任级别那还是分集群更稳妥。如果只是逻辑分组、权限切分、资源限额Namespace 完全够用而且管理起来轻量得多。如果是环境隔离dev/test/prodNamespace 是主流做法但要注意生产环境的配额和权限要单独收紧。用 Namespace 的核心收益就是一套控制平面服务多拨人成本低、切换快。代价就是隔离是“软”的需要你额外用 RBAC、NetworkPolicy、ResourceQuota 去补齐。3. 核心细节解析与实操要点3.1 创建与规划 Namespace 的命名规范创建 Namespace 本身很简单一行命令的事kubectl create namespace team-alpha但真正考验功力的是怎么规划命名。我踩过的坑是早期随便起名后来团队多了、环境多了名字就乱成一锅粥。后来我固定了一套规范推荐你也参考环境前缀dev-、test-、staging-、prod-团队或业务线team-alpha、payment、search组合形式dev-team-alpha、prod-payment这样一眼就能看出这个 Namespace 属于哪个环境、哪个团队。另外Namespace 名字必须符合 DNS 标签规范小写字母、数字、连字符长度不超过 63 个字符。别用下划线和大写否则创建会直接报错。注意Namespace 名字一旦确定后期改名非常麻烦因为所有资源引用都要跟着改。所以规划阶段多花十分钟能省后面几小时的返工。3.2 ResourceQuota给每个 Namespace 上“紧箍咒”没有配额的 Namespace 就像没有预算的部门迟早会把集群资源吃光。ResourceQuota 是我认为 Namespace 里最该优先配置的东西。一个典型的配额长这样apiVersion: v1 kind: ResourceQuota metadata: name: team-alpha-quota namespace: team-alpha spec: hard: requests.cpu: 10 requests.memory: 20Gi limits.cpu: 20 limits.memory: 40Gi pods: 50 services: 20 persistentvolumeclaims: 10这里有几个参数选择的逻辑要讲清楚。requests.cpu设成 10意思是这个 Namespace 里所有 Pod 的 CPU 请求总和不能超过 10 核。为什么 requests 和 limits 要分开设因为 requests 影响调度节点得有这么多资源才放得下limits 影响运行时上限超过会被限流或杀掉。一般 limits 设成 requests 的 2 倍左右比较合理给突发流量留点空间又不至于太离谱。pods: 50这个限制也很重要。我遇到过某个团队写了个死循环不断创建 Pod如果没有 Pod 数量上限整个集群的 IP 资源都会被耗尽。加上这个限制后最多 50 个撑死了也就影响自己。3.3 LimitRange兜底的默认值ResourceQuota 管的是“总量”LimitRange 管的是“单个”。如果只配了 Quota 没配 LimitRange会出现一个尴尬情况用户创建 Pod 时没写 requests/limitsQuota 直接拒绝创建报错说“必须指定资源请求”。这时候 LimitRange 就派上用场了apiVersion: v1 kind: LimitRange metadata: name: team-alpha-limits namespace: team-alpha spec: limits: - type: Container default: cpu: 500m memory: 512Mi defaultRequest: cpu: 200m memory: 256Mi max: cpu: 4 memory: 8Gi min: cpu: 50m memory: 64Midefault是 limits 的默认值defaultRequest是 requests 的默认值。这样用户不写也能创建系统自动补上。max和min则防止有人写个 100 核的离谱请求。这套组合拳打下来Namespace 的资源使用就基本可控了。3.4 RBAC 与 Namespace 的绑定关系Namespace 的权限隔离靠的是 Role 和 RoleBinding注意不是 ClusterRole。Role 是命名空间级的只在该 Namespace 内生效。比如给 team-alpha 的开发者只读权限apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: team-alpha name: pod-reader rules: - apiGroups: [] resources: [pods, pods/log] verbs: [get, list, watch] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: team-alpha subjects: - kind: User name: dev-user apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io这里的关键点是RoleBinding 把 Role 绑定到用户作用域就锁死在 team-alpha 这个 Namespace 里。这个用户去kubectl get pods -n team-beta会直接被拒绝。这就是 Namespace 权限隔离的实际效果。提示如果你想让某个用户在所有 Namespace 都有权限那要用 ClusterRole ClusterRoleBinding但那样就失去了 Namespace 隔离的意义。生产环境里尽量用 RoleBinding 把权限限制在需要的 Namespace 内。4. 实操过程与核心环节实现4.1 从零搭建一个多租户 Namespace 环境假设现在要给两个团队team-alpha 和 team-beta在同一集群里划分空间我按实际操作顺序走一遍。第一步创建 Namespacekubectl create namespace team-alpha kubectl create namespace team-beta第二步给每个 Namespace 打标签方便后续用标签选择器批量管理kubectl label namespace team-alpha teamalpha envdev kubectl label namespace team-beta teambeta envdev标签这东西平时不起眼但当你需要批量查询或做策略匹配时特别有用。比如kubectl get namespaces -l envdev就能一次列出所有开发环境。第三步应用 ResourceQuota 和 LimitRange。把前面写的 YAML 分别 apply 到两个 Namespacekubectl apply -f team-alpha-quota.yaml kubectl apply -f team-alpha-limits.yaml kubectl apply -f team-beta-quota.yaml kubectl apply -f team-beta-limits.yaml第四步配置 RBAC。给每个团队的用户绑定对应的 Role。这一步做完两个团队就各自在自己的 Namespace 里干活互不干扰。第五步验证隔离效果。用 team-alpha 的用户去操作 team-beta 的资源应该被拒绝kubectl get pods -n team-beta --asdev-user-alpha如果返回Forbidden说明权限隔离生效了。4.2 跨 Namespace 服务访问的配置方法Namespace 之间默认网络是通的但服务发现需要写全限定域名FQDN。格式是service-name.namespace.svc.cluster.local比如 team-alpha 里有个叫api的 Serviceteam-beta 想访问它就得用api.team-alpha.svc.cluster.local我实测下来很多人卡在这里是因为只写了api结果 DNS 解析不到因为默认只在当前 Namespace 内查找。写全 FQDN 就稳了。如果你希望禁止跨 Namespace 访问那就得靠 NetworkPolicy。一个简单的默认拒绝策略apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-from-other-namespaces namespace: team-alpha spec: podSelector: {} policyTypes: - Ingress ingress: - from: - podSelector: {}这个策略的意思是只允许同一 Namespace 内的 Pod 访问其他 Namespace 的一律拒绝。注意podSelector: {}表示选中本 Namespace 所有 Podfrom里的podSelector: {}表示只放行同 Namespace 的来源。4.3 删除 Namespace 的正确姿势与风险删除 Namespace 是个危险操作因为它会级联删除里面所有资源。命令很简单kubectl delete namespace team-alpha但风险在于如果里面有正在运行的生产服务一删全没。而且删除是异步的Namespace 会进入Terminating状态如果里面有资源卡住比如 finalizer 没处理完它会一直卡在那儿。我踩过的坑是某个 Namespace 里有个 PVC 绑定的 PV 有 finalizer删 Namespace 时卡了半小时。后来排查发现是存储插件的问题。所以删除前一定要确认里面没有正在使用的 PVC 和 PV没有未完成的 Job没有带 finalizer 的自定义资源注意生产环境删除 Namespace 前先kubectl get all -n xxx看一眼里面有什么确认无误再动手。别问我怎么知道要提醒这一点的。5. 常见问题与排查技巧实录5.1 Namespace 卡在 Terminating 怎么办这是高频问题。Namespace 删除时卡住通常是因为里面有资源无法正常删除。排查思路先看 Namespace 状态kubectl get namespace team-alpha -o json找到status.conditions里的原因。查看里面还有哪些资源kubectl api-resources --verbslist --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n team-alpha。如果发现有资源带 finalizer手动移除 finalizer 再删。实在不行可以用 API 强制清空 spec.finalizers但这个操作要非常谨慎可能导致资源泄漏。我一般只在测试环境用这招。5.2 配额明明没满却创建失败这种情况我遇到过几次原因通常是ResourceQuota 统计的是requests 和 limits 的总和而不是实际使用量。也就是说即使你的 Pod 实际只用了 100m CPU但如果你声明了 2 核 requests配额就按 2 核扣。所以创建失败时先看kubectl describe resourcequota -n team-alpha对比Used和Hard两列往往能立刻找到原因。另一个常见原因是 LimitRange 的max设得太小用户请求超过了上限。这时候报错信息会明确说超过 max照着调就行。5.3 跨 Namespace 访问 DNS 解析失败前面提过核心是 FQDN 要写全。但还有一种情况CoreDNS 配置里如果限制了搜索域短名称可能解析不到。排查步骤先nslookup api.team-alpha.svc.cluster.local看能不能解析。如果全 FQDN 能解析短名称不行那就是搜索域的问题改用 FQDN 即可。如果全 FQDN 也不行检查 CoreDNS Pod 是否正常以及 NetworkPolicy 是否把 DNS 流量也拦了。最后这点特别隐蔽有人配了默认拒绝的 NetworkPolicy结果把到 CoreDNS 的 53 端口流量也拒了导致所有 DNS 解析失败。所以 NetworkPolicy 里一定要放行 DNS。5.4 常见问题速查表问题现象可能原因排查方向Namespace 卡 Terminating资源有 finalizer查看残留资源移除 finalizer创建 Pod 报配额不足requests/limits 总和超限describe resourcequota 对比 Used/Hard跨 Namespace 访问失败未用 FQDN改用 service.ns.svc.cluster.localDNS 全部解析失败NetworkPolicy 拦了 DNS放行 53 端口权限被拒RoleBinding 未绑定检查 RoleBinding 的 namespace 和 subject删除 Namespace 后 PV 还在PV 是集群级资源手动清理 PV6. 我个人的几条实操心得Namespace 这东西用起来简单用好了不容易。我最大的体会是规划先行配额兜底权限收紧。别等到出事了才想起来加限制那时候往往已经晚了。另外一个小技巧给每个 Namespace 打上统一的标签比如owner、env、cost-center后期做成本分摊和批量策略时特别省事。我现在管理的集群里所有 Namespace 都有这几个标签查起来一目了然。还有定期审计 Namespace 的使用情况。有些 Namespace 建了之后就没人用了白白占着配额。我一般每季度清理一次把长期无活动的 Namespace 归档或删除。这个习惯帮我省了不少集群资源。最后再分享一个排查思路遇到 Namespace 相关问题先kubectl describe namespace xxx再看kubectl get events -n xxx八成的问题都能从事件里找到线索。这比盲目翻文档快得多。