Kubernetes权威指南——深入掌握Pod(容器内获取Pod信息、Pod声明周期和重启策略、Pod健康检查和服务可用性检查) 深入掌握Pod6、在容器内获取Pod信息Downward API6.1、环境变量方式将Pod信息注入为环境变量6.2、环境变量方式将容器资源信息注入为环境变量6.3、Volume挂载方式7、Pod生命周期和重启策略8、Pod健康检查和服务可用性检查6、在容器内获取Pod信息Downward API我们知道每个Pod在被成功创建出来之后都会被系统分配唯一的名字、IP地址并且处于某个Namespace中那么我们如何在Pod的容器内获取Pod的这些重要信息呢答案就是使用Downward API。Downward API可以通过以下两种方式将Pod信息注入容器内部。环境变量用于单个变量可以将Pod信息和Container信息注入容器内部。Volume挂载将数组类信息生成为文件并挂载到容器内部。下面通过几个例子对Downward API的用法进行说明。6.1、环境变量方式将Pod信息注入为环境变量下面的例子通过Downward API将Pod的IP、名称和所在Namespace注入容器的环境变量中容器应用使用env命令将全部环境变量打印到标准输出中# dapi-test-pod.yamlapiVersion:v1kind:Podmetadata:name:dapi-test-podspec:containers:-name:test-containerimage:busyboxcommand:[/bin/sh,-c,env]env:-name:MY_POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:MY_POD_NAMESPACEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:MY_POD_IPvalueFrom:fieldRef:fieldPath:status.podIPrestartPolicy:Never注意到上面valueFrom这种特殊的语法是Downward API的写法。目前Downward API提供了以下变量。metadata.namePod的名称当Pod通过RC生成时其名称是RC随机产生的唯一名称。status.podIPPod的IP地址之所以叫作status.podIP而非metadata.IP是因为Pod的IP属于状态数据而非元数据。metadata.namespacePod所在的Namespace。运行kubectl create命令创建Pod# kubectl create -f dapi-test-pod.yamlpoddapi-test-podcreated查看dapi-test-pod的日志# kubectl logs dapi-test-pod......MY_POD_NAMESPACEdefaultMY_POD_IP172.17.1.2MY_POD_NAMEdapi-test-pod......从日志中我们可以看到Pod的IP、Name及Namespace等信息都被正确保存到了Pod的环境变量中。6.2、环境变量方式将容器资源信息注入为环境变量下面的例子通过Downward API将Container的资源请求和限制信息注入容器的环境变量中容器应用使用printenv命令将设置的资源请求和资源限制环境变量打印到标准输出中dapi-test-pod-container-vars.yamlapiVersion:v1kind:Podmetadata:name:dapi-test-pod-container-varsspec:containers:-name:test-containerimage:busyboximagePullPolicy:Nevercommand:[sh,-c]args:-while true; do echo-en \n; printenv MY_CPU_REQUEST MY_CPU_LIMIT; printenv MY_MEM_REQUEST MY_MEM_LIMIT; sleep 3600; done;resources:requests:memory:32Micpu:125mlimits:memory:64Micpu:250menv:-name:MY_CPU_REQUESTvalueFrom:resourceFieldRef:containerName:test-containerresource:requests.cpu-name:MY_CPU_LIMITvalueFrom:resourceFieldRef:containerName:test-containerresource:limits.cpu-name:MY_MEM_REQUESTvalueFrom:resourceFieldRef:containerName:test-containerresource:requests.memory-name:MY_MEM_LIMITvalueFrom:resourceFieldRef:containerName:test-containerresource:limits.memoryrestartPolicy:Never注意valueFrom这种特殊的Downward API语法目前resourceFieldRef可以将容器的资源请求和资源限制等配置设置为容器内部的环境变量。requests.cpu容器的CPU请求值。limits.cpu容器的CPU限制值。requests.memory容器的内存请求值。limits.memory容器的内存限制值。运行kubectl create命令来创建Pod# kubectl create -f dapi-test-pod-container-vars.yamlpoddapi-test-pod-container-varscreated# kubectl get podsNAME READY STATUS RESTARTS AGE dapi-test-pod-container-vars1/1 Running036s查看dapi-test-pod-container-vars的日志# kubectl logs dapi-test-pod-container-vars113355443267108864从日志中我们可以看到Container的requests.cpu 、limits.cpu 、 requests.memory 、limits.memory等信息都被正确保存到了Pod的环境变量中。6.3、Volume挂载方式下面的例子通过Downward API将Pod的Label、Annotation列表通过Volume挂载为容器中的一个文件容器应用使用echo命令将文件的内容打印到标准输出中# dapi-test-pod-volume.yamlapiVersion:v1kind:Podmetadata:name:dapi-test-pod-volumelabels:zone:us-est-coastcluster:test-cluster1rack:rack-22annotations:build:twobuilder:john-doespec:containers:-name:test-containerimage:busyboximagePullPolicy:Nevercommand:[sh,-c]args:-while true; do if[[-e /etc/labels]]; then echo-en \n\n; cat /etc/labels; fi; if[[-e /etc/annotations]]; then echo-en \n\n; cat /etc/annotations; fi; sleep 3600; done;volumeMounts:-name:podinfomountPath:/etcreadOnly:falsevolumes:-name:podinfodownwardAPI:items:-path:labelsfieldRef:fieldPath:metadata.labels-path:annotationsfieldRef:fieldPath:metadata.annotations这里要注意“volumes”字段中downwardAPI的特殊语法通过items的设置系统会根据path的名称生成文件。根据上例的设置系统将在容器内生成/etc/labels和/etc/annotations两个文件。在/etc/labels文件中将包含metadata.labels的全部Label列表在/etc/annotations文件中将包含metadata.annotations的全部Label列表。运行kubectl create命令创建Pod# kubectl create -f dapi-test-pod-volume.yamlpoddapi-test-pod-volumecreated# kubectl get podsNAME READY STATUS RESTARTS AGE dapi-test-pod-volume1/1 Running01m查看dapi-test-pod-volume的日志# k logs dapi-test-pod-volumeclustertest-cluster1rackrack-22zoneus-est-coastbuildtwobuilderjohn-doe从日志中我们看到Pod的Label和Annotation信息都被保存到了容器内的/etc/labels和/etc/annotations文件中。那么Downward API有什么价值呢在某些集群中集群中的每个节点都需要将自身的标识ID及进程绑定的IP地址等信息事先写入配置文件中进程在启动时会读取这些信息然后将这些信息发布到某个类似服务注册中心的地方以实现集群节点的自动发现功能。此时Downward API就可以派上用场了具体做法是先编写一个预启动脚本或Init Container通过环境变量或文件方式获取Pod自身的名称、IP地址等信息然后将这些信息写入主程序的配置文件中最后启动主程序。7、Pod生命周期和重启策略Pod在整个生命周期中被系统定义为各种状态熟悉Pod的各种状态对于理解如何设置Pod的调度策略、重启策略是很有必要的。Pod的状态如表所示。Pod的重启策略RestartPolicy应用于Pod内的所有容器并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查详见下节失败时kubelet将根据RestartPolicy的设置来进行相应的操作。Pod的重启策略包括Always、OnFailure和Never默认值为Always。Always当容器失效时由kubelet自动重启该容器。OnFailure当容器终止运行且退出码不为0时由kubelet自动重启该容器。Never不论容器运行状态如何kubelet都不会重启该容器。kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算例如1、2、4、8倍等最长延时5min并且在成功重启后的10min后重置该时间。Pod的重启策略与控制方式息息相关当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理静态Pod​。每种控制器对Pod的重启策略要求如下。RC和DaemonSet必须设置为Always需要保证该容器持续运行。JobOnFailure或Never确保容器执行完成后不再重启。kubelet在Pod失效时自动重启它不论将RestartPolicy设置为什么值也不会对Pod进行健康检查。结合Pod的状态和重启策略下表列出一些常见的状态转换场景。8、Pod健康检查和服务可用性检查Kubernetes对Pod的健康状态可以通过两类探针来检查 LivenessProbe和ReadinessProbekubelet定期执行这两类探针来诊断容器的健康状况。1LivenessProbe探针用于判断容器是否存活Running状态​如果LivenessProbe探针探测到容器不健康则kubelet将杀掉该容器并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。2ReadinessProbe探针用于判断容器服务是否可用Ready状态​达到Ready状态的Pod才可以接收请求。对于被Service管理的PodService与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False则系统自动将其从Service的后端Endpoint列表中隔离出去后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。LivenessProbe和ReadinessProbe均可配置以下三种实现方式。1ExecAction在容器内部执行一个命令如果该命令的返回码为0则表明容器健康。在下面的例子中通过执行“cat /tmp/health”命令来判断一个容器运行是否正常。在该Pod运行后将在创建/tmp/health文件10s后删除该文件而LivenessProbe健康检查的初始探测时间initialDelaySeconds为15s探测结果是Fail将导致kubelet杀掉该容器并重启它apiVersion:v1kind:Podmetadata:labels:test:livenessname:liveness-execspec:containers:-name:livenessimage:gcr.io/google_containers/busyboxargs:-/bin/sh--c-echo ok/tmp/health; sleep 10; rm-rf /tmp/health; sleep 600livenessProbe:exec:command:-cat-/tmp/healthinitialDelaySeconds:15timeoutSeconds:12TCPSocketAction通过容器的IP地址和端口号执行TCP检查如果能够建立TCP连接则表明容器健康。在下面的例子中通过与容器内的localhost:80建立TCP连接进行健康检查apiVersion:v1kind:Podmetadata:name:pod-with-healthcheckspec:containers:-name:nginximage:nginxports:-containerPort:80livenessProbe:tcpSocket:port:80initialDelaySeconds:30timeoutSeconds:13HTTPGetAction通过容器的IP地址、端口号及路径调用HTTP Get方法如果响应的状态码大于等于200且小于400则认为容器健康。在下面的例子中kubelet定时发送HTTP请求到localhost:80/_status/healthz来进行容器应用的健康检查apiVersion:v1kind:Podmetadata:name:pod-with-healthcheckspec:containers:-name:nginximage:nginxports:-containerPort:80livenessProbe:httpGet:path:/_status/healthzport:80initialDelaySeconds:30timeoutSeconds:1对于每种探测方式都需要设置initialDelaySeconds和timeoutSeconds两个参数它们的含义分别如下。initialDelaySeconds启动容器后进行首次健康检查的等待时间单位为s。timeoutSeconds健康检查发送请求后等待响应的超时时间单位为s。当超时发生时kubelet会认为容器已经无法提供服务将会重启该容器。Kubernetes的ReadinessProbe机制可能无法满足某些复杂应用对容器内服务可用状态的判断所以Kubernetes从1.11版本开始引入Pod Ready特性对Readiness探测机制进行扩展在1.14版本时达到GA稳定版称其为Pod Readiness Gates。通过Pod Readiness Gates机制用户可以将自定义的ReadinessProbe探测方式设置在Pod上辅助Kubernetes设置Pod何时达到服务可用状态Ready​。为了使自定义的ReadinessProbe生效用户需要提供一个外部的控制器Controller来设置相应的Condition状态。Pod的Readiness Gates在Pod定义中的ReadinessGate字段进行设置。下面的例子设置了一个类型为www.example.com/feature-1的新Readiness GateKind:Pod......spec:readinessGates:-conditionType:www.example.com/feature-1status:conditions:-type:Ready# Kubernetes系统内置的名为Ready的Conditionstatus:TruelastProbeTime:nulllastTransitionTime:2018-01-01T00:00:00Z-type:www.example.com/feature-1# 用户自定义Conditionstatus:FalselastProbeTime:nulllastTransitionTime:2019-03-01T00:00:00ZcontainerStatuses:-containerID:docker://abcd...ready:true......新增的自定义Condition的状态status将由用户自定义的外部控制器设置默认值为False。Kubernetes将在判断全部readinessGates条件都为True时才设置Pod为服务可用状态Ready为True​。