使用 exec 和端口转发进行调试

KubernetesBeginner
立即练习

介绍

上一个实验重点介绍了日志和事件。它们是排查问题的初步信号,但有时你还需要检查正在运行的容器,或者从终端临时访问某个服务。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 的临时本地连接,从终端进行了测试,并干净地停止了后台转发进程。