这一小节讲解如何分配内存请求和对一个容器做内存限制。一个容器被保证拥有足够的内存可以处理请求,但是也不允许使用超过限制的内存。

开始之前

需要拥有一个k8s集群

需要安装好一个kubectl 工具,并且能够与集群通信。

如果没有准备好,你可以使用minikube或者使用以下的练习场地。

https://www.katacoda.com/courses/kubernetes/playground

http://labs.play-with-k8s.com/

可以使用以下命令,检测版本

kubectl version

集群中的每个节点,至少拥有300MB的内存。

本文中的一些步骤要求你在集群中有运行 metrics-server 的服务,如果你没有运行,你可以跳过这些步骤。

如果你使用的是minikube ,你可以使用以下命令来启用:

minikube addons enable metrics-server

检查 metrics-server是否运行,或者其它提供 metrics api 资源 (metrics.k8s.io),你可以使用以下的命令

kubectl get apiservices

如果 metrics api 资源是可用的,会响应以下内容:

NAME
v1beta1.metrics.k8s.io

创建命名空间

创建命名空间来保证当前的测试环境和集群的其它环境的隔离的。

定义一个内存请求和内存限制

定义一个内存请求:
resources:requests

定义一个内存限制:
resources:limits

在这个练习中,你创建了一个POD包含一个容器,容器申请了100MB的内存,并且设置了200MB内存限制。

apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

args是 提供容器启动的参数。

"--vm-bytes", "150M" 告诉容器分配多少内存

创建一个POD

kubectl create -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example

验证POD是否运行

kubectl get pod memory-demo --namespace=mem-example

查看POD的详细信息,并输出到yaml

kubectl get pod memory-demo --output=yaml --namespace=mem-example

获取POD的技术指标
kubectl top pod memory-demo --namespace=mem-example

显示的内存大小是 162,900,000 bytes ,大约是150MB,大于分配的100MB内存,小于200MB的内存限制。

NAME CPU(cores) MEMORY(bytes)
memory-demo 162856960

删除POD

kubectl delete pod memory-demo --namespace=mem-example

配置容器的内存限制

如果节点有足够的内存,那么容器就可以执行内存的分配请求。但是一个容器不允许使用
超出它的限制的内存。如果一个容器分配的内存超出了它的限制,该容器成为了被停止的候选人。
如果一个容器持续的使用超过自己内存限制的情况,该容器会被停止。如果一个停止的容器
能够被重启,和其它的运行错误一样,kubelet也会去重启它。

在这个练习中,你可以尝试创建一个POD,并且分配超出它限制的内存。
以下为创建一个POD,拥有一个容器,分配50MB的内存,并且设置了100MB的内存限制

apiVersion: v1
kind: Pod
metadata:
name: memory-demo-2
namespace: mem-example
spec:
containers:

  • name: memory-demo-2-ctr
    image: polinux/stress
    resources:
    requests:
    memory: "50Mi"
    limits:
    memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

    在 args 选项,我们尝试分配了250MB的内存,超过了我们设置的100MB限制。

创建POD

kubectl create -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

查看创建的POD的详细信息

kubectl get pod memory-demo-2 --namespace=mem-example

这个事情,容器可能在运行或者被杀掉,重复之前的命令直到容器被杀掉为止。
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s

查看容器的更多详细信息

kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

这个输出显示容器被杀掉的原因是因为内存不足(OOM)

lastState:
terminated:
containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null

在该练习中的容器可以被重启,那么kubelet 就会重启它。重启这个命令,会看到容器不断
被杀掉和重启

kubectl get pod memory-demo-2 --namespace=mem-example

下面的输出显示容器被杀掉,重启,再次被杀掉,再次重启等等

kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s

kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s

查看POD的更多历史信息

kubectl describe pod memory-demo-2 --namespace=mem-example

以下是容器不断启动和失败的事件信息
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container

查看节点的详细信息

kubectl describe nodes

下面的记录显示容器被杀掉是因为内存不足

Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

删除POD

kubectl delete pod memory-demo-2 --namespace=mem-example

定义一个内存分配超过你的节点的内存容量

内存被分配和限制用于容器,但是同样适用于POD。所有在POD的容器的内存分配总和就是
POD的容器请求,同样,在POD容器的内存限制总和就是POD容器的限制。

POD的调度是基于请求。一个POD可以被调度去运行,只有在节点有足够的内存来满足
POD内存的请求。

在这个练习中,你创建了一个POD,内存的请求大于集群中任意节点的容量。以下为创建一个
POD拥有一个容器,要求1000GB的内存,超过了集群中的任意节点的内存容量。

apiVersion: v1
kind: Pod
metadata:
name: memory-demo-3
namespace: mem-example
spec:
containers:

  • name: memory-demo-3-ctr
    image: polinux/stress
    resources:
    limits:
    memory: "1000Gi"
    requests:
    memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

创建POD
kubectl create -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

查看POD状态

kubectl get pod memory-demo-3 --namespace=mem-example

状态显示POD为 PENDING 。 意味着POD没有被调度到任何一个节点上面。它将会被无限期
停留在PENDING状态。

kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s

查看POD的详细信息
kubectl describe pod memory-demo-3 --namespace=mem-example

以下的信息显示容器没有被调度是因为内存不足
Events:
... Reason Message


... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).

内存单元

内存的资源是用bytes来衡量。你可以用普通整数或者带小数点的整数来表达内存容量。

后缀为E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki.

例如下面的值:

128974848, 129e6, 129M , 123Mi

删除POD
kubectl delete pod memory-demo-3 --namespace=mem-example

如果你没有定义内存限制

如果你没有设置内存限制,以下的情况将被适用:

  1. 容器没有内存的上限边界。容器能够使用节点的所有可用内存。
  2. 容器运行的命名空间有默认的内存限制,容器将被自动分配这个默认的限制。集群管理员
    可用使用 LimitRange 来定义内存限制的默认值。

内存请求和限制的动机

在运行的集群中对容器进行内存的分配和限制,可以使集群的内存资源使用效率更高。
保持POD的内存请求较低,这样POD可以有机会可以被调度。设置内存限制比内存分配更好,
你可以完成以下的两件事情:

    POD 可能存在对内存的爆发性需求
    POD内存容量的爆发可以被限制在合理的区间。

清除

清除命名空间。删除以上练习创建的所有POD

kubectl delete namespace mem-example