Kubernetes运维之容器编排高级Pod编写

为容器设置一个环境变量

创建 Pod 时,可以为其下的容器设置环境变量。通过配置文件的 env 或者 envFrom 字段来设置环境变量。

本示例中,将创建一个只包含单个容器的 Pod。Pod 的配置文件中设置环境变量的名称为 DEMO_GREETING, 其值为 "Hello from the environment"。下面是 Pod 的配置清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec: # 指定规格信息
containers: # 指定要启动一个什么样的容器
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
env: # 设置环境变量
- name: DEMO_GREETING
value: "Hello from the environment"
- name: DEMO_FAREWELL
value: "Such a sweet sorrow"

打印结果应为:

1
2
3
4
5
$ kubectl exec envar-demo -- printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=envar-demo
DEMO_FAREWELL=Such a sweet sorrow
DEMO_GREETING=Hello from the environment

在配置中使用环境变量

在 Pod 的配置中定义的环境变量可以在配置的其他地方使用, 例如可用在为 Pod 的容器设置的命令和参数中。 在下面的示例配置中,环境变量 GREETINGHONORIFICNAME 分别设置为 Warm greetings toThe Most HonorableKubernetes。然后这些环境变量在传递给容器 env-print-demo 的 CLI 参数中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
name: print-greeting
spec: # 指定规格信息
containers: # 指定要启动一个什么样的容器
- name: env-print-demo
image: bash # 使用的镜像
env:
- name: GREETING
value: "Warm greetings to"
- name: HONORIFIC
value: "The Most Honorable"
- name: NAME
value: "Kubernetes"
#command: ["echo"] # 直接覆盖容器默认命令,command是以数组。
#args: ["$(GREETING) $(HONORIFIC) $(NAME)"]
#也可以用这样方式
command:
- /bin/sh
- -c
- "echo $(GREETING) $(HONORIFIC) $(NAME)"

创建后,命令 echo Warm greetings to The Most Honorable Kubernetes 将在容器中运行。

1
2
$ kubectl logs print-greeting 
Warm greetings to The Most Honorable Kubernetes

Pod 的生命周期

我们一般将Pod对象从创建到终止的这段时间范围称为Pod的生命周期,它主要包含下面的过程:

  • Pod创建过程。
  • 运行初始化容器(init container)过程。
  • 生命周期钩子函数:
    • Poststart:于容器创建完成之后立即运行的钩子程序
    • preStop:容器终止之前立即运行的程序,是以同步方式的进行,因此其完成之前会阻塞 删除容器的调用。

容器探测

  • ExecAction:在容器中执行命令,根据返回的状态码判断容器健康状态,返回0即表示成功,否则为失败。

  • TCPSocketAction: 通过与容器的某TCP端口尝试建立连接进行诊断,端口能打开即为表示成功,否则失败。

  • HTTPGetAction:向容器指定 URL 发起 HTTP GET 请求,响应码为2xx或者是3xx为成功,否则失败。

  • Pod终止过程。

终止过程主要分为如下几个步骤:

  1. 用户发出删除 pod 命令
  2. Pod 对象随着时间的推移更新,在宽限期(默认情况下30秒),pod 被视为“dead”状态
  3. 将 pod 标记为“Terminating”状态
  4. 第三步同时运行,监控到 pod 对象为“Terminating”状态的同时启动 pod 关闭过程
  5. 第三步同时进行,endpoints 控制器监控到 pod 对象关闭,将pod与service匹配的 endpoints 列表中删除
  6. 如果 pod 中定义了 preStop 钩子处理程序,则 pod 被标记为“Terminating”状态时以同步的方式启动执行;若宽限期结束后,preStop 仍未执行结束,第二步会重新执行并额外获得一个2秒的小宽限期
  7. Pod 内对象的容器收到 TERM 信号
  8. 宽限期结束之后,若存在任何一个运行的进程,pod 会收到 SIGKILL 信号
  9. Kubelet 请求 API Server 将此 Pod 资源宽限期设置为0从而完成删除操作

查看帮助文档

1
2
3
$ kubectl explain pod.spec.containers.lifecycle
$ kubectl explain pod.spec.containers.lifecycle.postStart
$ kubectl explain pod.spec.containers.lifecycle.preStop
类型说明健康检查标准
ExecAction容器内部执行shell命令命令成功返回0
TCPSocketAction通过容器的IP、port执行TCP进行检查port端口是否打开
HTTPGetAciton通过容器的IP、port、path,用HTTP Get请求检查200<=返回值>400

生命周期钩子函数

官方文档:容器的生命周期事件设置处理函数 | Kubernetes

定义 postStart 和 preStop 处理函数

在本练习中,你将创建一个包含一个容器的 Pod,该容器为 postStart 和 preStop 事件提供对应的处理函数。

下面是对应 Pod 的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec: # 容器启动执行命令
# httpGet: # 容器启动访问http、https请求
# tcpSocket: # 容器启动访问tcp端口
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]

在上述配置文件中,你可以看到 postStart 命令在容器的 /usr/share 目录下写入文件 message。 命令 preStop 负责优雅地终止 nginx 服务。当因为失效而导致容器终止时,这一处理方式很有用。

存活、就绪和启动探测器

存活、就绪和启动探测器 | Kubernetes

容器三种探针(Probe)

  • 启动探针
    • kubelet 使用启动探测器可以知道应用程序容器什么时候启动了。 如果配置了这类探测器,就可以控制容器在启动成功后再进行存活性和就绪检查, 确保这些存活、就绪探测器不会影响应用程序的启动。 这可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。
  • 存活探测器
    • kubelet 使用存活探测器来知道什么时候要重启容器。 例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。 这样的情况下重启容器有助于让应用程序在有问题的情况下更可用。
  • 绪探测器
    • kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量, 当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。

Probe配置项

  • initialDelaySeconds【延迟探测时间(秒)】:表示容器启动初始化延迟的时间,也就是告诉监测从多久之后开始运行,单位是秒,默认是0秒;
  • periodSeconds【执行探测频率(秒)】:监测开始后,默认10秒执行一次 路径(健康检测页面) 监测,最小值是1。
  • timeoutSeconds【超时时间(秒)】: 表示探测到超时后等待多少秒,如果超过这个时长后,则认为监测失败(若监测路径1秒后没有返回,则认为超时)
  • failureThreshold【不健康伐值】:当Pod成功启动且检查失败且连续达到设定次数时,放弃生存检查意味着重新启动Pod。(放弃就绪检查,Pod将被标记为未就绪。 默认为3.最小值为1)
  • successThreshold【健康伐值】:探测器失败后检查成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。即监测路径健康后完成本次检查。

详情配置查看:

1
2
3
kubectl explain pod.spec.containers.livenessProbe
kubectl explain pod.spec.containers.startupProbe
kubectl explain pod.spec.containers.readinessProbe

存活探测器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: harbor.od.com/public/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe: # 存活探针
exec: #
command: ["cat", "/tmp/healthy"] # 返回不是0,那就是探测失败。
initialDelaySeconds: 5 # 指定多少秒以后执行探测
periodSeconds: 5 # 每个几秒运行一次
timeoutSeconds: 5 # 探测5秒没有返回结果,说明失败,执行下一次探测
successThreshold: 1 # 成功阈值,连续几次成功才算成功。
failureThreshold: 3 # 失败阈值,连续几次失败才算真失败。

污点和容忍度调度

在Kubernetes中通过给一个Node设置污点,以及Pod对于这个污点的容忍度结合起来实现哪些Pod可以被调度到哪些节点上,只有当一个Pod可以容忍某个节点的污点,这个Pod才会可能被调度该节点上。

请注意污点是在Node上设置的,而容忍度是在Pod上设置的。

Taints(污点)

您可以使用命令 kubectl taint 给节点增加一个污点。比如,

1
kubectl taint nodes node1 key1=value1:NoSchedule

给节点 node1 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 node1 这个节点。

若要移除上述命令所添加的污点,你可以执行:

1
kubectl taint nodes node1 key1=value1:NoSchedule-

Taints的表现形式为

1
<key>=<value>:<effect>
  • key: 就是污点的key
  • value:污点的值,如上面是一个空的value,所以没有显示=
  • effect:设置当有这个污点是产生的效果。

effect的三种类型:

  • NoSchedule: 如果Pod没有容忍该污点,不调度到该节点上。
  • PreferNoSchedule:尽量阻止Pod被调度到这个节点上,但是如果没有其它节点能够调度,可以调度到该节点。
  • NoExecute: NoScheduler和PreferNoSchedule只是在调度阶段起作用,但是NoExecute会影响正常运行的Pod,如果一个节点被打了NoExecute的污点,而运行在该节点的Pod没有容忍会直接被这个节点移除。

实例

自定义污点容忍

  1. 创建一个Nginx的Deployment并设置污点容忍度

    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
    32
    33
    34
    35
    36
    # kubectl taint node k8s-master1 node-type=budiandu:NoSchedule
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: nginx-deployment
    labels:
    app: nginx
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: nginx
    template:
    metadata:
    labels:
    app: nginx
    spec:
    containers:
    - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    tolerations:
    - key: node-type
    operator: Equal
    value: budiandu
    effect: NoSchedule

    # 查看调度
    [root@k8s-master1 ~]# kubectl apply -f nginx.yml
    deployment.apps/nginx-deployment created
    [root@k8s-master1 ~]# kubectl get pod -o wide
    NAME READY STATUS RESTARTS AGE
    nginx-deployment-dc75ffbf4-6r9pf 1/1 Running 0 3m55s
    nginx-deployment-dc75ffbf4-brxmp 1/1 Running 0 3m55s
    nginx-deployment-dc75ffbf4-k4mkb 1/1 Running 0 3m55s

    operator支持两个选项Equal和Exists,Equal用与匹配对应的value也是默认的操作符,Exists用来匹配污点的Key

​ 删除节点的污点

1
[root@linux-node1 ~]# kubectl taint node k8s-master1 node-type-