k8s部分实践技巧

Pod生命周期

下图就是Pod的生命周期

1
2
Init container一定要在Main container之前执行,而且成功之后才会开始Main container。如果他失败pod也会失败,所以可根据此特性来做初始化的工作。
当要在main container加载一些配置数据时,在它启动之前可以用Init container来替它加载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Pod
metadata:
name:my-app
spec:
containers:
- name: my-app
image: my-app:latest
volumeMounts:
- name: config-data
mountPath: /data
initContainers:
- name: config-data
image: busvbox
command:["echo","-n","{'address':10.0.1.192:2379/db'}",">","/data/config"]
volumeMounts:
- name: config-data
mountPath: /data
volumes:
- name: config-data
hostPath: {}
1
2
2个container可以共享一个存储volume,通过init container把数据准备到这个共享空间的路径上,main container就可以在这个存储上加载数据。
这样一来main container就会与数据加载以及初始化的方式彻底解耦。
与PostStart对比
  • poststart是异步执行的
  • poststart过程不能保证在container的入口点前执行完成
  • container的状态在poststart过程完成后才会被置为running
1
2
3
4
5
6
7
8
9
如果在pod中包含多个container,当我们需要某个container先完成启动就绪,就绪完成后才继续下一个container的创建,那么就可以在前一个container中加一个postStart。
这个postStart过程只是检查自己是否就绪,如果一直没就绪退出后返回不正常时整个pod会失败,无法创建成功。
如果创建成功意味着已就绪,就可以继续启动下一个container。
而且这个方式可以在不同场景中,尤其是在sidecar的场景中,需要确保sidecar首先就绪。

终止也很重要。
当一个pod被终止,它会在服务发现里摘掉不接受流量,状态变成terminating。
这时它会收到一个信号SIGTERM,告诉它应该准备停止了。此时并不会把container马上杀掉,默认是30秒,在30秒之后会收到另一个信号SIGKILL,是强制立刻杀掉。
我们并不一定需要处理SIGTERM,而是可利用一个PreStop的hook来优雅处理。它可实现完美中断,避免数据丢失或服务发现未摘掉等情况。

健康检查

  • livenessProbe:存活性探针,判断容器是否存活健康,不满足健康条件那么kubelet将根据pod设置的restartpolicy来处理。
  • readinessProbe:就绪探针,判断容器内程序是否健康能正常对外提供服务。异常则通过enpoint列表剔除此pod。
  • startupProbe:启动探针,主要解决上面2种无法更好判断程序是否启动、存活。StartupProbe探针只是在容器启动后按照配置满足一次后,不在进行后续的探测。
1
2
3
4
5
6
7
8
9
10
11
12
13
startupProbe在Container启动时就开始工作,它确保该Container一定可以启动成功。
如果startupProbe的执行结果失败,那么它就会重启Container,直到Container启动成功。
如果startupProbe的执行结果成功,那么它认为Container启动成功,接下来才可以开始执行livenessProbe,或者是Container可以开始接收应用请求了
。这样就避免了Container还没启动完成,应用请求或者是livenessProbe的请求就发送过来,导致得不到预期的响应结果的情况发生。

如果三个探针同时存在,则先执行startupProbe探针,其他两个探针将会被暂时禁用,直到startupProbe一次探测成功,其他2个探针才启动;
如果startupProbe探测失败,kubelet 将杀死容器,并根据restartPolicy重启策略来判断容器是否要进行重启操作。

# startupProbe的实践建议
1. 对于那些启动时间比较长的Container,建议配置startupProbe;
2. startupProbe最好和livenessProbe、readiness同时配置;
3. startupProbe的类型和执行的命令,最好和livenessProbe保持一致;这样避免startupProbe执行成功,而livenessProbe失败导致Container重启,而很难去定位和分析问题;
4. startupProbe的periodSeconds*failureThreshold一定要大于Container启动的需要时长。否则,该时间段内,Container不能完成启动,将被重启,下一次又没能在该时长范围内完成启动,再次被重启,陷入死循环;
1
2
3
4
5
6
7
8
livenessProbe:
httpGet:
path: /test
prot: 80
failureThreshold: 1
initialDelay:10
periodSeconds: 10
# 容器启动10s后每10s检查一次,允许失败的次数是1次。如果失败次数超过1则会触发restartPolicy

QoS 和 Priority

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Priority  关于调度时
1. priority代表的是pod的重要性。
2. 高优先级的pod被调度时,如果出现资源不足,低优先级pod将会被驱逐以腾出资源完成调度。
3. 当preemptionPolicy设置为Never,则高优先级的pod不会抢占低优先级pod的资源,但在调度过程中会被放在优先位置。

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority-nonpreempting
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "not cause other pods to be preempted."

apiVersion: v1kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority

# 通常情况下不提倡对pod设定优先级,因为优先级越来越高就很容易失控。我们更期望的是与调度无关、与启动顺序无关的更好的架构。
1
2
3
4
当一个node上有很多pod在运行,可能会出现node硬件不够用的情况。哪些pod会杀死哪些会保留,这个才是QoS。
1. 当k8s集群内资源紧缺,优先杀死BestEffort类别的容器。因为系统不为该类资源提供任何服务保证,但此类资源最大好处就是能够尽可能的使用集群资源。
2. 接下来就轮到Burstable类别的容器,如果有多个Burstable类别的容器,就看谁的资源占用多就优先杀死谁。
3. 对于Guaranteed类别的容器拥有最高优先级,他们一般不会被杀死,除非内存需求超限,或OOM时没有其他更低优先级的Pod对象存储,才会干掉Guaranteed类容器。

Affinity 和 Taint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Affinity亲和性是从pod的视角去看怎样的node适合我来运行;Taint是从node的角度来看自己可以运行什么样的pod,兼容了node上的taint的pod才可以被调度到node上。

# Affinity
affinity:
podAntiAffinity:
requiredDuringSchedulingignoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: in
values:
- nginx
topologyKey: "kubernetes.io/hostname"

# Taint
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: lfNotPresent
tolerations:
- key: "spot"
operator: "Exists"
effect: "NoSchedule"
kubectl taint nodes spotnode1 spot=true:NoSchedule
-------------本文结束感谢您的阅读-------------
原创技术分享,感谢您的支持。