一、深入Pod
k8s 的资源清单.md
1.创建Pod -配置文件详解
1.1基本配置
创建pod-base.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: nginx-demo labels: type: app version: 1.0.0 namespace: dev spec: containers: - name: nginx image: nginx:1.7.9 imagePullPolicy: IfNotPresent command: - nginx - -g - 'daemon off;' workingDir: /usr/share/nginx/html ports: - name: http containerPort: 80 hostPort: 80 protocol: TCP env: - name: JVM_OPTS value: 'Xms128m -Xmx128m' resources: requests: cpu: 100m memory: 128Mi limits: cpu: 200m memory: 256Mi restartPolicy: OnFailure
apiVersion: v1 #必选,文档版本号,例如v1 kind: Pod #必选,资源对象类型,例如 Pod,也可以配置为Deployment metadata: #必选,Pod相关的元数据,用来描述Pod的数据 name: nginx-demo #必选,Pod名称 labels: #定义Pod的标签 type: app #自定义lable标签,名字为type 值为app version: 1.0.0 #自定义label标签 描述Pod版本号 namespace: dev #Pod所属的命名空间,默认为"default" spec: #必选,期望Pod按照这个里面的描述进行创建 containers: #必选,Pod中容器列表 对于Pod中的容器描述 - name: nginx #必选,容器名称 image: nginx:1.7.9 #必选,容器的镜像名称 imagePullPolicy: IfNotPresent #获取镜像的策略 指定如果本地有就用本地的,如果没有就拉取远程的 command: #容器的启动命令列表,如不指定,使用打包时使用的启动命令 - nginx - -g - 'daemon off;' #nginx -g 'daemon off' workingDir: /usr/share/nginx/html #容器的工作目录 ports: #需要暴露的端口库号列表 - name: http #端口的名称 containerPort: 80 #容器需要监听的端口号 hostPort: int #容器所在主机需要监听的端口号,默认与Container相同 protocol: TCP #端口协议,支持TCP和UDP,默认TCP env: #容器运行前需设置的环境变量列表 name: JVM_OPTS #环境变量名称 value: 'Xms128m -Xmx128m' #环境变量的值 resources: #资源限制和请求的设置 requests: #最少需要多少资源 cpu: 100m #限制cpu最少使用0.1个核心 memory: 128Mi #限制内存最少使用128兆 limits: #最多需要多少资源 cpu: 200m # memory: 256Mi # restartPolicy: OnFailure #重启策略,只有失败的情况才会重启
# 把上面的内容放进去 [root@k8s-master pods] vi nginx.demo.yaml # 创建Pod [root@k8s-master pods]# kubectl apply -f nginx-demo.yaml pod/nginx-demo created # 查看Pod状况 # READY 0/1 : 表示当前Pod中有1个容器,未准备就绪 # STATUS ContainerCreating 容器创建中 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 0/1 ContainerCreating 0 36s #CrashLoopBackOff 表示你的 Pod 在启动后立即崩溃, #并且 Kubernetes 正在尝试重新启动它,但是这一过程一直在循环中。 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 0/1 CrashLoopBackOff 1 (9s ago) 10s #查看 Pod 的日志 [root@k8s-master pods]# kubectl logs nginx-demo -n dev 2024/01/02 09:18:06 [emerg] 1#0: unexpected end of parameter, expecting ";" in command line nginx: [emerg] unexpected end of parameter, expecting ";" in command line #根据日志的内容,问题似乎是在 Nginx 启动命令行参数中。 #日志指出出现了一个紧急错误,即“unexpected end of parameter, #expecting ';' in command line”(预期参数结束,期望在命令行中找到 ';')。 #尝试更新你的 YAML 文件中的 Nginx 启动命令,使用正常的 Nginx 启动方式: #command: # - nginx # - -g # - 'daemon off;' #发现少了;导致了报错 #修改配置文件 [root@k8s-master pods]# vi nginx-demo.yaml #创建Pod [root@k8s-master pods]# kubectl apply -f nginx-demo.yaml -n dev The Pod "nginx-demo" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative) core.PodSpec{ Volumes: {{Name: "kube-api-access-gbfg2", VolumeSource: {Projected: &{Sources: {{ServiceAccountToken: &{ExpirationSeconds: 3607, Path: "token"}}, {ConfigMap: &{LocalObjectReference: {Name: "kube-root-ca.crt"}, Items: {{Key: "ca.crt", Path: "ca.crt"}}}}, {DownwardAPI: &{Items: {{Path: "namespace", FieldRef: &{APIVersion: "v1", FieldPath: "metadata.namespace"}}}}}}, DefaultMode: &420}}}}, InitContainers: nil, Containers: []core.Container{ { Name: "nginx", Image: "nginx:1.7.9", Command: []string{ "nginx", "-g", - "daemon off;", + "daemon off", }, Args: nil, WorkingDir: "/usr/share/nginx/html", ... // 17 identical fields }, }, EphemeralContainers: nil, RestartPolicy: "OnFailure", ... // 26 identical fields } #错误提示表明在 Kubernetes 中,你不能直接修改 Pod 中的某些字段, #除非是 spec.containers[*].image、spec.initContainers[*].image、 #spec.activeDeadlineSeconds、spec.tolerations #或 spec.terminationGracePeriodSeconds 这些字段。在你的更新中, #尝试修改了 spec.containers[*].command 字段,这是不允许的。 #为了解决这个问题,需要创建一个新的 Pod 资源而不是直接更新现有的 Pod。 #删除现有的 Pod: [root@k8s-master pods]# kubectl delete pod nginx-demo -n dev pod "nginx-demo" deleted #创建一个新的 Pod: [root@k8s-master pods]# kubectl apply -f nginx-demo.yaml -n dev pod/nginx-demo created # 查看Pod状况 # READY 1/1 : 表示当前Pod中有1个容器,准备就绪 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 1/1 Running 0 15s # 可以通过describe查看内部的详情 [root@k8s-master pods]# kubectl describe pod nginx-demo -n dev
查看Pod内部的详情中的事件
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 19m default-scheduler Successfully assigned dev/nginx-demo to k8s-node1 Normal Pulled 19m kubelet Container image "nginx:1.7.9" already present on machine Normal Created 19m kubelet Created container nginx Normal Started 19m kubelet Started container nginx
- assigned dev/nginx-demo to k8s-node1 Pod 成功被调度到节点 k8s-node1 上。这表示 Kubernetes 调度器成功地选择了一个节点来运行你的 Pod
- Container image “nginx:1.7.9” already present on machine 节点上已经有了所需的 Nginx 镜像,因此无需从远程仓库再次拉取
- 因此无需从远程仓库再次拉取
- Created container nginx 容器 “nginx” 已经被成功创建
- Started container nginx 容器 “nginx” 已经成功启动
# 查看pod详细信息 [root@k8s-master pods]# kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-pod 1/1 Running 0 5d18h 10.244.1.6 k8s-node1 <none> <none>
#从集群内部访问了 Pod 的 IP 地址。这个 IP 地址是由 Kubernetes 分配的集群内部地址 [root@k8s-master pods]# curl 10.244.1.6 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
#路由表显示主机上的 IP 路由信息 [root@k8s-master pods]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.235.2 0.0.0.0 UG 100 0 0 ens33 10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0 10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 192.168.235.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33
1.2探针技术详解
容器内应用的监测机制,根据不同的探针来判断容器应用当前的状态
容器运行成功后会创建一个探针,会一直监控容器,一但发现容器挂掉了,会检查配置文件中是否有对应重启策略,按照要求的重启策略进行重启,或者是否需要重启。 restartPolicy: OnFailure # 重启策略 来重新启动
没有这个配置的话,容器挂掉了就是挂掉了
1.2.1探针类型
- 生命周期探针(Liveness Probe)
生命周期探针用于确定容器是否处于运行中 。如果生命周期探针失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。.
配置示例:
livenessProbe: failureThreshold: 5 #失败多少次算失败 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 # 初始化时间 periodSeconds: 10 # 间隔时间 successThreshold: 1 # 多少此检测成功算成功 timeoutSeconds: 5 # 请求超时时间
- failureThreshold: 允许的连续失败次数,达到此次数后容器将被认为是不健康,将被杀死并根据重启策略进行处理。
- httpGet: 指定 HTTP GET 请求的相关配置。
- path: 探针将发送 HTTP GET 请求到容器中的路径。
- port: 探针将使用的端口号。
- scheme: HTTP 或 HTTPS,指定请求的协议。
- initialDelaySeconds: 容器启动后多久开始进行探针检测。
- periodSeconds: 探针检测的间隔时间,即每隔多久进行一次健康检查。
- successThreshold: 允许的连续成功次数,达到此次数后容器将被认为是健康。
- timeoutSeconds: 探针请求的超时时间,如果在此时间内没有响应,将被视为失败。
总的来说,上述配置表示容器的 Liveness Probe 将会:
- 在容器启动后等待 60 秒开始进行探针检测。
- 每隔 10 秒发送一个 HTTP GET 请求到 /health 路径,使用 HTTP 协议,端口为 8080。
- 如果连续 5 次检测失败(即容器返回非 2xx 的 HTTP 状态码),则认为容器不健康。
- 如果连续 1 次检测成功,则认为容器恢复到健康状态。
就绪性探针(Readiness Probe)
用于探测容器内的程序是否健康 ,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure
配置示例:
readinessProbe: failureThreshold: 3 # 错误次数 httpGet: path: /ready port: 8181 scheme: HTTP periodSeconds: 10 # 间隔时间 successThreshold: 1 timeoutSeconds: 1
- StartupProbe
k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
配置示例:
startupProbe: httpGet: path: /api/startup port: 80
1.2.2探测方式
- exec 方式
exec 方式通过执行容器内的命令检查容器的健康状态,如果返回值为 0,则任务容器时健康的。
livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 3 periodSeconds: 5
Liveness Probe 将每 5 秒执行一次 cat /tmp/healthy 命令,如果命令成功执行(返回码为 0),则认为容器是健康的
- tcpSocket 方式
通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 3 periodSeconds: 5
Liveness Probe 将每 5 秒尝试在容器的 8080 端口上建立一个 TCP 连接,如果连接成功,则认为容器是健康的
- httpGet 方式
httpGet 方式通过发送 HTTP GET 请求检查容器的健康状态。
允许针对 httpGet 配置额外的字段:
- host:连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。
- scheme:用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 “HTTP”。
- path:访问 HTTP 服务的路径。默认值为 “/”。
- httpHeaders:请求中自定义的 HTTP 头。HTTP 头字段允许重复。
- port:访问容器的端口号或者端口名。如果数字必须在 1~65535 之间。
livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 3 periodSeconds: 5
periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务在监听 8080 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz 路径下的处理程序返回成功代码
针对 HTTP 探针,kubelet 除了必需的 Host 头部之外还发送两个请求头部字段:
- User-Agent:默认值是 kube-probe/1.29,其中 1.29 是 kubelet 的版本号。
- Accept:默认值 /。
你可以通过为探测设置 httpHeaders 来重载默认的头部字段值。例如:
livenessProbe: httpGet: httpHeaders: - name: Accept value: application/json startupProbe: httpGet: httpHeaders: - name: User-Agent value: MyUserAgent
1.2.3StartupProbe探针的使用
httpGet方式:
[root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 1/1 Running 0 5d19h #删除现有的 Pod: [root@k8s-master pods]# kubectl delete pod nginx-demo -n dev pod "nginx-demo" deleted #修改配置文件 [root@k8s-master pods]# vi nginx-demo.yaml # 在command 上面加入以下内容 startupProbe: #应用启动探针配置 httpGet: # 探测方式,基于http请求探测 path: /api/startup # http请求路径 这个是不存在的path请求不到 port: 80 #请求端口 failureThreshold: 3 # 失败多少次算失败 periodSeconds: 10 # 间隔时间 successThreshold: 1 # 多少此检测成功算成功 timeoutSeconds: 5 # 请求超时时间
#创建一个新的 Pod: [root@k8s-master pods]# kubectl apply -f nginx-demo.yaml -n dev pod/nginx-demo created [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 0/1 Running 1 (11s ago) 42s [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 0/1 Running 1 (16s ago) 47s [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-demo 0/1 Running 1 (29s ago) 60s # 可以通过describe查看内部的详情 [root@k8s-master pods]# kubectl describe pod nginx-demo -n dev Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 109s default-scheduler Successfully assigned dev/nginx-demo to k8s-node1 Normal Pulled 18s (x4 over 108s) kubelet Container image "nginx:1.7.9" already present on machine Normal Created 18s (x4 over 108s) kubelet Created container nginx Normal Started 18s (x4 over 108s) kubelet Started container nginx Normal Killing 18s (x3 over 78s) kubelet Container nginx failed startup probe, will be restarted Warning Unhealthy 8s (x10 over 98s) kubelet Startup probe failed: HTTP probe failed with statuscode: 404
Startup probe failed: HTTP probe failed with statuscode: 404:
Kubernetes 的启动探测(Startup Probe)中,HTTP 探测失败,返回了状态码 404
[root@k8s-master pods]# mv nginx-demo.yaml nginx-po.yaml [root@k8s-master pods]# ls nginx-po.yaml #删除现有的 Pod: [root@k8s-master pods]# kubectl delete pod nginx-demo -n dev pod "nginx-demo" deleted #修改配置文件 [root@k8s-master pods]# vi nginx-po.yaml # 修改配置 metadata: name: nginx-po path: /index.html #http请求路径 这个是存在的路径
#创建一个新的 Pod [root@k8s-master pods]# kubectl apply -f nginx-po.yaml -n dev pod/nginx-po created #通过describe查看内部的详情 [root@k8s-master pods]# kubectl describe pod nginx-po -n dev
打印内部详情: 没有错误信息 打印了对应Startup对应配置信息 探针方式为http-get
# 查看Pod状况 # READY 1/1 : 表示当前Pod中有1个容器,准备就绪 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 1/1 Running 0 4m11s
tcpScocket方式: 端口连接成功就算成功的访问
** **把之前httpGet方式的探针注释,改为tcpSocket方式。
startupProbe: #应用启动探针配置 tcpSocket: port: 80 # 请求端口
按照原来的步骤再来一遍
打印内部详情: 没有错误信息 打印了对应Startup对应配置信息 探针方式为tcp-socket
**exec方式: **
command: - sh - -c - "echo success >/inited;"
在 /inited 文件中写入 “success” 字符串
打印内部详情: 没有错误信息 打印了对应Startup对应配置信息 探针方式为exec 由之前的额发请求变成了命令的方式执行
# 查看Pod状况 # READY 1/1 : 表示当前Pod中有1个容器,准备就绪 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 1/1 Running 0 69s #在名为 "nginx-po" 的 Pod 中的 "nginx" 容器内执行 cat /inited 命令,查看 "/inited" 文件的内容 [root@k8s-master pods]# kubectl exec -it nginx-po -n dev -c nginx -- cat /inited success #出现了success 操作成功
1.2.4LivenessProbe探针的使用
# 复制nginx-po.yaml文件内容 [root@k8s-master pods]# cp nginx-po.yaml nginx-livexess-po.yaml cp:是否覆盖"nginx-livexess-po.yaml"? Y [root@k8s-master pods]# ls nginx-livexess-po.yaml nginx-po.yaml #修改配置文件 [root@k8s-master pods]# vi nginx-livexess-po.yaml startupProbe: #应用启动探针配置 #tcpSocket: # port: 80 # 请求端口 exec: command: - sh - -c - "sllep 3;echo success >/inited;" failureThreshold: 3 # 失败多少次算失败 periodSeconds: 10 # 间隔时间 successThreshold: 1 # 多少此检测成功算成功 timeoutSeconds: 5 # 请求超时时间 livenessProbe: #应用存活探针配置 httpGet: # 探测方式,基于http请求探测 path: /started.html # http请求路径 这个是不存在的path请求不到 port: 80 #请求端口 failureThreshold: 3 # 失败多少次算失败 periodSeconds: 10 # 间隔时间 successThreshold: 1 # 多少此检测成功算成功 timeoutSeconds: 5 # 请求超时时间
#RESTARTS 重启3次 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 0/1 Running 3 (12s ago) 2m12s #Completed重启5次终止状态 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 0/1 Completed 5 5m56s [root@k8s-master pods]# kubectl cp started.html dev/nginx-po:/usr/share/nginx/html/ #文件存在后启动成功 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 1/1 Running 1 (2m ago) 2m40s
使用启动探针保护慢启动容器
有时候,会有一些现有的应用在启动时需要较长的初始化时间。 要这种情况下,若要不影响对死锁作出快速响应的探测,设置存活探测参数是要技巧的。 技巧就是使用相同的命令来设置启动探测,针对 HTTP 或 TCP 检测,可以通过将 failureThreshold * periodSeconds 参数设置为足够长的时间来应对最糟糕情况下的启动时间
这样,前面的例子就变成了:
ports: - name: liveness-port containerPort: 8080 hostPort: 8080 livenessProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 1 periodSeconds: 10 startupProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 30 periodSeconds: 10
幸亏有启动探测,应用将会有最多 5 分钟(30 * 10 = 300s)的时间来完成其启动过程。 一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁作出快速响应。 如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来执行进一步处置。
1.2.5ReadinessProbe 就绪探针的使用
有时候,应用会暂时性地无法为请求提供服务。 例如,应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。 在这种情况下,既不想杀死应用,也不想给它发送请求。 Kubernetes 提供了就绪探针来发现并缓解这些情况。 容器所在 Pod 上报还未就绪的信息,并且不接受通过 Kubernetes Service 的流量。
说明:
就绪探针在容器的整个生命周期中保持运行状态。
注意:
- 存活探针与就绪性探针相互间不等待对方成功。 如果要在执行就绪性探针之前等待,应该使用 initialDelaySeconds 或 startupProbe。
- 就绪探针的配置和存活探针的配置相似。 唯一区别就是要使用 readinessProbe 字段,而不是 livenessProbe 字段。HTTP 和 TCP 的就绪探针配置也和存活探针的配置完全相同。
- 就绪和存活探测可以在同一个容器上并行使用。 两者共同使用,可以确保流量不会发给还未就绪的容器,当这些探测失败时容器会被重新启动
# 复制nginx-livexess-po.yaml文件内容 [root@k8s-master pods]# cp nginx-livexess-po.yaml nginx-rediness-po.yaml [root@k8s-master pods]# vi nginx-rediness-po.yaml readinessProbe: #应用就绪探针配置 httpGet: # 探测方式,基于http请求探测 path: /started.html # http请求路径 这个是不存在的path请求不到 port: 80 #请求端口 failureThreshold: 5 # 失败多少次算失败 periodSeconds: 10 # 间隔时间 successThreshold: 1 # 多少此检测成功算成功 timeoutSeconds: 5 # 请求超时时间
# 禁止外部网络访问 不会重启 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 0/1 Running 0 21s #把这个文件放进pod中 [root@k8s-master pods]# kubectl cp started.html nginx-po:/usr/share/nginx/html/ -n dev # 再次查看pod就为就绪状态了 [root@k8s-master pods]# kubectl get pod -n dev NAME READY STATUS RESTARTS AGE nginx-po 1/1 Running 0 2m39s
1.3 Pod生命周期
1.3.1 Pod生命周期图解
1.3.2 容器状态
要检查 Pod 中容器的状态,你可以使用 kubectl describe pod <pod 名称>。 其输出中包含 Pod 中每个容器的状态。
每种状态都有特定的含义:
Waiting (等待)
如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
Running(运行中)
Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息。
Terminated(已终止)
处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。
如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行。
1.3.3postStart 和 preStop 钩子函数
钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:
- post start:容器创建之后执行,但在容器中的应用程序开始运行之前,如果失败了会重启容器.
postStart 处理函数与容器的代码是异步执行的,但 Kubernetes 的容器管理逻辑会一直阻塞等待 postStart 处理函数执行完毕。 只有 postStart 处理函数执行完毕,容器的状态才会变成 RUNNING
- pre stop :容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
除非 Pod 宽限期限超时, Kubernetes 的容器管理逻辑会一直阻塞等待 preStop 处理函数执行完毕
钩子处理器支持使用下面三种方式定义动作:
Exec命令:在容器内执行一次命令
…… lifecycle: postStart: exec: command: - cat - /tmp/healthy ……
TCPSocket:在当前容器尝试访问指定的socket
…… lifecycle: postStart: tcpSocket: port: 8080 ……
HTTPGet:在当前容器中向某url发起http请求
…… lifecycle: postStart: httpGet: path: / #URI地址 port: 80 #端口号 host: 192.168.5.3 #主机地址 scheme: HTTP #支持的协议,http或者https ……
1.3.4 Pod 退出流程>删除操作
- 用户或控制器发起删除操作: 删除操作可以由用户通过 kubectl delete pod 命令发起,或者由控制器(如 Deployment、StatefulSet、DaemonSet 等)进行删除操作。
- Terminating 阶段开始: Pod 进入 Terminating 阶段,此时将开始执行删除流程。
- PreStop 钩子执行: 如果容器定义了 preStop 生命周期钩子,将执行这个钩子中定义的操作。这是在容器终止之前执行的清理操作。
- SIGTERM 信号发送: Kubernetes 向容器发送 SIGTERM 信号,通知容器开始优雅终止。优雅终止的期限由 terminationGracePeriodSeconds 字段定义,默认是 30 秒。
- 优雅终止: 在 SIGTERM 信号发送后,容器有一个优雅终止期限,在这个期限内,容器有机会完成正在进行的工作、关闭连接等。
- Terminating 阶段完成: 如果在优雅终止期限内容器成功终止,Pod 将进入 Terminated 阶段,然后被删除。如果容器无法在优雅终止期限内完成,将进入下一步。
- SIGKILL 信号发送: 如果容器在优雅终止期限内未能正常终止,Kubernetes 将发送 SIGKILL 信号,强制终止容器。
- Pod 删除: Pod 进入 Terminated 阶段,然后被删除。删除操作将从 API Server 和集群中移除该 Pod 的配置和状态信息。
1.3.5 PreStop事件的应用
使用 preStop 生命周期钩子时,可以在应用即将终止之前执行一些清理操作。在您的场景中,可以通过 preStop 钩子来实现注册中心下线、数据清理和数据销毁等操作。
如果应用销毁操作耗时需要比较长,可以在 preStop 按照如下方式进行配置
preStop: exec: command: - sh - -c - 'sleep 20; kill pgrep java'
但是需要注意,由于 k8s 默认给 pod 的停止宽限时间为 30s,如果我们停止操作会超过 30s 时,不要光设置 sleep 50,还要将 terminationGracePeriodSeconds: 30 也更新成更长的时间,否则 k8s 最多只会在这个时间的基础上再宽限几秒,不会真正等待 50s
以下是一个示例 Pod 配置,其中包含一个具有 preStop 钩子的容器:
apiVersion: v1 kind: Pod metadata: name: my-app-pod spec: terminationGracePeriodSeconds: 90 # 设置终止期限为 90 秒 containers: - name: my-app-container image: my-app-image:latest lifecycle: preStop: exec: command: ["/bin/sh", "-c", "cleanup-script.sh"]
在这个示例中,cleanup-script.sh 是一个您定义的脚本,其中包含执行清理操作的逻辑。您可以在这个脚本中实现注册中心下线、数据清理和数据销毁等操作。
1.3.6 完整示例
apiVersion: v1 kind: Pod metadata: name: pod-hook-exec namespace: dev spec: terminationGracePeriodSeconds: 45 containers: - name: main-container image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo 'postStart... creating file' > /usr/share/nginx/html/index.html"] preStop: exec: command: ["/bin/sh", "-c", "echo 'preStop... creating file' > /pods/termination-file.html"]
# 创建pod [root@k8s-master pods]# kubectl apply -f pod-lifecycle-demo.yaml pod/lifecycle-graceful-pod created # 查看pod列表 [root@k8s-master pods]# kubectl get pods -n dev NAME READY STATUS RESTARTS AGE pod-hook-exec 1/1 Running 0 68s #查看pod [root@k8s-master pods]# kubectl get pods pod-hook-exec -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-hook-exec 1/1 Running 0 104s 10.244.1.27 k8s-node1 <none> <none> # 访问pod [root@k8s-master pods]# curl 10.244.1.27 postStart... creating file
postStart… creating file 这个是postStart钩子函数执行的内容.
1.3.7强制删除
强制删除不会等待来自 kubelet 对 Pod 已终止的确认消息。 无论强制删除是否成功杀死了 Pod,它都会立即从 API 服务器中释放该名字。
如果要使用 kubectl 1.5 以上版本强制删除 Pod,请执行下面命令:
kubectl delete pods <pod> --grace-period=0 --force
如果你使用 kubectl 的 1.4 以下版本,则应省略 --force 选项:
kubectl delete pods <pod> --grace-period=0
如果在执行这些命令后 Pod 仍处于 Unknown 状态,请使用以下命令从集群中删除 Pod:
kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
请始终谨慎地执行强制删除 StatefulSet 类型的 Pod,并充分了解强制删除操作所涉及的风险