プライベート GKE ノードは kubectl が使う API を決めない
ノードへの SSH、API 呼び出し、ログ配信はそれぞれ別の経路を通る。プライベートノードのアドレスから何かを推測する前に、kubeconfig のサーバー URL を読むこと。
ノードはプライベートで、VPN はそこに届いているのに、kubectl はクラスターと通信できない。この二つの事実は無関係だ。kubectl が使うアドレスは、認証情報を取得したときに kubeconfig へ保存されたサーバー URL から来ており、追加したルートで変わるものではない。そもそも kubectl が到達しようとしているのはノードではない。
五つの確認を、意味のある唯一の値から始める。
確認 1: kubeconfig のサーバー URL を読む
認証情報を吐き出さずにエンドポイントを表示する: kubectl config view --minify -o jsonpath="{.clusters[0].cluster.server}"。この一行で、クライアントが IP アドレス、DNS 名、あるいは意図しない外部アドレスのどれを指しているかが分かる。この調査の残りはすべてそこから導かれる。
URL が設定したつもりのエンドポイントでなければ、残りの診断は気を散らすだけだ。
確認 2: URL をエンドポイントの種類と照合する
現在の GKE は IP ベースと DNS ベースの両方のコントロールプレーン アクセスをサポートしており、取得する認証情報がどちらかを選ぶ。gcloud container clusters get-credentials NAME --location REGION --internal-ip は内部 IP のエンドポイントを書き込み、--dns-endpoint は DNS ベースのアクセスを選ぶ。どちらのフラグもネットワーク経路を用意しないため、取得すれば接続が直ると期待する人は驚く。意図して取得をやり直し、そのあと URL をもう一度読む。
URL を読み直さずにフラグを変えると、ノート PC は二つのクラスターの認証情報と一つの不可解なエラーを抱えることになる。
許可ネットワークのエントリは外部エンドポイントに誰が到達できるかを決めるもので、内部エンドポイントには適用されない。プライベート経路を試すために広げるのは、診断ではなく露出を変えることになる。
確認 3: そのエンドポイントへの経路を証明する
URL が内部 IP なら、クライアントが実際にいるネットワークからの経路、許可された送信元範囲、クラスターのリージョンまたはグローバル アクセス設定を確認する。コントロールプレーンの範囲とノードのサブネットは同じ宛先ではないので、ノードへの経路が通ってもエンドポイントについては何も証明できない。DNS ベースのアクセスでは、経路は文書化された Private Google Access を伴う Google API への接続であり、ワーカーのサブネットへの経路ではない。kubectl を責める前に、平易な TCP 接続でエンドポイントを試すこと。
タイムアウトは経路の問題だ。403 はポリシーの問題だ。両者に共通の修正はない。
確認 4: ログと exec を API 呼び出しから切り分ける
通常の API リクエストが成功するのに kubectl logs や kubectl exec が失敗するなら、すでにエンドポイント選択は通過している。これらの操作には対応する Kubernetes の権限が必要で、コントロールプレーンからノードへの通信に依存しており、失敗はタイムアウトではなく Forbidden 応答であることもある。ノードへの SSH アクセスはまったく別のサービスを試すもので、これらを確立しない。
VPN チケットを開き直す前に、二つの分類は別の場所に住んでいるのだから、エラーの分類を読むこと。
確認 5: 次の人のために三つの観察を残す
選ばれた API URL、許可された API リクエストが一つ通るかどうか、そして正確にどの後続操作が失敗するのかを、エラー文とともに記録する。この三行がエンドポイント選択とノード アクセスを分け、まったく正常な VPN 経路が運んでいないリクエストのせいにされるのを防ぐ。
次のエンジニアはトンネルが壊れているのかと尋ねる。あなたのメモがすでにそれに答えているはずだ。