介绍
日志、事件、exec 和端口转发可以帮助你检查应用程序。而探针(Probes)则允许 Kubernetes 对应用程序进行持续的健康检查。就绪探针回答的问题是:「该 Pod 是否应该接收流量?」;存活探针回答的问题是:「该容器是否应该被重启?」
在本实验中,你将分别配置就绪探针和存活探针。首先,你将创建一个只有在创建了 /ready 端点后才会变为就绪状态的应用程序。然后,你将创建另一个带有存活探针的应用程序,通过 kubectl exec 删除其健康检查文件,并观察 Kubernetes 如何重启该容器。
准备探针练习命名空间
在此步骤中,你将准备一个干净的命名空间用于探针练习。
从 /home/labex/project 开始。你将把探针的清单文件保存在此目录中。
mkdir -p /home/labex/project
cd /home/labex/project
检查 Kubernetes API 服务器是否可达。如果虚拟机刚启动且节点尚未就绪,请等待几秒钟后再运行该命令。
kubectl get nodes --request-timeout=5s
预期输出包含:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
等待集群网络 Pod 就绪。探针和 Service 依赖于健康的 Pod 网络。
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
预期输出:
pod/calico-node-... condition met
创建一个名为 ckad-prep-probes 的命名空间,并将其设置为当前命名空间:
kubectl create namespace ckad-prep-probes
kubectl config set-context --current --namespace=ckad-prep-probes
确认当前命名空间:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
预期输出:
ckad-prep-probes
配置就绪探针
在此步骤中,你将配置一个就绪探针,并观察 Service 如何仅使用就绪的 Pod。
该容器会立即启动 HTTP 服务器,但在几秒钟后才会创建 /www/ready 文件。就绪探针会检查端口 8080 上的 GET /ready 请求。在该路径存在之前,Pod 可以处于 Running 状态但并非 Ready,此时 Service 不应向其发送流量。
创建 readiness-web.yaml:
cat > readiness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-web
spec:
replicas: 2
selector:
matchLabels:
app: readiness-web
template:
metadata:
labels:
app: readiness-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
mkdir -p /www
echo readiness-ok > /www/index.html
(sleep 12; echo ready > /www/ready) &
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
---
apiVersion: v1
kind: Service
metadata:
name: readiness-web
spec:
selector:
app: readiness-web
ports:
- port: 80
targetPort: 8080
EOF
应用清单文件,并在创建后立即查看 Pod:
kubectl apply -f readiness-web.yaml
sleep 3
kubectl get pods -l app=readiness-web
预期输出可能显示 Pod 处于 Running 但尚未 Ready 的状态:
NAME READY STATUS RESTARTS AGE
readiness-web-... 0/1 Running 0 ...
等待 Deployment 变为可用状态:
kubectl rollout status deployment/readiness-web --timeout=120s
预期输出:
deployment "readiness-web" successfully rolled out
通过 EndpointSlice 检查 Service 端点。在就绪探针通过后,Service 应该有两个就绪的端点。
kubectl get endpointslice -l kubernetes.io/service-name=readiness-web
预期输出包含:
NAME ADDRESSTYPE PORTS ENDPOINTS
readiness-web-... IPv4 8080 ... + 1 more...
创建一个客户端 Pod 并测试 Service:
kubectl run probe-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/probe-client --timeout=120s
kubectl exec probe-client -- wget -qO- http://readiness-web
预期输出:
readiness-ok
配置存活探针
在此步骤中,你将配置一个检查健康文件的存活探针。
存活探针决定了 Kubernetes 是否应该重启容器。此示例使用了一个 exec 探针,它会在容器内运行 test -f /tmp/healthy。容器在启动时会创建该文件,因此它最初是健康的。
创建 liveness-web.yaml:
cat > liveness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-web
spec:
replicas: 1
selector:
matchLabels:
app: liveness-web
template:
metadata:
labels:
app: liveness-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
touch /tmp/healthy
mkdir -p /www
echo liveness-ok > /www/index.html
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
livenessProbe:
exec:
command:
- test
- -f
- /tmp/healthy
initialDelaySeconds: 3
periodSeconds: 3
failureThreshold: 1
EOF
应用清单文件并等待 Deployment 就绪:
kubectl apply -f liveness-web.yaml
kubectl rollout status deployment/liveness-web --timeout=120s
预期输出包含:
deployment.apps/liveness-web created
deployment "liveness-web" successfully rolled out
存储 Pod 名称并确认健康文件存在:
LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"
kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file exists"
预期输出包含 Pod 名称以及:
health file exists
描述 Pod 并查看存活探针配置:
kubectl describe pod "$LIVE_POD" | grep -A3 'Liveness:'
预期输出包含:
Liveness: exec [test -f /tmp/healthy] delay=3s timeout=1s period=3s
触发存活重启
在此步骤中,你将删除健康文件,并观察存活探针如何重启容器。
Pod 对象可以保持不变,而其中的容器会重启。这就是为什么你要观察容器的重启次数,而不是期望出现一个新的 Pod 名称。
存储当前的 Pod 名称:
LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"
从容器内部删除健康文件:
kubectl exec "$LIVE_POD" -- rm /tmp/healthy
观察重启次数,直到它大于零。存活探针每三秒运行一次,因此这可能需要一点时间。
for i in $(seq 1 20); do
RESTARTS="$(kubectl get pod "$LIVE_POD" -o jsonpath='{.status.containerStatuses[0].restartCount}')"
echo "restart-count=$RESTARTS"
if [ "$RESTARTS" != "0" ]; then
break
fi
sleep 3
done
预期输出最终包含:
restart-count=1
容器重启后,启动命令会再次创建 /tmp/healthy。确认文件已恢复:
kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file recreated"
预期输出:
health file recreated
读取 Pod 事件并查看存活探针失败记录:
kubectl describe pod "$LIVE_POD" | sed -n '/Events:/,$p'
预期输出包含:
Warning Unhealthy ... Liveness probe failed
Normal Killing ... Container web failed liveness probe
总结
你配置了两种主要的应用程序探针。就绪探针控制了 Pod 何时加入 Service 端点,而存活探针在健康文件被删除后重启了容器。你还检查了 EndpointSlice、Pod 描述、重启次数和事件,从而将探针配置与可见的 Kubernetes 行为关联了起来。


