Kubernetes 设计了 Compute Resource(计算资源)的概念。与 API Resource(比如 Pod, Service)不同,compute resource 表示一个容器在运行时的资源使用,分为 CPU 和内存两种。每种资源又分为 request 和 limit 两种,比如下面的 deployment:
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"
其中:
- CPU
- Limit 的值表示该容器能使用的最多 CPU 时间(应该是通过 cgroup 去限制的)。如果容器的 CPU 使用率很高,容器实现(如 docker)可能会允许容器使用比它的 limit 更多的 CPU,但是 K8S 不会将容器杀掉
- Request 的值通过转换,会变成
--cpu-share
参数传给 docker
- 内存
- Limit 表示能使用的内存上限。容器业务程序使用的量大于 limit 值时,会因为 OOM 被容器内的操作系统杀掉
- Request 表示 K8S 保证分配给容器使用的内存量。如果业务程序使用的内存大于 request,且 node 节点上资源不足时,容器有可能被 K8S evict
虽然 limit / request 是配置在容器上的,但是 pod 也有这个概念,它的 limit / request 指其中所有容器的总和。
K8S 在选择 node 节点去部署 pod 时,会保证该 node 剩余的容量 大于 pod 所要求的 request,但不要求剩余容量大于 limit。Node capacity 一般由 kubelet 自动上报,但是也可以手动指定,比如你需要预留一部分资源给不被 K8S 管理的进程时。K8S 计算 node 剩余容量时,不会将非 kubelet 管理的资源计算进来,比如你手动 docker run 的容器,或者 node 节点上非容器的进程。
内存占用高的一个场景
在工作中,发现有一个场景会引起容器中的 cache 内存占用升得非常高。
在我们的例子中,容器有 8G 内存,实际 RSS 占用仅有 1G 不到,但是 cache 内存占了 6G。Cache 内存的上升是由于突发地大量打日志引起。Cache 占用上去后,长时间没有自动回收;不清楚回收机制。
这篇 文章 似乎描述了同样的问题,未细看,应该看。
这个命令应该可以要求 kernel 回收 cache 内存:
sysctl -w vm.drop_caches=1
容器环境中,Linux 的 OOM Killer 会将 cache 内存纳入 OOM 的考虑之中。
Kubernetes 使用 container_memory_working_set_bytes
指标来监控容器的内存使用。
参考
- Managing Compute Resources for Containers - Kubernetes
- Nodes - Kubernetes
- Kubernetes in Action 一书中,Chapter 14: Managing pods' computational resources 有非常详尽的描述