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 サーバーに到達可能か確認します。VM が起動した直後でノードの準備ができていない場合は、数秒待ってから再度コマンドを実行してください。

kubectl get nodes --request-timeout=5s

期待される出力例:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

クラスターのネットワーク用 Pod が「Ready」になるまで待ちます。ポートフォワードは API サーバーへの接続を使用しますが、アプリケーションには健全な Pod とサービスが必要です。

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 という名前のサービスが、クラスター内の Pod をポート 80 で公開します。kubectl port-forward は Pod だけでなくサービスもターゲットにできるため、サービスを含めています。

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

マニフェストを適用し、デプロイメントの完了を待ちます。

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 とサービスを調査します。

kubectl get pods -l app=debug-web
kubectl get service debug-web

2 つの実行中 Pod と ClusterIP サービスが表示されるはずです。

debug-web-...   1/1   Running
debug-web       ClusterIP

exec を使用した実行中コンテナの調査

このステップでは、kubectl exec を使用してアプリケーション Pod 内でコマンドを実行します。

kubectl exec は、Pod が実行中であるものの、コンテナ内部で何が起きているかを確認する必要がある場合に便利です。これはログの代わりになるものではなく、通常のデプロイメント中に隠れた手動修正を行うために使用すべきではありません。デバッグのワークフローにおいては、コンテナ内部からファイル、プロセス、環境変数、ローカルネットワークの挙動を確認するのに役立ちます。

Pod 名をシェル変数に格納します。

POD_NAME="$(kubectl get pods -l app=debug-web -o jsonpath='{.items[0].metadata.name}')"
echo "$POD_NAME"

Pod 名が 1 つ出力されます。

debug-web-...

コンテナ内で hostname を実行します。Kubernetes はコンテナのホスト名を Pod 名から設定するため、出力は 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

ポートフォワードを使用したサービスのテスト

このステップでは、kubectl port-forward を使用してターミナルからサービスにアクセスします。

ポートフォワードは、ローカルポートからクラスター内の Pod やサービスへの一時的なトンネルを作成します。サービスのタイプを変更したり、Ingress を作成したり、外部アクセスを開放したりすることなく、迅速にデバッグできるため非常に便利です。フォアグラウンドで実行される kubectl port-forward コマンドは停止するまで実行され続けるため、この実験ではバックグラウンドで起動し、テスト後に停止させます。

ローカルポート 18080 からサービスポート 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

まとめ

実用的な 2 つのデバッグツールを練習しました。kubectl exec を使用して、実行中のコンテナのホスト名、プロセス、ファイル、およびローカルホストの HTTP レスポンスを調査しました。また、kubectl port-forward を使用して ClusterIP サービスへの一時的なローカル接続を作成し、ターミナルからテストを行い、バックグラウンドの転送プロセスをクリーンに停止させました。