利用 namespace 分隔系统资源 (十八)
前言
Kubernetes 的名字空间并不是一个实体对象,只是一个逻辑上的概念。它可以把集群切分成一个个彼此独立的区域,然后我们把对象放到这些区域里,就实现了类似容器技术里 namespace 的隔离效果,应用只能在自己的名字空间里分配资源和运行,不会干扰到其他名字空间里的应用。
Kubernetes 的 Master/Node 架构已经能很好地管理集群,为什么还要引入名字空间这个东西呢?它的实际意义是什么呢?
我觉得,这恰恰是 Kubernetes面对大规模集群、海量节点时的一种现实考虑。因为集群很大、计算资源充足,会有非常多的用户在 Kubernetes 里创建各式各样的应用,可能会有百万数量级别的 Pod,这就使得资源争抢和命名冲突的概率大大增加了,情形和单机 Linux 系统里是非常相似的。
比如说,现在有一个 Kubernetes 集群,前端组、后端组、测试组都在使用它。这个时候就很容易命名冲突,比如后端组先创建了一个 Pod 叫Web,这个名字就被“占用”了,之后前端组和测试组就只能绞尽脑汁再新起一个不冲突的名字。接着资源争抢也容易出现,比如某一天,测试组不小心部署了有 Bug 的应用,在节点上把资源都给“吃”完了,就会导致其他组的同事根本无法工作。
所以,当多团队、多项目共用 Kubernetes 的时候,为了避免这些问题的出现,我们就需要把集群给适当地局部化,为每一类用户创建出只属于它自己的“工作空间”。
如果把 Kubernetes 比做一个大牧场的话,API 对象就是里面的鸡鸭牛羊,而名字空间就是圈养它们的围栏,有了各自合适的活动区域,就能更有效、更安全地利用 Kubernetes。
一、使用namespace
名字空间也是一种 API 对象,使用命令 kubectl api-resources 可以看到它的简称是ns,命令 kubectl create 不需要额外的参数,可以很容易地创建一个名字空间,比如:
kubectl create ns test-ns
kubectl get ns
Kubernetes 初始化集群的时候也会预设 4 个名字空间:default、kube-system、kube-public、kube-node-lease。我们常用的是前两个,default 是用户对象默认的名字空间,kube-system 是系统组件所在的名字空间。
想要把一个对象放入特定的名字空间,需要在它的 metadata 里添加一个 namespace 字段,比如我们要在test-ns里创建一个简单的 Nginx Pod,就要这样写:
apiVersion: v1
kind: Pod
metadata:
name: ngx
namespace: test-ns
spec:
containers:
- image: nginx:alpine
name: ngx
kubectl apply 创建这个对象之后,我们直接用 kubectl get 是看不到它的,因为默认查看的是default名字空间,想要操作其他名字空间的对象必须要用-n参数明确指定:
kubectl get pod -n test-ns
注意:
因为名字空间里的对象都从属于名字空间,所以在删除名字空间的时候一定要小心,一旦名字空间被删除,它里面的所有对象也都会消失。
你可以执行一下 kubectl delete,试着删除刚才创建的名字空间test-ns:
kubectl delete ns test-ns
就会发现删除名字空间后,它里面的 Pod 也会无影无踪了。
二、什么是资源配额
有了名字空间,我们就可以像管理容器一样,给名字空间设定配额,把整个集群的计算资源分割成不同的大小,按需分配给团队或项目使用。
不过集群和单机不一样,除了限制最基本的 CPU 和内存,还必须限制各种对象的数量,否则对象之间也会互相挤占资源。
名字空间的资源配额需要使用一个专门的 API 对象,叫做 ResourceQuota,简称是 quota,我们可以使用命令 kubectl create 创建一个它的样板文件:
export out="--dry-run=client -o yaml"
kubectl create quota dev-qt $out
因为资源配额对象必须依附在某个名字空间上,所以在它的 metadata 字段里必须明确写出 namespace(否则就会应用到 default 名字空间)。
apiVersion: v1
kind: Namespace
metadata:
name: dev-ns
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-qt
namespace: dev-ns
spec:
spec: {}
ResourceQuota 对象的使用方式比较灵活,既可以限制整个名字空间的配额,也可以只限制某些类型的对象(使用 scopeSelector),今天我们看第一种,它需要在 spec 里使用 hard 字段,意思就是硬性全局限制。
在 ResourceQuota 里可以设置各类资源配额,字段非常多,我简单地归了一下类,你可以后面再去官方文档上查找详细信息:
- CPU 和内存配额,使用 request.、limits.,这是和容器资源限制是一样的。
- 存储容量配额,使 requests.storage 限制的是 PVC 的存储总量,也可以用 persistentvolumeclaims 限制 PVC 的个数。
- 核心对象配额,使用对象的名字(英语复数形式),比如 pods、configmaps、secrets、services。
- 其他 API 对象配额,使用 count/name.group 的形式,比如 count/jobs.batch、count/deployments.apps。
下面的这个 YAML 就是一个比较完整的资源配额对象:
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-qt
namespace: dev-ns
spec:
hard:
requests.cpu: 10
requests.memory: 10Gi
limits.cpu: 10
limits.memory: 20Gi
requests.storage: 100Gi
persistentvolumeclaims: 100
pods: 100
configmaps: 100
secrets: 100
services: 10
count/jobs.batch: 1
count/cronjobs.batch: 1
count/deployments.apps: 1
我来稍微解释一下它为名字空间加上的全局资源配额:
- 所有 Pod 的需求总量最多是 10 个 CPU 和 10GB 的内存,上限总量是 10 个 CPU 和 20GB 的内存。
- 只能创建 100 个 PVC 对象,使用 100GB 的持久化存储空间。
- 只能创建 100 个 Pod,100 个 ConfigMap,100 个 Secret,10 个 Service。
- 只能创建 1 个 Job,1 个 CronJob,1 个 Deployment。
相关文章:
【k8s】利用namespace分隔系统资源(十八)
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)