管理内存、CPU和API资源

65 阅读16分钟

为命名空间配置默认的内存请求和限制

在Kubernetes集群中,可以划分多个命名空间,如果在具有默认内存限制的命名空间内尝试创建一个Pod,并且这个Pod中的容器没有声明自己的内存资源限制,那么控制面会为该容器设置默认的内存限制。

首先创建一个名叫test命名空间:

kubectl create ns test

接着创建LimitRange,在LimitRange的清单中声明默认的内存请求和默认的内存限制:

# memory-defaults.yaml

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default:
      memory: 512Mi
    defaultRequest:
      memory: 256Mi
    type: Container

test命名空间创建限制LimitRange

kubectl apply -f memory-defaults.yaml -n test

1、容器没有声明内存请求和限制

现在如果在 default-mem-example 命名空间中创建一个 Pod, 并且该 Pod 中所有容器都没有声明自己的内存请求和内存限制, 控制面会将内存的默认请求值 256MiB 和默认限制值 512MiB 应用到 Pod 上。

下面创建一个Pod,这个Pod中的容器没有声明内存请求和限制:

# memroy-defaults-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: default-mem-demo
  namespace: test
spec:
  containers:
  - name: default-mem-demo-ctr
    image: nginx:1.17.1

创建上面Pod的资源清单,查看Pod详情:

kubectl get pod default-mem-demo -oyaml -n test

输出内容中限制该Pod的容器有256MiB的内存请求和512MiB的内存限制。这些都是LimitRange设置的默认值。

spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: default-mem-demo-ctr
    resources:
      limits:
        memory: 512Mi
      requests:
        memory: 256Mi

最后做一下清理工作,删除刚创建的Pod:

kubectl default -f memory-defaults-pod.yaml

2、容器声明了限制,但是没有声明请求

以下只包含一个容器的Pod清单中,容器声明了内存限制,但是没有声明内存请求。

# memory-defaults-pod.yaml 

apiVersion: v1
kind: Pod
metadata:
  name: default-mem-demo
  namespace: test
spec:
  containers:
  - name: default-mem-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "1Gi"

Pod创建完成后,进行查看详情:

kubectl get pod default-mem-demo -n test -oyaml

输出结果显示容器的内存请求被设置为它的内存限制相同的值。注意该容器没有被指定默认的内存请求值256MiB。

spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: default-mem-demo-ctr
    resources:
      limits:
        memory: 1Gi
      requests:
        memory: 1Gi

最后,清理刚才创建的Pod:

kubectl delete -f memory-defaults-pod.yaml

3、容器声明了内存请求,但是没有声明内存限制

以下只包含一个容器的Pod清单中,容器声明了内存请求,但是没有声明内存限制。

apiVersion: v1
kind: Pod
metadata:
  name: default-mem-demo
  namespace: test
spec:
  containers:
  - name: default-mem-demo-ctr
    image: nginx:1.17.1
    resources:
      requests:
        memory: "128Mi"

创建Pod后查看Pod详情:

kubectl get pod default-mem-demo -n test -oyaml

输出结果显示所创建的Pod中,容器的内存请求为Pod清单中声明的值,然而同一容器的内存限制被设置为512MiB,此值是test命名空间的么哦人内存限制值。

spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: default-mem-demo-ctr
    resources:
      limits:
        memory: 512Mi
      requests:
        memory: 128Mi

现在我们知道命名空间的最大内存限制值是512Mi,那么我们在声明容器的内存请求值大于512Mi会怎么样呢?

The Pod "default-mem-demo" is invalid: spec.containers[0].resources.requests: Invalid value: "1Gi": must be less than or equal to memory limit

最后,清理刚才创建的Pod:

kubectl delete -f memory-defaults-pod.yaml

4、设置默认内存限制和请求的动机

如果命名空间设置了内存资源配额,那么为内存限制设置一个默认值会很有帮助。以下是内存资源配额对命名空间施加的三条限制:

  • 命名空间中运行的每个Pod中的容器都必须有内存限制。(如果为Pod中的每个容器声明了内存限制,Kubernetes可以通过奖其容器的内存限制相加推断出Pod级别的内存限制)
  • 内存限制用来在Pod被调度的节点上执行资源预留,预留给命名空间中所有Pod使用的内存总量不能超过规定的限制。
  • 命名空间中所有Pod实际使用的内存总量也不能超过规定的限制。

当添加LimitRange时,如果该命名空间中的任何Pod中的容器未指定内存限制,控制面将默认内存限制应用于该容器,这样Pod可以在受到内存ResourceQuota限制的命名空间中运行。

为命名空间配置最大和最小内存约束

首先创建命名空间,以便在此实验练习中创建的资源与集群的其他资源进行隔离。

kubectl create ns constraints-mem

接着创建LimitRange,在LimitRange的清单中声明最大内存请求和最小内存限制:

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-min-max-demo-lr
spec:
  limits:
  - max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container

创建LimitRange:

kubectl apply -f memory-constraints.yaml -n constraints-mem

查看LimitRange的详情:

kubectl get -f memory-constraints.yaml -n constraints-mem -oyaml

输出显示预期的最大和最小内存约束,但是注意,即使没有在LimitRange的配置文件中指定默认值,也会自动创建他们:

limits:
- default:
    memory: 1Gi
  defaultRequest:
    memory: 1Gi
  max:
    memory: 1Gi
  min:
    memory: 500M
  type: Container

现在,每当在constraints-mem命名空间中创建Pod时,Kubernetes就会执行下面步骤:

  • 如果Pod中的任何容器未声明自己的内存请求和限制,控制面将为该容器设置默认的内存请求和限制。
  • 确保该Pod中的每个容器的内存请求至少500MiB。
  • 确保该Pod中每个容器内存请求不大于1GiB。

1、创建满足LimitRange限制的Pod

以下为包含一个容器的Pod清单,该容器声明了600MiB的内存请求和800MiB的内存限制,这些满足了LimitRange施加的最小和最大内存约束。

# memory-constraints-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
  namespace: constraints-mem
spec:
  containers:
  - name: constraints-mem-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "600Mi"

创建Pod后进行查看Pod详情:

kubectl get -f memory-constraints-pod.yaml  -oyaml

输出结果显示该Pod的容器内存请求为600MiB,内存限制为800MiB。这些满足这个命名空间中LimitRange设定的限制范围。

containers:
- image: nginx:1.17.1
  imagePullPolicy: IfNotPresent
  name: constraints-mem-demo-ctr
  resources:
    limits:
      memory: 800Mi
    requests:
      memory: 600Mi

2、尝试创建一个超过最大内存限制的Pod

以下为包含一个容器的Pod清单,这个容器声明了800MiB得内存请求和1.5GiB的内存限制。

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
  namespace: constraints-mem
spec:
  containers:
  - name: constraints-mem-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "1.5Gi"
      requests:
        memory: "800Mi"

尝试创建Pod,会发现Pod创建失败,因为它定义了一个容器的内存请求超过了允许的值。

Error from server (Forbidden): error when creating "memory-constraints-pod.yaml": pods "constraints-mem-demo" is forbidden: maximum memory usage per Container is 1Gi, but limit is 1536Mi

3、尝试创建一个不满足最小内存请求的Pod

以下为只有一个容器的 Pod 的清单。这个容器声明了 100 MiB 的内存请求和 800 MiB 的内存限制。

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
  namespace: constraints-mem
spec:
  containers:
  - name: constraintes-mem-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "100Mi"

尝试创建Pod,会发现Pod创建失败,因为它定义了一个容器的内存请求小于强制要求的最小值:

Error from server (Forbidden): error when creating "memory-constraints-pod.yaml": pods "constraints-mem-demo" is forbidden: minimum memory usage per Container is 500Mi, but request is 100Mi

4、创建一个没有声明内存请求和限制的Pod

以下为只有一个容器的Pod清单,该容器没有声明内存请求,也没有声明内存限制。

# memory-constraints-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
  namespace: constraints-mem
spec:
  containers:
  - name: constraints-mem-demo-ctr
    image: nginx:1.17.1

创建Pod后进行查看Pod的详情:

kubectl get -f memory-constraints-pod.yaml  -o yaml

输出结果显示Pod的唯一容器内存请求为1GiB,内存限制为1GiB,容器怎样获得那些数值呢?

containers:
- image: nginx:1.17.1
  imagePullPolicy: IfNotPresent
  name: constraints-mem-demo-ctr
  resources:
    limits:
      memory: 1Gi
    requests:
      memory: 1Gi

因为声明的Pod没有为容器声明任何内存请求和限制,集群会从LimitRange获取默认的内存请求和限制,应用于容器。

5、强制执行内存最大和最小限制

LimitRange为命名空间设定的最大和最小内存限制只有在Pod创建和更新时才会强制执行,如果更新LimitRange,它不会影响此前创建的Pod。

为命名空间配置默认的cpu请求和限制

如果在具有默认CPU限制的命名空间内创建一个Pod,并且这个Pod中任何容器都没有声明自己的CPU限制,那么控制面会为容器设定默认的CPU限制。

首先创建一个命名空间,以便在本次实验练习创建的资源和集群的其余部分相隔离。

kubectl create ns default-cpu

接着创建LimitRange,在LimitRange的清单中声明默认的CPU请求和默认的CPU限制:

# cpu-defaults.yaml

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default:
      cpu: 1
    defaultRequest:
      cpu: 0.5
    type: Container

在命名空间default-cpu中创建LimitRange对象:

kubectl apply -f cpu-defaults.yaml -n default-cpu

1、容器没有声明CPU请求和限制

现在在default-cpu命名空间中创建一个Pod,这个Pod中所有的容器都没有声明自己的CPU请求和CPU限制,控制面会将CPU的默认请求值0.5和默认限制值1应用到Pod上。

以下是包含一个容器的Pod清单,该容器没有声明CPU请求和限制。

# cpu-defaults-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo
  namespace: default-cpu
spec:
  containers:
  - name: default-cpu-demo-ctr
    image: nginx:1.17.1

创建Pod后进行查看:

kubectl get pod -n default-cpu-demo -n default-cpu -oyaml

输出显示该Pod的唯一容器有500m cpu的CPU请求和1 cpu的CPU限制,这些都是LimitRange声明中的默认值:

containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: default-cpu-demo-ctr
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: 500m

2、只声明容器的限制,不声明容器的请求

以下为只包含一个容器的Pod清单,该容器声明了CPU限制,而没有声明CPU请求。

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo
  namespace: default-cpu
spec:
  containers:
  - name: default-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        cpu: "1"

创建Pod后进行查看:

kubectl get pod -n default-cpu-demo -n default-cpu -oyaml

输出显示该容器的CPU请求和CPU限制设置相同,注意该容器没有被指定默认的CPU请求值是0.5 cpu:

containers:
- image: nginx:1.17.1
  imagePullPolicy: IfNotPresent
  name: default-cpu-demo-ctr
  resources:
    limits:
      cpu: "1"
    requests:
      cpu: "1"

3、只声明容器的请求,不声明限制

以下为只包含一个容器的Pod清单,该容器声明了CPU请求,而没有声明CPU限制。

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo
  namespace: default-cpu
spec:
  containers:
  - name: default-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      requests:
        cpu: "0.75"

创建Pod后进行查看:

kubectl get pod -n default-cpu-demo -n default-cpu -oyaml

输出显示所创建的Pod中,容器的CPU请求为Pod清单中声明的值,然而同一容易CPU限制被设置为1 cpu,此值是该命名空间的默认CPU限制值。

containers:
- image: nginx:1.17.1
  imagePullPolicy: IfNotPresent
  name: default-cpu-demo-ctr
  resources:
    limits:
      cpu: "1"
    requests:
      cpu: 750m

4、默认CPU限制和请求的动机

如果命名空间设置了CPU资源配额,为CPU限制设置一个默认值会很有帮助,以下是CPU资源配额对命名空间施加的两条限制:

  • 命名空间中运行的每个Pod中的容器都必须有CPU限制
  • CPU限制用来在Pod被调度到的节点上执行资源预留

预留给命名空间中所有Pod使用的CPU总量不能超过规定的限制。

当添加LImitRange时,如果该命名空间中的任何Pod中容器未指定CPU限制,控制面板将默认CPU限制应用于该容器,这样Pod可以在受到CPU ResourceQuota限制的命名空间中的运行。

为命名空间配置CPU最大和最小约束

创建一个命名空间:

kubectl create ns constraints-cpu

以下为LimitRange的示例清单:

# cpu-constraints.yaml

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-min-max-demo-lr
spec:
  limits:
  - max:
      cpu: "800m"
    min:
      cpu: "200m"
    type: Container

创建LimitRange:

kubectl apply -f cpu-constraints.yaml -n constraints-cpu

查看LimitRange详情:

kubectl get limitrange cpu-min-max-demo-lr --output=yaml --namespace=constraints-cpu

输出结果显示CPU的最小和最大限制符合预期,但需要注意的是,尽管LimitRange的配置文件中没有声明默认值,默认值也会被自动创建:

limits:
- default:
    cpu: 800m
  defaultRequest:
    cpu: 800m
  max:
    cpu: 800m
  min:
    cpu: 200m
  type: Container

现在,每当在constraints-cpu命名空间中创建Pod时,或者某些其他的Kubernetes API客户端常见等价的Pod时,Kubernetes就会执行下面的步骤:

  • 如果Pod中的任何容器未声明自己的CPU请求和限制,控制面将为该容器设置默认的CPU请求和限制。
  • 确保该Pod中每个容器的CPU请求至少200 millicpu
  • 确保该Pod中每个容器的CPU不大于800 millicpu

1、创建满足LimitRange限制的Pod

以下是仅包含一个容器的Pod清单,该容器声明了CPU请求500 millicpu 和 CPU限制800 millicpu。这些参数满足了LimitRange对象为此命名空间规定的CPU最小和最大限制。

# cpu-constraints-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo
  namespace: constraints-cpu
spec:
  containers:
  - name: constraints-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        cpu: "800m"
      requests:
        cpu: "500m"

创建Pod,并确认Pod正在运行, 容器处于健康状态后,查看Pod详情:

kubectl get -f cpu-constraints-pod.yaml  -oyaml

输出结果显示该Pod的容器CPU请求为500 millicpu,CPU限制为800 millicpu。这些参数满足LimitRange规定的限制范围。

resources:
  limits:
    cpu: 800m
  requests:
    cpu: 500m

2、尝试创建一个超过最大CPU限制的Pod

这里给出了包含一个容器的 Pod 的配置文件。容器声明了 500 millicpu 的 CPU 请求和 1.5 CPU 的 CPU 限制。

apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo
  namespace: constraints-cpu
spec:
  containers:
  - name: constraints-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        cpu: "1.5"
      requests:
        cpu: "500m"

尝试创建Pod后,发现Pod创建失败,因为其中定义了一个无法被接受的容器,该容器之所以无法被接受是因为其中设定了过高的CPU限制值:

Error from server (Forbidden): error when creating "cpu-constraints-pod.yaml": pods "constraints-cpu-demo" is forbidden: maximum cpu usage per Container is 800m, but limit is 1500m

3、尝试创建一个不满足最小CPU请求的Pod

以下为某个只有一个容器的 Pod 的清单。该容器声明了 CPU 请求 100 millicpu 和 CPU 限制 800 millicpu。

apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo
  namespace: constraints-cpu
spec:
  containers:
  - name: constraints-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        cpu: "800m"
      requests:
        cpu: "100m"

尝试创建Pod,输出结果显示Pod创建失败,因为其中定义了一个无法被接受的容器,该容器无法被接受的原因是其中所设置的CPU请求小于最小值的限制:

Error from server (Forbidden): error when creating "cpu-constraints-pod.yaml": pods "constraints-cpu-demo" is forbidden: minimum cpu usage per Container is 200m, but request is 100m

4、创建一个没有声明CPU请求和CPU限制的Pod

以下为一个只有一个容器的 Pod 的清单。该容器没有声明 CPU 请求,也没有声明 CPU 限制。

apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo
  namespace: constraints-cpu
spec:
  containers:
  - name: constraints-cpu-demo-ctr
    image: nginx:1.17.1

创建Pod后,查看Pod详情,输出结果显示Pod唯一容器的CPU请求为800 milicpu,CPU限制为800 millicpu。

容器是怎么获得这些数值的呢?

resources:
  limits:
    cpu: 800m
  requests:
    cpu: 800m

因为这一容器没有声明自己的CPU请求和限制,控制面会根据命名空间中配置的LimitRange设置默认的CPU请求和限制。

5、CPU最大和最小限制的强制执行

只有当Pod创建或者更新时,LimitRange为命名空间规定的CPU最小和最大限制才会被强制执行。如果对LimitRange进行修改,那不会影响此前创建的Pod。

为命名空间配置内存和CPU配额

创建一个命名空间。

kubectl create ns quota-mem-cpu

创建ResourceQuota:

# quota-mem-cpu.yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-demo
  namespace: quota-mem-cpu
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi

ResourceQuota在quota-men-cpu命名空间中设置了如下要求:

  • 在该命名空间中的每个Pod的所有容器都必须要有内存请求和限制,以及CPU请求和限制
  • 在该命名空间中所有Pod的内存请求总和不能超过1GiB
  • 在该命名空间中所有Pod的内存限制总和不能超过2GiB
  • 在该命名空间中所有Pod的CPU请求总和不能超过1cpu
  • 在该命名空间中所有Pod得CPU限制总和不能超过2cpu

接下来创建一个Pod,以下是Pod的示例清单:

# quota-mem-cpu-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: quota-mem-cpu-demo
  namespace: quota-mem-cpu
spec:
  containers:
  - name: quota-mem-cpu-demo-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "800Mi"
        cpu: "800m"
      requests:
        memory: "600Mi"
        cpu: "400m"

创建Pod,确定Pod正常运行以及其容器处于健康状态,查看ResourceQuota的详情:

kubectl get resourcequota mem-cpu-demo -n quota-mem-cpu -oyaml

输出结果显示了配额以及有多少配额已经被使用。可以看到Pod的内存和CPU请求值及限制值没有超过配额。

status:
  hard:
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.cpu: "1"
    requests.memory: 1Gi
  used:
    limits.cpu: 800m
    limits.memory: 800Mi
    requests.cpu: 400m
    requests.memory: 600Mi

接着我们尝试创建第二个Pod,以下是第二个Pod的清单:

# quota-mem-cpu-pod-2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: quota-mem-cpu-demo-2
  namespace: quota-mem-cpu
spec:
  containers:
  - name: quota-mem-cpu-demo-2-ctr
    image: nginx:1.17.1
    resources:
      limits:
        memory: "1Gi"
        cpu: "800m"
      requests:
        memory: "700Mi"
        cpu: "400m"

在清单中,可以看到Pod得内存请求为700MiB,注意新的内存请求和已经使用的内存请求之和超过了内存请求的配额:600MiB + 700 MiB > 1GiB。

当尝试创建Pod,会发现第二个Pod不能创建成功。输出结果显示创建第二个Pod会导致内存请求总量超过内存请求限制。

Error from server (Forbidden): error when creating "quota-mem-cpu-pod-2.yaml": pods "quota-mem-cpu-demo-2" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.memory=700Mi, used: requests.memory=600Mi, limited: requests.memory=1Gi

配置命名空间下Pod配额

首先创建一个命名空间:

kubectl create ns quota-pod

接着创建ResourceQuota,下面是ResourceQuota的示例清单:

# quota-pod.yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  name: pod-demo
  namespace: quota-pod
spec:
  hard:
    pods: "2"

创建这个ResourceQuota后查看资源配额的详细信息:

kubectl get -f quota-pod.yaml -oyaml

从输出的信息可以看奥,该命名空间下Pod的配额是2个,目前创建的Pod数为0,配额使用率为0。

spec:
  hard:
    pods: "2"
status:
  hard:
    pods: "2"
  used:
    pods: "0"

接下来我们创建一个Deployment,显式声明replicas:3告诉kubernetes尝试创建三个Pod,且运行相同的应用。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-quota-demo
  namespace: quota-pod
spec:
  selector:
    matchLabels:
      purpose: quota-demo
  replicas: 3
  template:
    metadata:
      labels:
        purpose: quota-demo
    spec:
      containers:
      - name: pod-quota-demo
        image: nginx:1.17.1

然后查看deploy的详情,会发现由于资源配额的限制,只有两个Pod能被创建成功。

参考链接

kubernetes.io/zh-cn/docs/…