在一个宿主机的内核之上可以运行多个容器,这些容器共享底层宿主机的内核,因此任何一个容器都可以请求占有这个内核管理的所有可用硬件资源。

但若是在多租户的环境下如果有人运行了恶意代码,那个这个容器会及大量的去占有宿主机上的资源,进而导致其他容器无法运行。

容器间的隔离默认情况下只是在内核的名称空间级别进行了隔离,但在进程运行时所用到的资源范围上没有做太多的隔离操作。

因而我们应该为每一个应用设定在其内部运行时的资源最小保证量(request)和最大保证量(limits)。

  • request:确保节点至少为Pod或容器预留的资源最小量。
  • limits:限制pod或容器的最大使用量。

计算资源

k8s中的计算资源有2种,CPU、Memory。

CPU是一种可压缩资源,一个应用在不运行时不会调度到CPU上。

memory是不可压缩资源。其所申请的资源会被占用的。任何一种扩缩容都可能导致程序的崩溃或者OOM的发生。

k8s中CPU不是按照占用百分比来分配的。 而是指定容器可以占用多少个核心。1核等于1000m核。

k8s的memery分配和一般的分配没有区别,1Ki、1Mi。i表示为1024进制的。

计算资源限制参数

k8s中根据计算资源的上下阈值为其设定了4个参数

1
2
3
4
5
6
7
resource:
reuqests:
cpu:
memory:
limits:
cpu:
memory:

资源需求和限制示例

示例1

1.编写资源清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@k8s-master01:~/yaml/chapter04# vim resource-requests-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: stress-pod
spec:
containers:
- name: stress
image: ikubernetes/stress-ng
command: ["/usr/bin/stress-ng","-c 1","-m 1","--metrics-brief"] # 启动一个进程,一个内存进程
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"

2.应用资源清单

1
2
3
4
5
6
root@k8s-master01:~/yaml/chapter04# kubectl apply -f resource-requests-demo.yaml
pod/stress-pod created

root@k8s-master01:~/yaml/chapter04# kubectl get pods stress-pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
stress-pod 1/1 Running 0 4m5s 10.244.2.23 k8s-node02 <none> <none>

3.在pod内观察资源消耗状况

1
2
3
4
5
6
7
8
9
10
root@k8s-master01:~/yaml/chapter04# kubectl exec stress-pod -- top
Mem: 5691452K used, 2460832K free, 6760K shrd, 517008K buff, 3715652K cached
CPU: 8% usr 0% sys 0% nic 89% idle 0% io 0% irq 0% sirq
Load average: 0.57 0.62 0.48 3/960 16
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
7 1 root R 6900 0% 0 4% {stress-ng-cpu} /usr/bin/stress-ng
9 8 root R 262m 3% 1 3% {stress-ng-vm} /usr/bin/stress-ng
1 0 root S 6252 0% 5 0% /usr/bin/stress-ng -c 1 -m 1
8 1 root S 6252 0% 4 0% {stress-ng-vm} /usr/bin/stress-ng
10 0 root R 1512 0% 4 0% top

cpu 8%:k8s-node02上有6颗核心,正常情况下要启动一个cpu来运行进程,而在配置清单中定义了一个进程最大占用cpu为400m核。6个CPU最大占用其中一颗的0.4核,所以cpu占用8%。如果配置清单中不设置limits上限,CPU会占用17%左右。这是因为一个进程在设计时默认为单进程的,所以其最多也就绑定在一个CPU核心上,其最多也就占用一个CPU核心的资源。

memory占用262m:在stress-ng这个压测容器中,一个进程默认做多占用256M,所以此处显示内存占用262M。

4.其他,查看pod内的内存信息

1
2
3
4
5
6
7
8
9
10
11
12
13
root@k8s-master01:~/yaml/chapter04# kubectl exec stress-pod --  free -m
total used free shared buffers cached
Mem: 7961 6898 1062 6 592 4315
-/+ buffers/cache: 1990 5970
Swap: 0 0 0

root@k8s-master01:~/yaml/chapter04# kubectl exec stress-pod -- grep "processor" /proc/cpuinfo
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5

在上面的结果中可以看到,虽然资源清单中限制了pod的资源限制和资源需求,单pod内能看到的资源量还是其节点上的真正的资源量。这样就存在一个问题,有些程序默认运行时,所使用的CPU资源和memory资源是其自身所能看见的来设定的,而不是根据pod或容器上所设定requests和limits来设定的。这就会导致所运行的pod很快就崩溃。为了避免这个问题,需要使用downwardAPI来告诉容器有多少CPU和内存所使用,而不是其所看见的。

内存泄漏示例2

1.编写资源配置清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@k8s-master01:~/yaml/chapter04# vim resource-limits-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: memleak-pod
labels:
app: memleak
spec:
containers:
- name: simmemleak
image: ikubernetes/simmemleak
imagePullPolicy: IfNotPresent
resources:
memory: "64Mi"
cpu: "1"
limits:
memory: "64Mi"
cpu: "1"

2.应用配置清单

1
2
root@k8s-master01:~/yaml/chapter04# kubectl apply -f resource-limits-demo.yaml
pod/memleak-pod created

3.查看pod状态

1
2
3
4
5
6
7
root@k8s-master01:~/yaml/chapter04# kubectl get pods memleak-pod -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS G ATES
memleak-pod 0/1 OOMKilled 2 26s 10.244.2.25 k8s-node02 <none> <none>
memleak-pod 0/1 CrashLoopBackOff 2 40s 10.244.2.25 k8s-node02 <none> <none>
memleak-pod 0/1 OOMKilled 3 54s 10.244.2.25 k8s-node02 <none> <none>
memleak-pod 0/1 CrashLoopBackOff 3 66s 10.244.2.25 k8s-node02 <none> <none>
memleak-pod 0/1 OOMKilled 4 107s 10.244.2.25 k8s-node02 <none> <none>

k8s发现pod出现内存泄漏后,会发起OOMKilled。第一次出现pod将立即被重启,而后会根据回退算法来进程重启。分别间隔,0、10、20、40、80、160、300秒进程重启。至值CrashLoopBackOff状态。