2.18 集群管理

2.18 集群管理 #

2.18.1 名字空间 #

Kubernetes 的名字空间并不是一个实体对象,只是一个逻辑上的概念。它可以把集群切分成一个个彼此独立的区域,然后把对象放到这些区域里,就实现了类似容器技术里 namespace 的隔离效果,应用只能在自己的名字空间里分配资源和运行,不会干扰到其他名字空间里的应用。

在 Master/Node 架构里引入名字空间,是因为集群很大、计算资源充足,会有非常多的用户在 Kubernetes 里创建各式各样的应用,可能会有百万数量级别的 Pod,这就使得资源争抢和命名冲突的概率大大增加了,情形和单机 Linux 系统里是非常相似的。

比如,现在有一个 Kubernetes 集群,前端组、后端组、测试组都在使用它。这个时候就很容易命名冲突,比如后端组先创建了一个 Pod 叫 Web,这个名字就被 “占用” 了,之后前端组和测试组就只能绞尽脑汁再新起一个不冲突的名字。资源争抢也容易出现,比如,测试组不小心部署了有 Bug 的应用,在节点上把资源都给 “吃” 完了,就会导致其他组的同事根本无法工作。

当多团队、多项目共用 Kubernetes 的时候,就需要把集群给适当地 “局部化”,为每一类用户创建出只属于它自己的 “工作空间”。

2.18.2 使用名字空间 #

名字空间也是一种 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

apply 创建对象之后,使用 kubectl get 是看不到它的,因为默认查看的是 “default” 名字空间,想要操作其他名字空间的对象必须要用 -n 参数明确指定:

名字空间里的对象都从属于名字空间,所以在删除名字空间的时候一定要小心,一旦名字空间被删除,它里面的所有对象也都会消失。可以执行一下 kubectl delete,尝试删除刚才创建的名字空间 “test-ns”:

会发现删除名字空间后,它里面的 Pod 也删除了。

2.18.3 资源配额 #

有了名字空间后,可以像管理容器一样,给名字空间设定配额,把整个集群的计算资源分割成不同的大小,按需分配给团队或项目使用。不过集群和单机不一样,除了限制最基本的 CPU 和内存,还必须限制各种对象的数量,否则对象之间也会互相挤占资源。

名字空间的资源配额需要使用一个专门的 API 对象 ResourceQuota,简称是 quota,可以使用命令 kubectl create 创建一个它的样板文件:

export out="--dry-run=client -o yaml"
kubectl create quota dev-qt $out

因为资源配额对象必须依附在某个名字空间上,所以在它的 metadata 字段里必须明确写出 namespace,否则就会应用到 default 名字空间。

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。

2.18.4 使用资源配额 #

以下的 YAML 描述是创建一个名字空间 “dev-ns”,再创建一个资源配额对象 “dev-qt”:

apiVersion: v1
kind: Namespace
metadata:
  name: dev-ns

---

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。

apply 创建资源配额对象后,用 kubectl get 加上 -n 指定名字空间查看:

kubectl apply -f quota-ns.yml
kubectl get quota -n dev-ns

可以用命令 kubectl describe 查看对象,会有一个清晰的表格:

kubectl describe quota -n dev-ns

可以尝试在这个名字空间里运行两个 busybox Job,要加上 -n 参数:

kubectl create job echo1 -n dev-ns --image=busybox -- echo hello
kubectl create job echo2 -n dev-ns --image=busybox -- echo hello

ResourceQuota 限制了名字空间里最多只能有一个 Job,所以在创建第二个 Job 对象时会失败,提示超出了资源配额。

使用命令 kubectl describe 查看,会发现 Job 资源已经到达了上限:

2.18.5 默认资源配额 #

在名字空间加上了资源配额限制之后,会有一个合理但比较烦人的约束:要求所有在里面运行的 Pod 都必须用字段 resources 声明资源需求,否则就无法创建。

比如,想用命令 kubectl run 创建一个 Pod:

kubectl run ngx --image=nginx:alpine -n dev-ns

给出了一个 Forbidden 的错误提示,说不满足配额要求。

如果 Pod 里没有 resources 字段,就可以无限制地使用 CPU 和内存,这显然与名字空间的资源配额相冲突。为了保证名字空间的资源总量可管可控,Kubernetes 就只能拒绝创建这样的 Pod。

如果想让 Kubernetes 自动为 Pod 加上资源限制,给个默认值。这里就需要用到一个很小但很有用的辅助对象 —— LimitRange,简称是 limits,它可以为 API 对象添加默认的资源配额限制

可以用命令 kubectl explain limits 来查看它的 YAML 字段详细说明:

  • spec.limits 是它的核心属性,描述了默认的资源限制。

  • type 是要限制的对象类型,可以是 Container、Pod、PersistentVolumeClaim。

  • default 是默认的资源上限,对应容器里的 resources.limits,只适用于 Container。

  • defaultRequest 默认申请的资源,对应容器里的 resources.requests,同样也只适用于 Container。

  • max、min 是对象能使用的资源的最大最小值。

以下是一个 LimitRange YAML 描述:

apiVersion: v1
kind: LimitRange
metadata:
  name: dev-limits
  namespace: dev-ns

spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 200m
        memory: 50Mi
      default:
        cpu: 500m
        memory: 100Mi
    - type: Pod
      max:
        cpu: 800m
        memory: 200Mi

设置了每个容器默认申请 0.2 的 CPU 和 50MB 内存,容器的资源上限是 0.5 的 CPU 和 100MB 内存,每个 Pod 的最大使用量是 0.8 的 CPU 和 200MB 内存。

使用 kubectl apply 创建 LimitRange 之后,再用 kubectl describe 可以看到它的状态:

有了这个默认的资源配额作为 “保底”,就可以不用编写 resources 字段直接创建 Pod:

使用 kubectl describe pod -n dev-ns 查看状态可知,LimitRange 为它自动加上的资源配额:

不是所有的 API 对象都可以划分进名字空间管理,比如 Node、PV 等这样的全局资源就不属于任何名字空间。