介绍
上一个实验重点介绍了日志和事件。它们是排查问题的初步信号,但有时你还需要检查正在运行的容器,或者从终端临时访问某个服务。Kubernetes 为此提供了两个常用工具:kubectl exec 和 kubectl port-forward。
在本实验中,你将部署一个小型 Web 应用,使用 kubectl exec 检查 Pod 内部的文件和进程,并使用 kubectl port-forward 建立到该服务的临时本地连接。实验流程经过简化,旨在让你专注于调试技术本身,而非应用的复杂性。
准备调试命名空间
在此步骤中,你将准备一个干净的命名空间,用于练习 exec 和端口转发。
首先进入 /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 就绪。端口转发依赖于 API 服务器连接,但应用本身仍需要健康的 Pod 和 Service。
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
预期输出:
pod/calico-node-... condition met
创建一个名为 ckad-prep-debug 的命名空间,并将其设置为当前命名空间:
kubectl create namespace ckad-prep-debug
kubectl config set-context --current --namespace=ckad-prep-debug
确认当前命名空间:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
预期输出:
ckad-prep-debug
部署小型 Web 应用
在此步骤中,你将部署一个简单的应用以供检查和访问。
该 Pod 会写入一个 index.html 文件,并在 8080 端口运行 BusyBox httpd 服务。一个名为 debug-web 的 Service 会在集群内将 Pod 暴露在 80 端口。之所以包含 Service,是因为 kubectl port-forward 既可以针对 Pod,也可以针对 Service。
创建 debug-web.yaml:
cat > debug-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: debug-web
spec:
replicas: 2
selector:
matchLabels:
app: debug-web
template:
metadata:
labels:
app: debug-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
mkdir -p /www
echo "debug-web-ready" > /www/index.html
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 1
periodSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
name: debug-web
spec:
selector:
app: debug-web
ports:
- port: 80
targetPort: 8080
EOF
应用清单并等待 Deployment 就绪:
kubectl apply -f debug-web.yaml
kubectl rollout status deployment/debug-web --timeout=120s
预期输出包含:
deployment.apps/debug-web created
service/debug-web created
deployment "debug-web" successfully rolled out
检查 Pod 和 Service:
kubectl get pods -l app=debug-web
kubectl get service debug-web
预期输出包含两个 Running 状态的 Pod 和一个 ClusterIP 类型的 Service:
debug-web-... 1/1 Running
debug-web ClusterIP
使用 exec 检查运行中的容器
在此步骤中,你将使用 kubectl exec 在应用 Pod 内部运行命令。
当 Pod 正在运行但你需要检查容器内部状态时,kubectl exec 非常有用。它不能替代日志,也不应在正常部署期间用于进行隐蔽的手动修复。在调试工作流中,它可以帮助你从容器内部确认文件、进程、环境变量以及本地网络行为。
将一个 Pod 名称存储到 shell 变量中:
POD_NAME="$(kubectl get pods -l app=debug-web -o jsonpath='{.items[0].metadata.name}')"
echo "$POD_NAME"
预期输出为一个 Pod 名称:
debug-web-...
在容器内运行 hostname。输出应与 Pod 名称匹配,因为 Kubernetes 会根据 Pod 名称设置容器的主机名。
kubectl exec "$POD_NAME" -- hostname
预期输出:
debug-web-...
列出容器内正在运行的进程:
kubectl exec "$POD_NAME" -- ps
预期输出包含 httpd 进程:
PID USER TIME COMMAND
... root ... httpd -f -p 8080 -h /www
读取 Web 服务器提供的文件:
kubectl exec "$POD_NAME" -- cat /www/index.html
预期输出:
debug-web-ready
最后,从同一个容器内部测试 Web 服务器:
kubectl exec "$POD_NAME" -- wget -qO- http://127.0.0.1:8080
预期输出:
debug-web-ready
使用端口转发测试 Service
在此步骤中,你将使用 kubectl port-forward 从终端访问 Service。
端口转发会创建一个从本地端口到集群中 Pod 或 Service 的临时隧道。它对于快速调试非常有用,因为它不需要更改 Service 类型、创建 Ingress 或开放外部访问。前台运行的 kubectl port-forward 命令会一直运行直到你停止它,因此本实验将其在后台启动,进行测试,然后再将其停止。
启动从本地端口 18080 到 Service 端口 80 的端口转发。输出被写入 /tmp/debug-web-port-forward.log,以便终端保持可用。
kubectl port-forward service/debug-web 18080:80 > /tmp/debug-web-port-forward.log 2>&1 &
PF_PID=$!
sleep 3
cat /tmp/debug-web-port-forward.log
预期输出包含:
Forwarding from 127.0.0.1:18080 -> 8080
通过本地转发的端口发送请求:
wget -qO- http://127.0.0.1:18080
预期输出:
debug-web-ready
停止后台的端口转发进程。此清理步骤很重要,否则本地端口将保持被占用状态。
kill "$PF_PID"
wait "$PF_PID" 2>/dev/null || true
确认端口转发日志记录了已处理的连接:
cat /tmp/debug-web-port-forward.log
预期输出包含:
Handling connection for 18080
总结
你练习了两种实用的调试工具。你使用了 kubectl exec 来检查运行中容器的主机名、进程、文件以及 localhost 的 HTTP 响应。你还使用了 kubectl port-forward 创建了到 ClusterIP Service 的临时本地连接,从终端进行了测试,并干净地停止了后台转发进程。


