冒頭まとめ

kubectl get podsなどを実行したとき、次のエラーが出ることがあります。

Unable to connect to the server: dial tcp: lookup api.example.com: no such host
The connection to the server 127.0.0.1:6443 was refused - did you specify the right host or port?

どちらもkubectlからKubernetes APIサーバーへ接続できていません。ただし、直す場所は後半の文言によって異なります。

後半の文言最初に疑う場所
connection refusedAPIサーバーの停止、ホスト、ポート
no such hostDNS、VPN、kubeconfig内のホスト名
i/o timeout、TLS handshake timeout経路、VPN、ファイアウォール、負荷
x509:、tls:CA証明書、接続先名、証明書の期限
no configuration has been providedkubeconfigの有無と読み込み元

最初に、kubectlが選んでいるcontextとAPIサーバーのURLを確認してください。

kubectl config current-context
kubectl config view --minify
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}'

想定外のクラスターが表示された場合は、ネットワークを調べる前にkubeconfigの読み込み元を直します。

Unable to connect to the serverとは

kubectlは、kubeconfigからAPIサーバーの場所、接続に使う認証情報、現在のcontextを読み取ります。その情報を使って接続を試み、名前解決、TCP接続、TLS接続などの段階で失敗すると、Unable to connect to the serverが表示されます。

kubectlの実装では、接続時のエラーがconnection refusedを含む場合だけ、次の専用メッセージへ変換します。

The connection to the server <host>:<port> was refused - did you specify the right host or port?

それ以外の接続エラーは、元の原因を後ろに付けた次の形式になります。

Unable to connect to the server: <接続に失敗した理由>

したがって、Unable to connect to the serverだけを見ても原因は決まりません。コロン以降にあるno such host、timeout、tlsなどを省略せずに確認することが重要です。

なお、これはPodやDeploymentのエラーではありません。kubectlがAPIサーバーへ到達する前後で止まっているため、kubectl logsやPodの再起動では解決できません。

kubeconfigとcontextを確認する

kubectlが接続に使う情報はkubeconfigにあります。まず、利用できるcontextと現在選ばれているcontextを確認します。

kubectl config get-contexts
kubectl config current-context
kubectl config view --minify

--minifyを付けると、現在のcontextに関係するclusterとuserへ表示を絞れます。server:に書かれたURLが、接続したいクラスターのAPIサーバーか確認してください。

kubeconfigの読み込み規則は次の順序です。

  1. --kubeconfigを指定した場合は、その1ファイルだけを使う
  2. KUBECONFIG環境変数がある場合は、列挙されたファイルをマージする
  3. どちらもない場合は、通常$HOME/.kube/configを使う

この規則はKubeconfigファイルを使用したクラスターアクセスの構成に記載されています。

LinuxまたはmacOSでは、環境変数を次のように確認できます。

printf '%s\n' "$KUBECONFIG"
ls -l "$HOME/.kube/config"

Windows PowerShellでは次を使います。

$Env:KUBECONFIG
Test-Path "$HOME\.kube\config"

KUBECONFIGには複数のファイルを指定できます。区切りはLinuxとmacOSではコロン、Windowsではセミコロンです。複数ファイルに同名のclusterやuserがあると、マージ結果が想定と異なることがあります。

確認のために特定のファイルだけを使う場合は、--kubeconfigを明示します。

kubectl --kubeconfig=/path/to/config config view --minify
kubectl --kubeconfig=/path/to/config get nodes

この指定で接続できるなら、クラスターではなく、通常実行時に読み込まれているkubeconfigやcontextが原因です。

error: no configuration has been providedやcluster has no server definedが出る場合は、TCP接続より前に設定の読み込みで止まっています。クラスター管理者または利用しているクラウド・ローカルクラスターの公式手順から、kubeconfigを取得し直してください。入手元が不明なkubeconfigは、認証プラグインなどを通じてコードを実行する可能性があるため使用しないでください。

connection refusedの対処

次の文言は、指定されたホストとポートへのTCP接続が拒否された場合に表示されます。

The connection to the server <host>:<port> was refused - did you specify the right host or port?

名前解決や経路が完全に失敗した場合とは異なり、接続先から拒否が返っています。主な原因は、APIサーバーが停止している、kubeconfigのポートが古い、クラスターを作り直したのに以前の接続先を参照している、といったものです。

まず、現在の接続先を取り出します。

kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}'

localhost:8080や、削除済みクラスターのIPアドレスが出る場合は、正しいkubeconfigを取得し直します。minikubeなどのローカルクラスターを使っている場合は、クラスター自体が起動しているかも確認してください。

管理対象のクラスターなら、control planeやAPIサーバー前段のロードバランサーが正常かを管理画面や監視から確認します。利用者側から接続できないという理由だけで、control planeを再起動しないでください。VPN、接続元制限、誤ったcontextでも同じように利用不能になるためです。

no such host・timeoutの対処

次の文言は、kubeconfigに書かれたホスト名をDNSで解決できない場合に出ます。

Unable to connect to the server: dial tcp: lookup api.example.com: no such host

APIサーバーのURLを確認し、そのホスト名が現在の環境から解決できるか調べます。

kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}'
nslookup api.example.com

社内DNSやプライベートDNSでのみ解決できるホストなら、VPNへ接続してから再確認します。クラスターを再作成したあとに古いホスト名が残っている場合は、DNS設定を手作業で書き換えるのではなく、正しいkubeconfigを取得し直してください。

i/o timeoutやTLS handshake timeoutの場合は、接続先へ応答が返る前に制限時間を超えています。VPN、ファイアウォール、プロキシ、APIサーバー前段のロードバランサーを確認します。

到達性だけを確認したい場合は、kubeconfigに表示されたURLを使い、短い接続時間で試します。

curl --connect-timeout 5 https://api.example.com:6443/readyz

認証情報を付けていないため、401 Unauthorizedや403 Forbiddenが返る場合があります。ただし、その応答が返るならDNS、TCP、TLSの接続は少なくとも成立しています。

自己署名証明書などでcurlの検証だけが失敗する場合、経路の確認に限って-kを使う方法もあります。

curl -k --connect-timeout 5 https://api.example.com:6443/readyz

-kはサーバー証明書の検証を無効にします。中間者攻撃を検出できなくなるため、恒久的な設定や通常のAPI操作には使用しないでください。kubectl側のTLS検証を無効にする解決策でもありません。

TLSエラーの対処

Unable to connect to the server:の後ろにx509:やtls:がある場合は、APIサーバーには接続を試みていますが、証明書の検証またはTLSハンドシェイクに失敗しています。

よくある原因は次のとおりです。

  • クラスターを再作成したため、kubeconfig内のCAが古い
  • 証明書の有効期限が切れている
  • kubeconfigの接続先名と証明書の対象名が一致しない
  • 途中のプロキシが別の証明書を返している

kubeconfig内の接続先と証明書設定を確認します。

kubectl config view --minify

certificate-authorityまたはcertificate-authority-dataと、serverの組み合わせが同じクラスターから取得されたものか確認してください。クラスターを作り直した場合は、古いCAだけを残して接続先を手作業で変えるのではなく、kubeconfig一式を再取得します。

insecure-skip-tls-verify: trueを恒久的に設定すると、kubectlが接続先の正当性を確認できなくなります。原因調査を省略するための対処としては使わないでください。

証明書が正しく、その後にUnauthorizedやForbiddenへ変わった場合は、接続自体は成立しています。次にトークン、クライアント証明書、exec認証プラグイン、RBACを調べます。

似たエラーとの違い

error: You must be logged in to the server (Unauthorized)は、APIサーバーへ到達したあとに認証で拒否されたエラーです。kubeconfigの接続先ではなく、認証情報の期限やログイン状態を確認します。

Error from server (Forbidden)は認証された利用者に操作権限がない状態です。接続障害ではなく、RBACなどの認可設定を確認します。

Error from server (NotFound)やthe server could not find the requested resourceは、APIサーバーから応答を受け取っています。リソース名、namespace、APIの種類やバージョンが調査対象です。

error: no configuration has been providedは、接続を試す前にkubeconfigを読み込めなかったエラーです。Unable to connect to the serverとは発生段階が異なります。

PodのPending、CrashLoopBackOff、ImagePullBackOffは、APIサーバーへ接続したあとに確認できるワークロード側の状態です。kubectl自体が接続できない今回のエラーとは分けて考えます。

解決手順のまとめ

最初にkubectl config current-contextとkubectl config view --minifyを実行し、kubectlが選んでいるクラスター、利用者、APIサーバーのURLを確認します。

設定が違う場合は、--kubeconfig、KUBECONFIG、$HOME/.kube/configの読み込み規則を確認してください。新しい端末、コンテナ、CIでは、kubeconfigや認証プラグインを渡していないことがあります。

接続先が正しければ、後半の文言に従って切り分けます。connection refusedはAPIサーバーとポート、no such hostはDNSとVPN、timeoutは経路とファイアウォール、x509やtlsは証明書と接続先名を確認します。

curl -kやinsecure-skip-tls-verifyで警告を消すことを解決策にしないでください。TLS検証を外して到達性を確認した場合も、最終的には正しいCAとkubeconfigでkubectlが接続できる状態へ戻す必要があります。

免責事項:本記事の内容は一般的なKubernetes環境を前提としています。kubeconfigには認証情報や外部コマンドの設定が含まれる場合があります。共有、公開、編集を行う前に内容を確認し、TLS検証やアクセス制御を無効化しないでください。