kubectl で Kubernetes リソースを調査する

KubernetesBeginner
オンラインで実践に進む

はじめに

Kubernetes for Beginners では、kubectl get、describe、ラベルを使ってアプリケーションが正常に動作しているかを確認しました。実際のクラスターには多数のオブジェクトが存在するため、次に身につけるべきスキルは、より絞り込んだ質問を行い、必要な証拠だけを取り出すことです。

この実験では、小規模なストアフロントワークロードをデプロイし、Namespace、ラベル、構造化フィールド、コントローラーの所有関係、イベントという複数の観点から調査します。最後に、Deployment とそれが管理する Pod を結び付ける簡潔なコマンドを完成させます。

すべての出力形式を暗記する必要はありません。代わりに、質問を絞り込んだクエリへ変換する練習をします。「どのオブジェクトが存在するか」「この Service に一致する Pod はどれか」「この Pod の所有者は誰か」「最近何が起きたか」といった問いを考えます。各ステップで、この調査ワークフローに新しいツールを一つずつ加えていきます。

調査用の作業領域を作成する

このステップでは、Namespace を作成し、用意されているリソースをそこへデプロイします。Namespace によって後続のクエリの対象範囲を絞り、同じような名前のオブジェクトを取り違えるのを防げます。

実験用の作業ディレクトリへ移動し、クラスターの状態を変更する前に現在のコンテキストを確認します。cd はシェルの作業ディレクトリを変更するため、以降の storefront.yaml などの相対パスは、用意された作業ディレクトリを基準に解決されます。

cd /home/labex/project/resource-inspection
kubectl config current-context

出力は labex-v135 になるはずです。Namespace を作成し、用意されている複数ドキュメント形式のマニフェストを適用します。

kubectl create namespace practice-observe
kubectl apply -f storefront.yaml
kubectl rollout status deployment/storefront -n practice-observe --timeout=60s

最後の数行は次のようになります。2 つの Pod が起動するまでの間に、中間的なロールアウトメッセージが表示される場合があります。

namespace/practice-observe created
deployment.apps/storefront created
service/storefront created
deployment "storefront" successfully rolled out

-n practice-observe は、コマンドの対象をその Namespace に限定します。ロールアウトコマンドは、任意の時間だけ待つのではなく、Deployment の 2 つのレプリカが利用可能になるまで待機します。

以降、-n practice-observe を繰り返し使用します。特に指定しない場合、Kubernetes コマンドは現在のコンテキストで設定されている Namespace(通常は default)を使用します。そのため、実際には正常なオブジェクトでも、誤った対象範囲を検索した結果「見つからない」ように見えることがあります。

リソースと対象範囲を確認する

このステップでは、オブジェクトを検索する前に API のディスカバリーを行います。kubectl api-resources は、現在の API サーバーが認識しているリソース名を、短縮名や Namespace に属するリソースかどうかの情報とともに一覧表示します。head へのパイプによって、広範な一覧の先頭 10 行だけを表示し、端末が大量の出力で埋まるのを防ぎます。

kubectl api-resources | head
kubectl api-resources --namespaced=true | grep -E 'pods|deployments|services'

パイプによって、リソース一覧が grep に渡されます。-E は | による選択肢の指定を有効にするため、1 つのコマンドで複数のリソース名に一致させられます。Pod、Deployment、Service が Namespace に属するリソースであることを確認してください。

アプリケーションのオブジェクトを正式なリソース名で一覧表示し、続けて一般的な短縮名を使って同じ検索を行います。

kubectl get pods,deployments,services -n practice-observe
kubectl get po,deploy,svc -n practice-observe

この 2 つのコマンドは、同じ API リソースを対象にしています。短縮名を使うと入力を減らせますが、スクリプトやドキュメントでは正式な名前のほうが分かりやすくなります。

Deployment が 1 つ、生成された Pod が 2 つ、Service が 1 つ表示されることを確認してください。カンマ区切りのリソース指定は、あくまで検索を簡潔にするためのものです。これらのオブジェクトは、それぞれ異なる役割と API スキーマを持っています。

出力にはリソース種別の接頭辞が付くため、混在した結果でも解釈しやすくなります。生成されたサフィックス、アドレス、経過時間は環境によって異なります。

NAME                              READY   STATUS    RESTARTS   AGE
pod/storefront-...                1/1     Running   0          ...
pod/storefront-...                1/1     Running   0          ...

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/storefront   2/2     2            2           ...

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/storefront   ClusterIP   ...          <none>        80/TCP    ...

ラベルとセレクターで絞り込む

このステップでは、ラベルを検索可能なメタデータとして利用します。--show-labels はすべてのラベルを表示し、-l は式に一致するラベルを持つオブジェクトだけを選択します。

kubectl get pods -n practice-observe --show-labels
kubectl get pods -n practice-observe -l app=storefront
kubectl get pods -n practice-observe -l 'app=storefront,tier=web'

セレクターの条件をカンマで区切ると、論理 AND として扱われます。そのため、最後のクエリでは両方のラベルを持つ Pod が返されます。

Service のセレクターと、選択された Pod のラベルを比較します。

kubectl get service storefront -n practice-observe -o jsonpath='Service selector: {.spec.selector.app}{"\n"}'
kubectl get pods -n practice-observe -l app=storefront -o custom-columns='NAME:.metadata.name,TIER:.metadata.labels.tier,IP:.status.podIP,READY:.status.containerStatuses[0].ready'
kubectl get endpointslices -n practice-observe -l kubernetes.io/service-name=storefront

JSONPath は Service から 1 つのフィールドを抽出します。-o custom-columns は、複数の Pod フィールドから簡潔な表を生成します。大きな YAML ドキュメントを目視で検索するよりも、確実に必要な情報を取り出せます。

最後のコマンドは、自動的に管理される kubernetes.io/service-name ラベルの値が storefront である EndpointSlice を検索します。EndpointSlice には、Service が選択したネットワークエンドポイントが記録されます。ENDPOINTS 列が空でなければ、一致するラベルによって到達可能なバックエンドが生成されたことを確認できます。

Service のセレクターには storefront と表示され、Pod の表の 2 行には tier=web が設定されているはずです。一致する app ラベルが接続点です。Service は Deployment の所有関係ではなく、ラベルを通じて Pod を検出します。

Service selector: storefront
NAME             TIER   IP          READY
storefront-...   web    10.244...   true
storefront-...   web    10.244...   true

NAME             ADDRESSTYPE   PORTS   ENDPOINTS                  AGE
storefront-...   IPv4          80      10.244...,10.244...          ...

コントローラーの所有関係を追跡する

このステップでは、Deployment から ReplicaSet、さらに Pod へと Kubernetes の所有関係をたどります。コントローラーは ownerReferences を設定することで、どの上位オブジェクトが各依存オブジェクトを管理しているかを Kubernetes に伝えます。

kubectl get replicasets -n practice-observe -l app=storefront
kubectl get replicasets -n practice-observe -l app=storefront -o custom-columns='REPLICASET:.metadata.name,OWNER_KIND:.metadata.ownerReferences[0].kind,OWNER_NAME:.metadata.ownerReferences[0].name'
kubectl get pods -n practice-observe -l app=storefront -o custom-columns='POD:.metadata.name,OWNER_KIND:.metadata.ownerReferences[0].kind,OWNER_NAME:.metadata.ownerReferences[0].name'

ReplicaSet の所有者は storefront Deployment になっているはずです。各 Pod の所有者は、Deployment ではなく、生成された ReplicaSet です。

Deployment/storefront -> ReplicaSet/storefront-... -> Pod/storefront-...

条件や最近のイベントと併せてこの関係を確認したい場合は、kubectl describe を使用します。

kubectl describe deployment storefront -n practice-observe

毎回 describe の出力を最初から最後まで読む必要はありません。この問いに対しては、Selector、レプリカ数、条件、イベントに注目してください。優れた調査コマンドとは、ノイズを最小限に抑えながら、その時点の問いに答えられるコマンドです。

イベントを時系列で読む

このステップでは、時系列に並べた証拠としてイベントを調査します。イベントにはスケジューリング、イメージ、コンテナ、コントローラーの動作が記録されます。ただし、イベントは一時的な診断情報であり、永続的な監査記録ではありません。

kubectl get events -n practice-observe --sort-by=.metadata.creationTimestamp

--sort-by は、フィールドパスを使ってオブジェクトを並べ替えます。まず Deployment に関するイベントに絞り、次に選択した 1 つの Pod を対象にします。

kubectl events -n practice-observe --for deployment/storefront
POD_NAME=$(kubectl get pods -n practice-observe -l app=storefront -o jsonpath='{.items[0].metadata.name}')
echo "$POD_NAME"
kubectl events -n practice-observe --for "pod/${POD_NAME}"

$(...) はコマンド置換です。シェルが内部のコマンドを実行し、その出力を POD_NAME に保存します。これで、Namespace を絞り、ラベルで選択し、フィールドを抽出し、所有関係を追跡し、最後に関連するイベントの時系列を確認するという、再利用可能な調査手順が整いました。

コントローラーが生成する Pod 名は、置き換えが発生すると変わります。そのため、古い値をコピーするよりも、ラベルで現在の名前を取得するほうが安全です。このパターンは、以降のトラブルシューティング実験でも繰り返し登場します。

通常、正常なライフサイクルには Scheduled、Pulled、Created、Started が含まれます。起動直後のローカルクラスターでは、Calico の準備が整うまでの FailedCreatePodSandBox など、以前の警告が残っている場合もあります。古い警告だけを見て、アプリケーションがまだ壊れていると判断しないでください。警告のタイムスタンプを後続の正常なイベントと比較し、そのうえで Pod の現在の READY 状態を確認します。タイムスタンプと生成された Pod 名は、実行のたびに変わるため意図的に省略されています。

まとめ

関係のないオブジェクトを調べることなく、Kubernetes アプリケーションを調査しました。Namespace、ラベル、JSONPath、カスタム列、所有者参照、イベントを組み合わせ、広範なインベントリから正確な運用上の証拠へと絞り込みました。次の実験では、この調査ワークフローを問題のある Pod とコンテナに適用します。