RedCloud Help

5.Pod资源高级用法

pod 是 k8s 最小调度单元,pod 里可以运行一个或者多个容器

1.1 Pod 高级用法:node 节点选择器和 nodeName

1.1.1、nodeName:

在 Kubernetes 中,NodeName 是每个 Node 节点的唯一标识符,它是一个字符串,通常是节点的主机名(hostname)。在创建 Pod 时,可以通过指定 nodeName 字段来将 Pod 调度到特定的Node 节点上。指定 pod 节点运行在具体 node 上

cat pod-node.yaml
apiVersion: v1 kind: Pod metadata: name: demo-pod namespace: default labels: app: busybox-tomcat env: pro spec: nodeName: redcloud002 containers: - name: tomcat ports: - containerPort: 8080 image: tomcat:latest imagePullPolicy: IfNotPresent - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-c" - "sleep 36000"

1.1.2、nodeSelector:

在 Kubernetes 中,nodeSelector 是一种用于在 Pod 级别上选择运行节点的方法。通过使用nodeSelector 字段,你可以指定一组键值对(标签),以便将 Pod 调度到具有匹配标签的节点上运行。

每个节点都可以使用一组标签进行标识,这些标签可以根据硬件规格、操作系统、地理位置或其他特定的属性来定义。当创建 Pod 时,你可以通过在Pod 的配置中指定 nodeSelector 字段,来告诉Kubernetes 调度器选择具有匹配标签的节点来运行该 Pod。

以下是一个示例 Pod 配置,展示了如何使用 nodeSelector 字段来选择节点:

apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx imagePullPolicy: IfNotPresent nodeSelector: disk: ssd region: us-west

在上述示例中,nodeSelector 字段包含了两个键值对:disk: ssd 和 region:us-west。这意味着Kubernetes 将尝试将这个 Pod 调度到具有标签 disk=ssd 和 region=us-west 的节点上。那我们需要给节点打标签才可以:

kubectl label nodes xianchaonode1 disk=ssd kubectl label nodes xianchaonode1 region=us-west Node Selector 是通过在 Pod 的 spec 中指定标签选择器来选择目标节点。例如,你可以在 Pod 的 spec 中指定 nodeSelector 字段来选择带有特定标签

1.2 Pod 高级用法:亲和性 affinity

在 k8s 中亲和性有两种:节点亲和性(node affinity)和 Pod 亲和性(pod affinity)。

  1. Pod 亲和性(Pod Affinity):Pod 亲和性用于指定 Pod 之间的关系,使它们倾向于在同一 节点或具有相似特征的节点上运行。这可以在以下场景中发挥作用: • 数据本地性:当两个或多个 Pod 需要访问相同的本地数据时,可以使用 Pod 亲和性 将它们调度到同一节点上。例如,在分布式数据库中,多个数据库实例需要访问相同的 数据卷或存储,可以通过 Pod 亲和性将它们调度到同一节点上,减少网络传输延迟。 • 互为依赖:当两个或多个 Pod 之间存在依赖关系,需要相互通信或协同工作时,可以 使用 Pod 亲和性将它们调度到同一节点上。例如,在微服务架构中,某个服务需要与 特定的缓存服务进行交互,可以使用 Pod 亲和性将它们调度到同一节点上,提高性能 和减少网络开销。 • 服务发现和负载均衡:在需要实现服务发现和负载均衡的场景中,可以使用 Pod 亲和 性将属于同一服务的多个实例调度到同一节点或相近的节点上。这样可以提高服务的可 用性、降低延迟,并简化负载均衡配置。

  2. 节点亲和性(Node Affinity):节点亲和性用于指定 Pod 与节点之间的关系,使 Pod 倾向 于在具有特定标签或节点特征的节点上运行。这可以在以下场景中发挥作用: • 资源需求:当某个 Pod 对计算资源(如 CPU、内存)或其他特定硬件资源(如 GPU)有特定需求时,可以使用节点亲和性将它调度到具有相应资源的节点上。这有助 于优化资源利用和性能。 • 逻辑分组:当需要将相关的 Pod 分组部署到特定节点上时,可以使用节点亲和性。例 如,在分布式系统中,某个节点需要承担特定的角色或任务,可以使用节点亲和性将相 关的 Pod 调度到该节点上,以便实现逻辑上的分组和管理。 • 特定硬件或软件要求:当某个 Pod 需要依赖特定的硬件设备或软件环境时,可以使用 节点亲和性将它调度到具备所需条件的节点上。例如,某个 Pod 需要与具有特定硬件 加速器的节点进行通信,可以使用节点亲和性将它调度到具备所需硬件的节点上。

1.2.1 node 节点亲和性

node 节点亲和性:nodeAffinity

kubectl explain pods.spec.affinity KIND: Pod VERSION: v1 RESOURCE: affinity <Object> DESCRIPTION: If specified, the pod's scheduling constraints Affinity is a group of affinity scheduling rules. FIELDS: nodeAffinity <Object> podAffinity <Object> podAntiAffinity <Object> kubectl explain pods.spec.affinity.nodeAffinity KIND: Pod VERSION: v1 RESOURCE: nodeAffinity <Object> DESCRIPTION: Describes node affinity scheduling rules for the pod. Node affinity is a group of node affinity scheduling rules. FIELDS: preferredDuringSchedulingIgnoredDuringExecution <[]Object> requiredDuringSchedulingIgnoredDuringExecution <Object> preferredDuringSchedulingIgnoredDuringExecution: preferredDuringSchedulingIgnoredDuringExecution 是 Kubernetes 中节点亲和性(Node Affinity)的一种规则类型,它允许用户指定 Pod 调度器尽可能将 Pod 调度到与指定节点亲和的节点 上,但如果没有可用的这样的节点,Pod 也可以调度到其他节点上。 requiredDuringSchedulingIgnoredDuringExecution:这个字段指定了一个节点选择器,Pod 只能被调度到满足这个节点选择器的节点上。如果没有节点满足这个要求,Pod 就无法被调度。

例 1:使用 requiredDuringSchedulingIgnoredDuringExecution

apiVersion: v1 kind: Pod metadata: name: nodeaffinity-1 namespace: default labels: app: myapp item: pro spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: a operator: In values: - b

我们检查当前节点中有任意一个节点拥有 a=b 标签,就可以把 pod 调度到有 a=b 这个标签的节点 上。

kubectl apply -f nodeaffinity.yaml kubectl get pods -owide -l app=myapp NAME READY STATUS RESTARTS AGE IP NODE nodeaffinity-1 0/1 Pending 0 3m9s <none> <none>

status 的状态是 pending,上面说明没有完成调度,因为没有任何一个拥有 a=b 标签的节点,而 且使用的是硬亲和性,必须满足条件才能完成调度

kubectl label nodes xianchaonode1 a=b NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nodeaffinity-1 1/1 Running 0 6m48s 10.244.209.132 redcloud001

例 2:使用 preferredDuringSchedulingIgnoredDuringExecution 软亲和性

apiVersion: v1 kind: Pod metadata: name: nodeaffinity-2 namespace: default labels: app: myapp1 item: pro1 spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - preference: matchExpressions: - key: a1 operator: In values: - b1 weight: 80
kubectl apply -f nodeaffinity-1.yaml kubectl get pods -owide -l app=myapp1 NAME READY STATUS RESTARTS AGE IP NODE nodeaffinity-2 1/1 Running 0 12s 10.244.187.65 redcloud001

上面说明软亲和性是可以运行这个 pod 的,尽管没有任何一个节点具有 a1=b1 这个标签

kubectl label nodes xianchaonode1 a- kubectl label nodes xianchaonode1 region- kubectl label nodes xianchaonode1 disk-

1.2.2 Pod 和 Pod 亲和性

podAffinity:表示 Pod 与其它 Pod 的亲和性。可以使用 requiredDuringSchedulingIgnoredDuringExecution、 preferredDuringSchedulingIgnoredDuringExecution 等字段来指定 Pod 与其它 Pod 的亲和性规则。这些字段中可以使用 topologyKey 和 labelSelector 字段来指定 Pod 之间的关系。

pod 亲和性分两种: podaffinity(pod 亲和性):Pod 亲和性是指一组 Pod 可以被调度到同一节点上,即它们互相吸引, 倾向于被调度在同一台节点上。例如,假设我们有一组具有相同标签的 Pod,通过使用 Pod 亲和性规 则,我们可以让它们在同一节点上运行,以获得更高的性能和更好的可靠性。

podunaffinity(pod 反亲和性):Pod 反亲和性是指一组 Pod 不应该被调度到同一节点上,即它 们互相排斥,避免被调度在同一台节点上。例如,如果我们有一组应用程序 Pod,我们可以使用 Pod 反亲和性规则来避免它们被调度到同一节点上,以减少单点故障的风险和提高可靠性。

kubectl explain pods.spec.affinity.podAffinity KIND: Pod VERSION: v1 RESOURCE: podAffinity <Object> DESCRIPTION: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). Pod affinity is a group of inter pod affinity scheduling rules. FIELDS: preferredDuringSchedulingIgnoredDuringExecution <[]Object> requiredDuringSchedulingIgnoredDuringExecution <[]Object> requiredDuringSchedulingIgnoredDuringExecution: 硬亲和性 preferredDuringSchedulingIgnoredDuringExecution:软亲和性

例 1:pod 和 pod 亲和性

定义两个 pod,调度到同一个位置

apiVersion: v1 kind: Pod metadata: name: first labels: app: first spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent
kubectl label nodes redcloud001 a- kubectl label nodes redcloud001 a- kubectl apply -f podaffinity-require.yaml kubectl get pods -owide -l app=first NAME READY STATUS RESTARTS AGE IP NODE first 1/1 Running 0 33s 10.244.187.66 redcloud001

通过上面可以看到,第一个 pod 调度到了 xianchaonode1 上了。

apiVersion: v1 kind: Pod metadata: name: second labels: app: second spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - { key: app, operator: In, values: [ "first" ] } topologyKey: kubernetes.io/hostname # 备注: # YAML 文件解释说明: #- labelSelector: # matchExpressions: #- {key: app, operator: In, values: ["myapp"]} # topologyKey: kubernetes.io/hostname #上面表示创建的 second 这个 pod 与拥有 app=first 标签的 pod 进行亲和性。

topologyKey: kubernetes.io/hostname :这个是 Kubernetes 中一个用于指定节点位置拓扑的 关键字,kubernetes.io/hostname 是一个节点标签的 key 值,不同的节点这个 key 对应的 value 值 是节点主机名,它表示 Pod 应该与具有相同的主机名的节点进行亲和性或反亲和性调度。也就是两个 pod 调度到同一个 node 节点或者不同的 node 节点上。

kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS redcloud001 Ready control-plane,master 15d v1.23.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=redcloud001,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers= redcloud002 Ready worker 15d v1.23.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=redcloud002,kubernetes.io/os=linux,node-role.kubernetes.io/worker=worker kubectl apply -f podaffinity-require-1.yaml kubectl get pods -owide -l app=second kubectl get pods -owide -l app=first

上面说明第一个 pod 调度到哪,第二个 pod 也调度到哪,这就是 pod 节点亲和性

kubectl delete -f podaffinity-require-1.yaml --force -- grace-period=0 kubectl delete -f podaffinity-require.yaml --force --graceperiod=0

例 2:pod 节点反亲和性

定义两个 pod,第一个 pod 做为基准,第二个 pod 跟它调度到不同的节点上

vim podunaffinity-1.yaml
apiVersion: v1 kind: Pod metadata: name: first-1 labels: app: first-1 spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent
kubectl apply -f podunaffinity-1.yaml kubectl get pods -l app=first-1 -owide NAME READY STATUS RESTARTS NODE first-1 1/1 Running 0 redcloud001
apiVersion: v1 kind: Pod metadata: name: second-1 labels: app: second-1 spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - { key: app, operator: In, values: [ "first-1" ] } topologyKey: kubernetes.io/hostname
kubectl apply -f podunaffinity-2.yaml kubectl get pods -l app=first-1 -owide NAME READY STATUS RESTARTS AGE IP NODE first-1 1/1 Running 0 4m34s 10.244.209.133 redcloud001 kubectl get pods -l app=second-1 -owide NAME READY STATUS RESTARTS AGE IP NODE second-1 1/1 Running 0 12s 10.244.187.68 redcloud002 <none>

上面结果表示两个 pod 不在一个 node 节点上,这就是 pod 节点反亲和性

1.3 污点和容忍度

我们给节点打一个污点,不容忍的 pod 就运行不上来,污点就是定义在节点上的键值属性数据,

可以定决定拒绝那些 pod,容忍度是定义在 pod 上的,用来指定能容忍哪些污点。

taints 是键值数据,用在节点上,定义污点;

tolerations 是键值数据,用在 pod 上,定义容忍度,能容忍哪些污点

kubectl describe nodes redcloud001 Taints: node-role.kubernetes.io/control-plane:NoSchedule kubectl explain node.spec.taints KIND: Node VERSION: v1 RESOURCE: taints <[]Object> DESCRIPTION: If specified, the node's taints. The node this Taint is attached to has the "effect" on any pod that does not tolerate the Taint. FIELDS: effect <string> -required- Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute. key <string> -required- Required. The taint key to be applied to a node. timeAdded <string> TimeAdded represents the time at which the taint was added. It is only written for NoExecute taints. value <string> The taint value corresponding to the taint key.

taints 的 effect 用来定义对 pod 对象的排斥等级(效果):

NoSchedule: 仅影响 pod 调度过程,当 pod 能容忍这个节点污点,就可以调度到当前节点,后来这个节点的 污点改了,加了一个新的污点,使得之前调度的 pod 不能容忍了,那这个 pod 会怎么处理,对 现存的 pod 对象不产生影响

NoExecute: 既影响调度过程,又影响现存的 pod 对象,如果现存的 pod 不能容忍节点后来加的污点,这个 pod 就会被驱逐

PreferNoSchedule: 最好不,也可以,是 NoSchedule 的柔性版本

kubectl describe nodes xianchaomaster1 查看 master 这个节点是否有污点,显示如下: Taints: node-role.kubernetes.io/control-plane:NoSchedule

上面可以看到 master 这个节点的污点是 Noschedule

所以我们创建的 pod 都不会调度到 master 上,因为我们创建的 pod 没有容忍度

kubectl describe pods kube-apiserver-xianchaomaster1 -n kube-system 显示如下: Tolerations: :NoExecute op=Exists 可以看到这个 pod 的容忍度是 NoExecute,则可以调度到 xianchaomaster1 上

1.3.1 管理节点污点

kubectl taint --help

例 1:把 xianchaonode1 当成是生产环境专用的。

kubectl taint node xianchaonode1 node-type=production:NoSchedule 给 xianchaonode1 打污点,pod 如果不能容忍就不会调度过来
apiVersion: v1 kind: Pod metadata: name: taint-pod namespace: default labels: tomcat: tomcat-pod spec: containers: - name: taint-pod ports: - containerPort: 8080 image: tomcat:8.5-jre8-alpine imagePullPolicy: IfNotPresent
kubectl apply -f pod-taint.yaml kubectl get pods -o wide

显示如下: taint-pod pending

pod 是 pending 状态,说明,xianchaomaster1 和 xianchaonode1 都打了污点,pod 没定义 容忍度,所以不会调度到任何一个节点上。

apiVersion: v1 kind: Pod metadata: name: myapp-deploy namespace: default labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 tolerations: - key: "node-type" operator: "Equal" value: "production" effect: "NoSchedule"

删除污点

kubectl taint nodes xianchaonode1 node-type=production:NoSchedule

1.4 Pod高级用法:对pod内的容器做健康探测

1.4.1 Liveness Probe(存活探测)

Liveness Probe 用于监测 pod 内的容器是否处于运行状态。当 Liveness Probe 探测失败时,Kubernetes根据重启策略决定是否重启该容器。适用于需要在容器发生故障时立即进行重启的应用场景,比如 Web 服务器和数据库等应用。

1.4.2 Readiness Probe(就绪探测)

Readiness Probe 用于监测 pod 内的容器是否已经准备好接受流量,即容器是否已经完成初始化并已经启动了应用程序。当容器的Readiness Probe 探测失败时,Kubernetes 将停止将新的流量转发到该容器。适用于需要应用程序启动较长时间的应用场景,比如大型 Web 应用程序。

1.4.3 Startup Probe(启动探测)

Startup Probe 用于监测 pod 内的容器是否已经启动成功并准备好接受流量。与 Liveness Probe 不同的是,Startup Probe 只会在容器启动时执行一次。当 Startup Probe 探测失败时,Kubernetes 将自动重启该容器。适用于需要较长启动时间的应用场景,比如应用 程序需要大量预热或者需要等待外部依赖组件的应用程序。

image_21.png

1.4.4 liveness 案例分享

Liveness Probe 用于检查 pod 内的容器是否在运行,并在容器出现故障时重新启动容器。Liveness Probe 支持三种探针:httpGet、exec 和 tcpSocket。

1.4.4.1 使用Http接口进行探测

apiVersion: v1 kind: Pod metadata: name: liveness-http labels: app: nginx spec: containers: - name: liveness image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 livenessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 20 periodSeconds: 10 restartPolicy: Always
文件说明

1、initialDelaySeconds:首次探测之前等待的时间,单位是秒。在容器启动之后,等待指定的时间后 才开始进行探测,避免容器还未启动完成就开始进行探测,导致探测失败。

2、periodSeconds:探测器的周期时间,单位是秒。探测器将在每隔一定时间间隔内进行一次探测。默 认周期时间是 10 秒。

kubectl apply -f live-http.yaml kubectl exec -it liveness-http --bin/bash rm -rf /usr/share/nginx/html/index.html kubectl get pods liveness-http NAME READY STATUS RESTARTS AGE liveness-http 1/1 Running 1 (3s ago) 3m3s # 可以看到pod里的容器重启了一次,因为默认的重启策略是always,只要探测失败就重启。
apiVersion: v1 kind: Service metadata: name: livess namespace: default spec: ports: - port: 80 targetPort: 80 selector: app: nginx type: NodePort
kubectl apply -f svc.yaml

svc跟pod关联之后,通过ipvsadm -Ln,可以看到ip了。

1.4.4.2 使用tcp接口进行探测:

apiVersion: v1 kind: Pod metadata: name: liveness-tcp spec: containers: - name: liveness image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 livenessProbe: tcpSocket: port: 80 initialDelaySeconds: 15 periodSeconds: 20
kubectl apply -f live-tcp.yaml kubectl get pods liveness-tcp NAME READY STATUS RESTARTS AGE liveness-tcp 1/1 Running 0 16s # 模拟探测失败情况: 在nginx容器中停止nginx服务,这样80端口无法访问 kubectl exec -it liveness-tcp --/bin/bash nginx -s stop # 查看pod kubectl get pods liveness-http NAME READY STATUS RESTARTS AGE liveness-http 1/1 Running 1 (3s ago) 3m3s

可以看到pod里的容器重启了一次。因为默认的重启策略是always,只要探测失败就重启。

1.4.5 readiness probe 案例分享

Readiness probe 用于检查容器是否已经准备好接受流量。Readiness Prode 支持三种探针: httpGet , exec 和 tcpSocket。

apiVersion: v1 kind: Pod metadata: name: my-pod labels: app: my-pod spec: containers: - name: nginx-container image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 readinessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 1 periodSeconds: 2 failureThreshold: 3 successThreshold: 1

文件说明

1、initialDelaySeconds:首次探测之前等待的时间,单位是秒。在容器启动之后,等待指定的时间后才开始进行探测,避免容器还未启动完成就开始进行探测,导致探测失败。

2、periodSeconds:探测器的周期时间,单位是秒。探测器将在每隔一定时间间隔内进行一次探测。默认周期时间是 10 秒。

3、failureThreshold:探测失败的阈值,failureThreshold: 3 是指在连续失败了 3 次探测后,探测就会被认定为失败,容器将被认为是不健康的,并且将被终止并重新启动。

4、successThreshold:探测成功的阈值,假设 successThreshold: 1,则当容器探测成功一次后,容器将被认为是健康的,继续运行。

所以上面最终的探测方式如下:

探测将在容器启动等待1分钟,然后开始执行。探测周期的时间间隔为2秒,也就是每隔2秒进行一次探测。如果在探测期间出现3次失败,则Pod将被标记为NotReady,如果探测成功一次,才会将其标记为Ready。

apiVersion: v1 kind: Service metadata: name: readiness spec: selector: app: my-pod ports: - port: 80 targetPort: 80
kubectl apply -f readiness-svc.yaml kubectl apply -f readiness-http.yaml kubectl get pods my-pod -w NAME READY STATUS RESTARTS AGE my-pod 0/1 ContainerCreating 0 1s my-pod 0/1 Running 0 2s my-pod 1/1 Running 0 2s

上面可以看到pod没有立即ready,因为initialDelaySeconds: 1.表示pod启动后1s才开始探测,所以至少要等1s,探测没问题才能就绪。

模拟探测失败的情况: 在Nginx 容器中删除 /usr/share/nginx/html/index.html文件,这样httpGet 探针将无法访问该文件,从而导致探测失败。

kubectl exec -it my-pod --/bin/bash rm -rf /usr/share/nginx/html/index.html kubectl get pods my-pod -w my-pod 1/1 Running 0 64s my-pod 0/1 Running 0 71s # 上面可以看到pod已经不就绪了,在64s时候删除index.html文件。然后每隔2s探测一次,6s探测了3次,都失败了,pod内的容器就会处于非就绪状态。 修复探测失败的情况:重新创建 /usr/share/nginx/html/index.html 文件。 kubectl get pods my-pod -w NAME READY STATUS RESTARTS AGE my-pod 0/1 Running 0 12m my-pod 1/1 Running 0 12m

1.5 Pod容器健康探测

1.5.1 为什么要对容器做探测

在 Kubernetes 中 Pod 是最小的计算单元,而一个 Pod 又由多个容器组成,相当于每个容器就是一个应用,应用在运行期间,可能因为某些意外情况致使程序挂掉。那么如何监控这些容器状态稳定性,保证服务在运行期间不会发生问题,发生问题后进行重启等机制,就成为了重中之重的事情,考虑到这点 kubernetes 推出了活性探针机制。有了存活性探针能保证程序在运行中如果挂掉能够自动重启,但是还有个经常遇到的问题,比如说,在 Kubernetes 中启动 Pod,显示明明 Pod 已经启动成功,且能访问里面的端口,但是却返回错误信息。还有就是在执行滚动更新时候,总会出现一段时间,Pod 对外提供网络访问,但是访问却发生 404,这两个原因,都是因为 Pod已经成功启动,但是Pod 的的容器中应用程序还在启动中导致,考虑到这点 Kubernetes 推出了就绪性探针机制。

1.5.1.1 默认的健康检查

Kubernetes 默认的健康检查机制: 每个容器启动时都会执行一个进程, 此进程由 Dockerfile 的CMD 或 ENTRYPOINT 指定。 如果进程退出时返回码非零, 则认为容器发生故障, Kubernetes 就会根据restartPolicy 策略决定是否重启容器。

apiVersion: v1 kind: Pod metadata: name: check namespace: default labels: app: check spec: containers: - name: check image: busybox:1.28 imagePullPolicy: IfNotPresent command: - /bin/sh - -c - sleep 10;exit
kubectl get pods -w NAME READY STATUS RESTARTS AGE check 0/1 Pending 0 0s check 0/1 Pending 0 0s check 0/1 ContainerCreating 0 0s check 0/1 ContainerCreating 0 1s check 1/1 Running 0 1s check 0/1 Completed 0 11s check 1/1 Running 1 (1s ago) 12s check 0/1 Completed 1 (11s ago) 22s check 0/1 CrashLoopBackOff 1 (13s ago) 34s check 1/1 Running 2 (13s ago) 34s check 0/1 Completed 2 (23s ago) 44s

在上面的例子中, 容器进程返回值非零, Kubernetes 则认为容器发生故障, 需要重启。 有不少情况是发生了故障, 但进程并不会退出。 比如访问 Web 服务器时显示 500 内部错误, 可能是系统超载, 也可能是资源死锁, 此时 httpd 进程并没有异常退出,在这种情况下重启容器可能是最直接、最有效的解决方案。

k8s提供了三种来实现容器探测的方法,分别是:

  • startupProd: 探测容器中的应用是否已经启动。如果提供了启动探测(startUp prode),则禁用其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功 Success。

  • livenessprobe:用指定的方式(exec、tcp、http)检测 pod 中的容器是否正常运行,如果检测失败,则认为容器不健康,那么 Kubelet 将根据 Pod 中设置的 restartPolicy 策略来判断 Pod是否要进行重启操作,如果容器配置中没有配置 livenessProbe,Kubelet 将认为存活探针探测s一直为 success(成功)状态。

  • readnessprobe:就绪性探针,用于检测容器中的应用是否可以接受请求,当探测成功后才使Pod 对外提供网络访问,将容器标记为就绪状态,可以加到 pod 前端负载,如果探测失败,则将容 器标记为未就绪状态,会把 pod 从前端负载移除。

可以自定义在pod启动时是否执行这些检测,如果不设置,则检测结果均默认为通过,如果设置,则顺序为startUpProd> readinessProbe和livenessProbe,readinessProbe和livenessProbe是并发关系

官方文档:Caution: Liveness probes do not wait for readiness probes to succeed. If you want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe

也就是 Liveness probes 并不会等到 Readiness probes 成功之后才运行,根据上面的官方文档,Liveness 和 readiness 应该是某种并发的关系。

目前 LivenessProbe 和 ReadinessProbe、startupprobe 探测都支持下面三种探针: 1、exec:在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。 2、TCPSocket:通过容器的 IP 地址和端口号执行 TCP 检 查,如果能够建立 TCP 连接,则表明 容器健康。 3、HTTPGet:通过容器的 IP 地址、端口号及路径调用 HTTP Get 方法,如果响应的状态码大于等 于 200 且小于 400,则认为容器健康 探针探测结果有以下值: 1、Success:表示通过检测。 2、Failure:表示未通过检测。 3、Unknown:表示检测没有正常进行。

Pod 探针相关的属性:

探针(Probe)有许多可选字段,可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为

  • initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是 0 秒,最小值是 0

  • periodSeconds: 执行探测的时间间隔(单位是秒),默认为 10s,单位“秒”,最小值是 1

  • timeoutSeconds: 探针执行检测请求后,等待响应的超时时间,默认为 1,单位“秒”。

  • successThreshold:连续探测几次成功,才认为探测成功,默认为 1,在 Liveness 探针中必须为 1,最小值为 1。

  • failureThreshold: 探测失败的重试次数,重试一定次数后将认为失败,在 readiness 探针中,Pod 会被标记为未就绪,默认为 3,最小值为 1

两种探针区别:

ReadinessProbe 和 livenessProbe 可以使用相同探测方式,只是对 Pod 的处置方式不同:

  • readinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。

  • livenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。

1.5.1.2 启动探测 startupProbe

exec 模式
apiVersion: v1 kind: Pod metadata: name: startupprobe spec: containers: - name: startup image: xianchao/tomcat-8.5-jre8:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 startupProbe: exec: command: - "/bin/sh" - "-c" - "aa ps aux | grep tomcat" initialDelaySeconds: 20 #容器启动后多久开始探测 periodSeconds: 20 #执行探测的时间间隔 timeoutSeconds: 10 #探针执行检测请求后,等待响应的超时时间 successThreshold: 1 #成功多少次才算成功 failureThreshold: 3 #失败多少次才算失败
tcpsocket模式
apiVersion: v1 kind: Pod metadata: name: startupprobe spec: containers: - name: startup image: xianchao/tomcat-8.5-jre8:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 startupProbe: tcpSocket: port: 8080 initialDelaySeconds: 20 #容器启动后多久开始探测 periodSeconds: 20 #执行探测的时间间隔 timeoutSeconds: 10 #探针执行检测请求后,等待响应的超时时间 successThreshold: 1 #成功多少次才算成功 failureThreshold: 3 #失败多少次才算失败
httpget模式
apiVersion: v1 kind: Pod metadata: name: startupprobe spec: containers: - name: startup image: xianchao/tomcat-8.5-jre8:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 startupProbe: httpGet: path: / port: 8080 initialDelaySeconds: 20 #容器启动后多久开始探测 periodSeconds: 20 #执行探测的时间间隔 timeoutSeconds: 10 #探针执行检测请求后,等待响应的超时时间 successThreshold: 1 #成功多少次才算成功 failureThreshold: 3 #失败多少

1.5.3 ReadinessProbe + LivenessProbe + startupProbe配合使用

一般程序中需要设置三种探针结合使用,并且也要结合实际情况,来配置初始化时间和检测间隔,下面列一个简单的springboot项目的例子。

apiVersion: v1 kind: Service metadata: name: springboot-live labels: app: springboot spec: type: NodePort ports: - name: server port: 8080 targetPort: 8080 nodePort: 31180 - name: management port: 8081 targetPort: 8081 nodePort: 31181 selector: app: springboot --- apiVersion: v1 kind: Pod metadata: name: springboot-live labels: app: springboot spec: containers: - name: springboot image: mydlqclub/springboot-helloworld:0.0.1 imagePullPolicy: IfNotPresent ports: - name: server containerPort: 8080 - name: management containerPort: 8081 readinessProbe: initialDelaySeconds: 20 periodSeconds: 5 timeoutSeconds: 10 httpGet: scheme: HTTP port: 8081 path: /actuator/health livenessProbe: initialDelaySeconds: 20 periodSeconds: 5 timeoutSeconds: 10 httpGet: scheme: HTTP port: 8081 path: /actuator/health startupProbe: initialDelaySeconds: 20 periodSeconds: 5 timeoutSeconds: 10 httpGet: scheme: HTTP port: 8081 path: /actuator/health
13 February 2026