这一小节讲解如何分配内存请求和对一个容器做内存限制。一个容器被保证拥有足够的内存可以处理请求,但是也不允许使用超过限制的内存。
开始之前
需要拥有一个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
删除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
如果你没有定义内存限制
如果你没有设置内存限制,以下的情况将被适用:
- 容器没有内存的上限边界。容器能够使用节点的所有可用内存。
- 容器运行的命名空间有默认的内存限制,容器将被自动分配这个默认的限制。集群管理员
可用使用 LimitRange 来定义内存限制的默认值。
内存请求和限制的动机
在运行的集群中对容器进行内存的分配和限制,可以使集群的内存资源使用效率更高。
保持POD的内存请求较低,这样POD可以有机会可以被调度。设置内存限制比内存分配更好,
你可以完成以下的两件事情:
POD 可能存在对内存的爆发性需求
POD内存容量的爆发可以被限制在合理的区间。
清除
清除命名空间。删除以上练习创建的所有POD
kubectl delete namespace mem-example