K8S实战(十八)| 容器资源分配和资源限制
码农天地 -前言
为了防止容器调度到资源不足的节点上,可以为容器指定资源最少要求量。
为了防止容器无节制的使用 CPU、内存 等资源,可以为容器指定资源最大允许使用量。
更新历史20200714 - 初稿 - 左程立原文地址 - https://blog.zuolinux.com/2020/07/14/container-resources-request-limit.html资源请求和资源约束可以为容器指定资源请求量和资源约束量。
资源一般指 CPU、内存。
资源请求量,指容器要求节点分配的最小容量,如果该节点可用容量小于容器要求的请求量,容器将被调度到其他合适节点。
资源约束量,指容器要求节点限制其使用的最大容量,如果容器内存使用量超过内容约束量,容器将被杀掉,如果指定了重启策略,容器杀掉后将被重启。
涉及的参数
约束量
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.limits.hugepages-<size>
请求量
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.requests.hugepages-<size>
示例
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
资源单位K8S 中的一个 cpu 等于云平台上的 1 个 vCPU/核或裸机 Intel 处理器上的 1 个超线程。
spec.containers[].resources.requests.cpu 为 0.5 的容器肯定能够获得请求 1 CPU 的容器的一半 CPU 资源。表达式 0.1 等价于表达式 100m, 可以看作 “100 millicpu”。具有小数点(如 0.1)的请求由 API 转换为 100m;最大精度是 1m。
优先考虑使用 100m 的形式。
内存可以使用E、P、T、G、M、K。也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。
Pod 的资源请求和约束Pod 的请求量等于内部所有容器的请求量之和。
Pod 的约束量等于内部所有容器的约束量之和。
带资源请求的 Pod 如何调度调度程序确保所调度的 Pod 的资源请求量小于节点的容量。
即,调度程序将查找到资源可用量充足的,可用量大于请求量的节点来放置 Pod。
带资源约束的 Pod 如何运行 内存资源约束如果容器超过其内存最大限制,则可能会被终止。如果容器可重新启动,kubelet 将重新启动容器。
如果一个容器内存使用量超过其内存请求值,那么当节点内存不足时,容器所处的 Pod 可能被逐出。
CPU 资源约束每个容器可能被允许也可能不被允许使用超过其 CPU 约束的处理时间。 但是,容器不会由于 CPU 使用率过高而被杀死。
spec.containers[].resources.limits.cpu 先被转换为 millicore 值,再乘以 100。其结果就是每 100 毫秒内容器可以使用的 CPU 时间总量。在此期间(100ms),容器所使用的 CPU 时间不会超过它被分配的时间。
默认的配额(quota)周期为 100 毫秒。 CPU配额的最小精度为 1 毫秒。
如何获知集群资源使用情况,需要通过 metrics-server 来获取。
metrics-server查看是否已安装 metrics-server,以下说明没安装
# kubectl top node
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
# kubectl get pods,svc,deployments -n kube-system | grep metrics-server
#
开始安装 metrics-server
git clone https://github.com/kubernetes-incubator/metrics-server
cd metrics-server/
git checkout release-0.3
修改 metrics-server/deploy/1.8+/metrics-server-deployment.yaml
containers:
- name: metrics-server
#image: k8s.gcr.io/metrics-server/metrics-server:v0.3.6
image: registry.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
imagePullPolicy: IfNotPresent
args:
- --cert-dir=/tmp
- --secure-port=4443
- --metric-resolution=30s
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
- --kubelet-insecure-tls
参数说明
--metric-resolution=30s:从 kubelet 采集数据的周期;
--kubelet-preferred-address-types:优先使用 InternalIP 来访问 kubelet,这样可以避免节点名称没有 DNS 解析记录时,通过节点名称调用节点 kubelet API 失败的情况(未配置时默认的情况);
--kubelet-insecure-tls:kubelet 的10250端口使用的是https协议,连接需要验证tls证书。--kubelet-insecure-tls不验证客户端证书
安装
kubectl apply -f deploy/1.8+/
再次查看,需要多等一会儿,确保采集到数据。
[root@master01 ~]# kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[]}
[root@master01 1.8+]# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master01 163m 4% 2093Mi 56%
master02 147m 3% 1638Mi 44%
master03 151m 3% 1609Mi 43%
work01 141m 3% 1084Mi 29%
work02 150m 3% 1097Mi 29%
work03 138m 3% 1471Mi 39%
[root@master01 1.8+]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
mysql-0 15m 202Mi
mysql-1 14m 191Mi
mysql-2 13m 182Mi
nfs-client-provisioner-7db698bbc9-8ph55 2m 8Mi
已经可以看到资源使用情况。
实践内存限额创建一个测试用命名空间
# kubectl create namespace mem-example
namespace/mem-example created
创建一个最大限额 100M,但最少需要 250M 的容器
# cat memory-request-limit-2.yaml
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"]
# kubectl apply -f memory-request-limit-2.yaml
pod/memory-demo-2 created
查看发现创建失败
# kubectl get pod -n mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 CrashLoopBackOff 3 88s
查看原因
# kubectl get pod -n mem-example -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' memory-demo-2
Container Name: memory-demo-2-ctr
LastState: map[terminated:map[containerID:docker://aaf41e exitCode:1 reason:OOMKilled ]]
其中有 reason:OOMKilled,说明超过了内存最大限额,导致了 OOM 然后被杀掉。
结束语通过 resources.requests 和 resources.limits,可以对资源进行最少容量要求和最大容量限制,确保容器可以运行在资源充足的节点上,同时也不会由于自身占用了过多资源而影响节点上其他容器。
联系我微信公众号:zuolinux_com