开篇:你遇到过这些场景吗?
集群跑了半年,突然某个服务的 Pod 把整台节点的内存吃光了,别的服务全崩了。
开发说"我就测一下",结果在 default 命名空间里创建了 200 个 Pod,调度器直接卡死。
想删个废弃的命名空间,结果卡在 Terminating 状态三天三夜。
如果你干过 SRE,上面这些坑你大概率踩过至少一个。Namespace 看似简单------不就是个逻辑分组嘛------但用不好真能让你半夜爬起来处理故障。
读完这篇你能搞定这几件事:
- 搞清楚 Namespace 到底能隔离什么、不能隔离什么(这个更重要)
- 用 ResourceQuota 和 LimitRange 给每个团队上"紧箍咒"
- 命名空间卡在 Terminating 时怎么救回来
- 一套我踩坑出来的命名规范和最佳实践
一、Namespace 到底是干啥的?
官方定义:Namespace 提供一种机制,将同一集群中的资源划分为相互隔离的组。
说白了,就是在同一个集群里切出几个"虚拟子集群"。每个 Namespace 里的资源名称可以重复------比如你在 dev 里有个叫 nginx 的 Service,在 prod 里也可以有个叫 nginx 的 Service,互不冲突。
1.1 它管得了什么,管不了什么?
管得了(namespaced 资源) :Pod、Service、Deployment、ConfigMap、Secret、Ingress 这些。
管不了(cluster-scoped 资源) :Node、PersistentVolume、StorageClass、ClusterRole 这些。
小心,很多人以为 Namespace 能隔离网络------它不能。跨 Namespace 的 Pod 默认是能互相访问的。想做网络隔离?得上 NetworkPolicy。
1.2 四个默认 Namespace,你搞清楚了吗?
Kubernetes 集群一启动就自带四个 Namespace:
|-------------------|-------------------------------------|--------------|
| Namespace | 用途 | 要不要动它 |
| default | 默认放资源的地方 | 别往里面乱放东西 |
| kube-system | 系统组件(kube-apiserver、etcd、coredns 等) | 绝对别动 |
| kube-public | 集群公共资源,未认证也能读 | 一般用不上 |
| kube-node-lease | 节点心跳租约 | 别碰 |
生产环境不要用 default 命名空间部署业务。我见过太多人图省事全塞 default 里,最后跟别人抢资源抢到互相伤害。创建自己的 Namespace,这是最基本的规矩。
二、管理 Namespace 的日常操作
2.1 创建
命令行一把梭:
kubectl create namespace production
或者用 YAML 声明式(我推荐这个,能进 Git):
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: prod
team: platform
kubectl apply -f namespace.yaml
命名规范建议 :别瞎起名。我一般用 {环境}-{团队}-{应用} 的格式,比如 prod-platform-api、staging-data-etl。这样一眼能看出是干啥的。
避坑:别用 kube-前缀创建 Namespace,这是给系统组件预留的。
2.2 查看与切换
# 列出所有
kubectl get namespaces
# 查看某个的详情
kubectl describe namespace production
# 临时指定命名空间
kubectl get pods -n production
# 永久切换默认命名空间(强烈推荐,省得每次都敲 -n)
kubectl config set-context --current --namespace=production
切完之后验证一下:
kubectl config view --minify | grep namespace
我一般每个团队成员的 kubeconfig 都提前配好默认 Namespace,省得他们忘加 -n 把资源怼到 default 里。
2.3 删除
kubectl delete namespace production
删除 Namespace 的时候,Kubernetes 会先删掉里面所有资源,再删 Namespace 本身。这个过程不可逆,删之前想清楚。
三、资源配额:这才是 Namespace 的核心价值
Namespace 光用来分组没啥意思,真正的威力在于配合 ResourceQuota 和 LimitRange 做资源管控。
3.1 ResourceQuota:限制"总量"
ResourceQuota 控制的是整个 Namespace 里所有 Pod 加起来能用多少资源。
来个例子,限制 CPU 和内存的总量:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-demo
namespace: production
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
这表示:
- 所有 Pod 的 CPU 请求总和 ≤ 4 核
- 所有 Pod 的内存请求总和 ≤ 8 GiB
- 所有 Pod 的 CPU 限制总和 ≤ 8 核
- 所有 Pod 的内存限制总和 ≤ 16 GiB
- Pod 总数 ≤ 20 个
应用之后看看效果:
kubectl get resourcequota quota-demo -n production -o yaml
输出里会显示用了多少、还剩多少。
这里有个巨坑,我必须提醒你 :一旦你在 Namespace 里启用了 ResourceQuota(比如限制了 cpu 或 memory),所有新创建的 Pod 必须显式声明 requests 和 limits ,否则 API Server 会直接拒绝创建,报类似 failed quota 或 must specify limits 的错误。很多开发配完 ResourceQuota 之后跑 deployment 发现 Pod 起不来,一脸懵------原因就是这个。所以提前跟团队打好招呼,所有部署模板把 resources 字段写齐。
(顺便提一嘴,ResourceQuota 还能限制其他资源数量,比如 Service、ConfigMap、PVC 的数量,你在 spec.hard 里加 services: "10"、configmaps: "5" 就行。)
3.2 LimitRange:给每个 Pod 设"规矩"
ResourceQuota 管总量,LimitRange 管单个 Pod 的上下限。
来个例子:
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-mem-limit-range
namespace: production
spec:
limits:
- max:
cpu: "2"
memory: 4Gi
min:
cpu: "100m"
memory: 256Mi
default:
cpu: "500m"
memory: 1Gi
defaultRequest:
cpu: "200m"
memory: 512Mi
type: Container
这表示:
- 每个容器的 CPU 必须在 100m ~ 2 核之间
- 每个容器的内存必须在 256Mi ~ 4Gi 之间
- 如果容器没声明 CPU 请求/限制,自动补
200m请求和500m限制 - 如果容器没声明内存请求/限制,自动补
512Mi请求和1Gi限制
小心,LimitRange 的校验只在 Pod 创建时生效。你后来改 LimitRange,已经跑着的 Pod 不会变。
3.3 ResourceQuota + LimitRange 配合使用
我个人的推荐打法:两个一起上。
- LimitRange 保底------防止有人忘写 resources 导致调度器瞎调度,也防止单 Pod 吃太多
- ResourceQuota 封顶------防止整个团队把集群资源吃干抹净
这俩配合好了,基本能杜绝"某个 Namespace 把集群搞崩"的情况。
四、生产环境 Namespace 最佳实践(我踩坑总结的)
4.1 按环境隔离
开发、测试、预发布、生产,各用各的 Namespace。别在一个 Namespace 里又跑测试又跑生产------你早晚会不小心把生产当测试删了。
4.2 给每个团队分配独立的 Namespace + 独立配额
如果集群有多个团队在用,每个团队至少一个 Namespace。配合 RBAC 限制每个团队只能操作自己的 Namespace。这样 A 团队搞炸了也只炸自己的,不影响别人。
具体怎么分配额:别所有团队共用一个大池子,而是给每个团队的 Namespace 单独建 ResourceQuota。比如数据团队搞 ETL 可能吃内存多,给 32Gi;平台团队跑网关,给 8Gi 就够了。量体裁衣,而不是一视同仁。
# 给数据团队的配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-data-team
namespace: prod-data-etl
spec:
hard:
requests.memory: 16Gi
limits.memory: 32Gi
---
# 给平台团队的配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-platform-team
namespace: prod-platform-gateway
spec:
hard:
requests.memory: 4Gi
limits.memory: 8Gi
这样哪个团队资源不够了,只扩它自己的就行,不用动别人。
4.3 必须配置 ResourceQuota
没有资源配额的 Namespace 就是个"无底洞"。我见过一个开发在测试环境起了 100 个 Pod 把节点内存打爆的------就是因为没设配额。
4.4 命名规范统一
定一套规则并强制执行。我现在的标准是:
{环境}-{团队名}-{应用名}
比如 prod-platform-gateway、staging-data-etl。别搞什么 test1、tmp、aaa 这种,半年后没人看得懂。
4.5 避免使用 default Namespace
这条再说一遍:生产环境别用 default。default 是给刚搭好集群时测试用的,不是让你跑正经业务的。
五、常见故障:Namespace 删不掉怎么办?
这是 SRE 绕不开的一个坑。kubectl delete ns xxx 之后,Namespace 卡在 Terminating 状态,几天都删不掉。
5.1 为什么会卡住?
Kubernetes 删除 Namespace 时,会先清理里面的所有资源。如果某个环节卡住了,删除流程就停在那了。
常见原因有这几个(不全,但 80% 的情况是其中之一):
- APIService 不可用:比如你装了 Istio 又卸了,但 CRD 残留,kube-apiserver 访问不到对应的 API 服务,就一直卡着。这个是我遇到最多的。
- CRD 实例有 finalizer 但控制器已死:某些自定义资源有 finalizer,需要对应的 controller 去处理。如果 controller 挂了,finalizer 没人清,Namespace 就卡着。
- 资源没删干净:某些资源卡在删除中(比如 PVC 挂载没解除),导致 Namespace 的 finalizer 一直等。
5.2 怎么排查?
第一步,看 Namespace 的状态:
kubectl describe ns <卡住的命名空间>
如果看到 Status: Terminating,接着往下查。
第二步,看看有哪些 API 服务挂了:
kubectl get apiservice | grep False
如果发现某个 APIService 是 False,它就是最常见的嫌疑人。
第三步,如果是 APIService 的问题,要么修好它(比如重启对应的控制器),要么直接删掉它:
kubectl delete apiservice <有问题的版本.api-group>
删掉之后,Namespace 通常会自动完成删除。
如果查了 APIService 没问题,再看看 Namespace 里还有哪些资源卡着:
# 先看这个命名空间里还剩啥
kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n <卡住的命名空间>
慢慢排查哪个资源删不掉,针对性处理。
5.3 最后的"核武器":强行移除 finalizers
如果上面的方法都不行,用这招------但这是最后手段,用了可能有残留资源变孤儿。
# 导出 namespace 的 json
kubectl get ns <卡住的命名空间> -o json > ns.json
# 编辑 json,把 metadata.finalizers 字段改成 []
# 然后用 curl 直接调 API 更新
curl -k -H "Content-Type: application/json" -X PUT \
--data-binary @ns.json \
https://<apiserver>/api/v1/namespaces/<卡住的命名空间>/finalize
或者用 kubectl patch 一把梭(注意 finalizers 在 metadata 下,不是 spec):
kubectl patch namespace <卡住的命名空间> -p '{"metadata":{"finalizers":[]}}' --type=merge
警告:这招是让 Kubernetes 跳过资源清理直接删 Namespace。里面的 Pod、PVC 等资源可能变成"孤儿"残留在集群里,你之后得手动清理。我一般实在没辙了才用这招。
六、总结一下
- Namespace 是逻辑隔离,不是安全隔离------跨 Namespace 的网络默认是通的,要做隔离得上 NetworkPolicy
- ResourceQuota + LimitRange 必须配------这是防止"一个租户搞垮全集群"的核心手段,注意配了 ResourceQuota 之后 Pod 必须显式声明 resources
- 别用 default 跑生产------给自己和队友省点心
- 命名规范统一------环境-团队-应用,一目了然
- Namespace 卡 Terminating 别慌------先查 APIService,再排查 CRD 和控制器,最后才考虑删 finalizers,而且 patch 的时候别把字段写错了(我专门强调这个,是因为自己在这栽过跟头)
你还有什么更好的 Namespace 管理经验?或者踩过什么奇葩的坑?评论区见。