Kubernetes之容器计算资源管理

Kubernetes有一种与资源配额管理有关的对象:ResourceQuota,此种类型的对象由集群管理员创建,创建好后作用于某个名称空间,限制名称空间内可以创建的各类对像的总数、CPU、内存等。用户、用户组则工作在名称空间之下,以此实现多用户、多用户共享同一集群,公平合理的分配资源。本文描述在一个名称空间之下创建容器时,对容器所使用的计算资源进行管理。

计算资源类型

计算资源包含cpu与memory,就是通常计算机上的硬件资源,不包含存储。计算资源可以被计量、申请、分配、消费。在Kurnetes中cpu的计量单位是core,就是几个核。memory的计算单位是byte,就是字节数。

定义pod、container时与计算资源相关的字段

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory

在定义pod时,以上与计算资源相关的字段只能指定给其中所定义的容器。当谈讨pod的limit与request时,指的是pod所有容器limit或者是request的总和。

CPU含义

在Kubernetes层面中,一个CPU表示一个核心处理器的core,但其具体含义取决于低层基础设施供应商,有可能是物理core、虚拟core、一个线程等,以下是一个CPU核在常见的基础设施供应商的含义:

  • 1 AWS vCPU
  • 1 GCP Core
  • 1 Azure vCore
  • 1 IBM vCPU
  • 1 Hyperthread on a bare-metal Intel processor with Hyperthreading

CPU的核数,最终应该是被转换成表示线程占用CPU的时长。首先换算的单位是100m(100毫秒),100m对应0.1个核。比如,0.4表示400毫秒的CPU内核运行时间,1表示1000毫秒的CPU内核运行时间,1.5表示1500毫秒的CPU内核运行时间,可以直接指定如400m、1500m,这种方法更直观更通用。如果一个节点有4个核则在1秒内有4000毫秒的时间片可供分配。所以无论宿主机节点有多少个核,CPU术数表示的意义不变,它是一个绝对值。另外它只能精确到小数点后1位或者是100m

MEMORY含义

其含义是字节数,表示多少个字节。在书写时可以用整数、指数、表示计算机容器的K、M等。

配置示例

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

requests字段对调度的影响

调度器计算pod中所有容器对cpu、memory需求总数,从候选节点中将不符合条件的节点过滤,如果没有节点符合条件则pod等待下一次调试并将调度失败的原因输出到pod事件中。

requests、limits字段对运行中容器的影响

容器运行环境一般是docker,在启动容器时由kubernetes将与limit有关的字段传递给kubelet,再由kubelet传递给容器运行时环境如docker run。

如果容器在运行时内存使用超过request但小于limit,容器不会被杀死,但当节点上的操作系统或者kubernetes认为节点内存紧张时,内存超过request的容器应该优先被杀死。如果容器在运行时内存使用超过limit应该立即被kubelet杀死,然后根据重启策略重启。

CPU的使用与内存不同,在定义容器时对CPU的request与limit作了限制,但是CPU的真实使用情况决定于操作系统的调度。即使CPU超过limit的限制,kubelet也不会杀死容器,因为这是操作系统的责任,操作系统有可能会杀死容器。

监控计算资源的使用

  • 资源的使用作为pod状态的一部分,可通过查看pod描述查看。
  • 配置集群资源监控系统,监控pod资源的使用。

问题定位、错误排查

pod调度失败:

当pod因为计算资源问题调度失败时,它处于pending状态,并且生成调度失败的错误事件,指明调度失败原因。系统重复调度pod直到找倒满足条件的pod。通过如下方法定位此类问题:

$ kubectl describe pod frontend | grep -A 3 Events
Events:
  FirstSeen LastSeen   Count  From          Subobject   PathReason      Message
  36s   5s     6      {scheduler }              FailedScheduling  Failed for reason PodExceedsFreeCPU and possibly others

出现此类问题的解决方法:

  • 增加node,提高资源的问题。
  • 删除不需要的pod,垃圾回收。
  • 确认pod配置,是否请求资源的数量超过了系统能力。

执行如下命令确认node的资源问题及使用情况:

$ kubectl describe nodes e2e-test-minion-group-4lw4
Name:            e2e-test-minion-group-4lw4
[ ... lines removed for clarity ...]
Capacity:
 cpu:                               2
 memory:                            7679792Ki
 pods:                              110
Allocatable:
 cpu:                               1800m
 memory:                            7474992Ki
 pods:                              110
[ ... lines removed for clarity ...]
Non-terminated Pods:        (5 in total)
  Namespace    Name                                  CPU Requests  CPU Limits  Memory Requests  Memory Limits
  ---------    ----                                  ------------  ----------  ---------------  -------------
  kube-system  fluentd-gcp-v1.38-28bv1               100m (5%)     0 (0%)      200Mi (2%)       200Mi (2%)
  kube-system  kube-dns-3297075139-61lj3             260m (13%)    0 (0%)      100Mi (1%)       170Mi (2%)
  kube-system  kube-proxy-e2e-test-...               100m (5%)     0 (0%)      0 (0%)           0 (0%)
  kube-system  monitoring-influxdb-grafana-v4-z1m12  200m (10%)    200m (10%)  600Mi (8%)       600Mi (8%)
  kube-system  node-problem-detector-v0.1-fj7m3      20m (1%)      200m (10%)  20Mi (0%)        100Mi (1%)
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  CPU Requests    CPU Limits    Memory Requests    Memory Limits
  ------------    ----------    ---------------    -------------
  680m (34%)      400m (20%)    920Mi (12%)        1070Mi (14%)

以上输出列出了计算资源目前占用情况。如果新pod的资源需求超过了未占用资源数量,则此node会被调度程序排除,后半部分的内容显示pod占用资源的详细情况。一般情况下资源总量小于节点实际总量,因为一般不允许kubernetes占用全部的节点资源。

容器运行失败

运行中的容器有可能因为资源问题被终止,运行如下指令确认容器终止原因:

[12:54:41] $ kubectl describe pod simmemleak-hra99
Name:                           simmemleak-hra99
Namespace:                      default
Image(s):                       saadali/simmemleak
Node:                           kubernetes-node-tf0f/10.240.216.66
Labels:                         name=simmemleak
Status:                         Running
Reason:
Message:
IP:                             10.244.2.75
Replication Controllers:        simmemleak (1/1 replicas created)
Containers:
  simmemleak:
    Image:  saadali/simmemleak
    Limits:
      cpu:                      100m
      memory:                   50Mi
    State:                      Running
      Started:                  Tue, 07 Jul 2015 12:54:41 -0700
    Last Termination State:     Terminated
      Exit Code:                1
      Started:                  Fri, 07 Jul 2015 12:54:30 -0700
      Finished:                 Fri, 07 Jul 2015 12:54:33 -0700
    Ready:                      False
    Restart Count:              5
Conditions:
  Type      Status
  Ready     False
Events:
  FirstSeen                         LastSeen                         Count  From                              SubobjectPath                       Reason      Message
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {scheduler }                                                          scheduled   Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   pulled      Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   created     Created with docker id 6a41280f516d
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   started     Started with docker id 6a41280f516d
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    spec.containers{simmemleak}         created     Created with docker id 87348f12526a

以上输出的"Restart Count"等于5表示 容器"simmemleak"被重启了5次,并且Ready为false。Pod对象描述中包含一个数组,其中列出了所有容器历史退出的状态码与错误消息,运行如下命令进一步查看:

[13:59:01] $ kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}'  simmemleak-hra99
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]

可以看到是因为内存溢出被杀死。

本地临时存储

在每个节点上,Kubernetes的根目录(/var/lib/kubelet by default)、日志目录(/var/log)通常位于节点上的根分区,此分区也同时被 EmptyDir volumes, container logs, image layers and container writable layers等消费。用户可以为image layers、容器可读写层指定其它分区,此时的临时存储空间不受本节内容的限制。那么如何限制pod对根分区的消耗呢?

为container设置对根分区存储的request与limit字段:

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

示例:

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
  - name: wp
    image: wordpress
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"

本地临时存储资源对调度的影响 

如果节点提供的存储能力达不到pod的要求,则调度程序将节点从候选列表删除。

本地临时存储资源对运行中容器的影响

这个与内存不同,内存是杀死后重新启动。存储的话即使杀死容器也不会释放存储空间, 因此kubernetes采用的是将pod从当前节点排挤出去。

你可能感兴趣的:(kubernetes)