Ubuntuでkubeletの10250番ポートエラーを解決
kubeadm initで「address already in use」が出る原因と対処法、kubectl logsやexecを妨げるファイアウォールのTCP 10250番ポート遮断を確認します。
ポート 10250 について
ポート 10250 は kubelet API です。このポートに関するエラーは、正反対の 2 つの問題のいずれかを示します。すでに別のプロセスがポートを使用しているため、kubeadm init が起動できない場合があります。または、ポートに到達できないため、正常に見えるノードに対して kubectl logs と kubectl exec が失敗する場合があります。
kubelet は、Kubernetes が各ノードで実行するエージェントです。コンテナを起動し、その状態を control plane に報告します。また、TCP 10250 で待ち受け、control plane から呼び出される HTTPS API を提供します。kubectl logs、kubectl exec、kubectl attach、kubectl port-forward を実行すると、API server はこのポートへの接続を開きます。metrics-server は同じポートで /metrics/resource を取得するため、kubectl top node が機能します。
この API では認証が必要です。kubeadm は匿名アクセスを無効にし、kubelet がクラスターの CA (certificate authority) を使用するように設定します。そのため、認証情報のないリクエストには Unauthorized が返され、コンテナ内の shell が開かれることはありません。この点を覚えておいてください。ポートに到達できることを確認する最も簡単な方法にもなるためです。Linux のポートについて初めて学ぶ場合は、Linux でポートが実際に何を意味するかで、このガイドが前提とする仕組みを説明しています。
2 つの障害は、1 つの要件から発生します。kubelet が起動する前にポート 10250 が空いている必要があります。また、kubelet の起動後は control plane から到達できなければなりません。
2 つの問題のどちらが発生していますか
対象の node で次のコマンドを実行します。以下のコマンドはすべて、自分のサーバー上で自分で実行するものです。
sudo ss -lntp | grep 10250
sudo systemctl status kubelet --no-pagerss -lntp は、各 TCP ソケットの待ち受け状態と、そのソケットを使用するプロセスを表示します。-l は待ち受け中のソケットに限定し、-n はポート番号を数値で表示し、-t は TCP に限定し、-p は所有プロセスを表示します。最後のフラグには root 権限が必要です。権限がないとプロセス列が空になり、原因を確認できません。
users:(("kubelet",pid=1043,fd=23)) で終わる行は、kubelet が実行中で、そのポートを使用していることを示します。ポートが空いているはずなら、それが答えです。ss に何も表示されず、それでも control plane からこの node に接続できない場合、まだ firewall は関係ありません。そもそもポートを待ち受けるプロセスがないためです。ルールを変更する前に、kubelet が停止している理由を調べてください。
systemctl status kubelet で状況のもう一方の側を確認できます。数分前の開始時刻とともに active (running) が表示されるのは正常です。kubeadm init または kubeadm join を実行する前に kubelet が数秒ごとに再起動していても正常です。パッケージに含まれる unit はインストール時に起動しますが、設定が見つからないため終了します。Upstream のドキュメントでは、kubelet が kubeadm からの指示を待つ間、この crash loop は想定された動作とされています。systemd の再起動動作に慣れていない場合は、このセクションの背景として systemd のサービス種別と再起動ポリシーの仕組み を参照してください。
kubeadm init の実行時にポート 10250 がすでに使用中になる理由
kubeadm init は、ディスクに何も書き込む前に事前チェックを実行します。チェックの1つでは、control plane に必要な各ポートへの bind を試行します。bind に失敗すると、10250 番ポートを示すエラーを出して停止します。これはバグではありません。kubeadm init は、以前のクラスターの残存状態の上に2つ目のクラスターを構築することを拒否しています。
実際には、次の4つが原因になります。
- 途中で失敗した以前の
kubeadm initまたはkubeadm join。kubelet にはすでに設定が与えられているため、実行中の kubelet がポートを保持しています。 - 開始したものの完了していない
kubeadm reset。reset は kubelet を停止しますが、unit を無効化しません。そのため、次回の再起動時に listener が再び起動します。 - 同じサーバーにインストールされた k3s または別の Kubernetes ディストリビューション。k3s には kubelet が組み込まれており、その kubelet も 10250 番ポートを bind します。
- apt によってインストールされ、独自の systemd unit で起動された
kubeletパッケージ。kubeadm をまだ実行していないサーバーでも発生します。
変更を加える前に、どれが原因かを確認します。
sudo ss -lntp 'sport = :10250'
systemctl list-units --type=service --state=running | grep -Ei 'kubelet|k3s|k0s'listener が k3s に属している場合は、k3s を停止し、実際に使用するクラスターを決めます。k3s と kubeadm は同じサーバー上で共存できません。同じポートと同じ CNI (container network interface) ディレクトリを使用するためです。k3s の installer は、server node では /usr/local/bin/k3s-uninstall.sh に、agent node では k3s-agent-uninstall.sh にアンインストールスクリプトを残します。
kubelet を停止してもポートが解放されない理由
sudo pkill kubeletを実行すると、ポート10250は約10秒間解放されます。パッケージで提供される unit には再起動ポリシーが設定されているため、systemd が新しい kubelet を起動し、再び同じポートをバインドします。設定は次のコマンドで確認できます。
systemctl show kubelet -p Restart -p RestartSec
sudo systemctl stop kubelet
sudo ss -lntp | grep 10250Restart=alwaysにRestartSec=10が指定されているのは、unit にこの設定が含まれているためです。そのため、killは一度成功したように見えても、実際には成功しません。ポートを解放する正しい方法はsystemctl stopです。停止を指示した unit については、systemd が再起動を続けないためです。
ポートが解放されても、クラスタの半分を担う node では十分ではありません。/var/lib/kubelet/config.yaml、/etc/kubernetes/pki配下の証明書、/etc/kubernetes/manifestsにある static pod のマニフェストは、すべて残っています。後続の preflight check はこれらのファイルにより失敗します。check を強制的に通過させると、証明書と設定が一致しないクラスタになります。node は正しい手順で reset してください。
ノードをクリーンにリセットする
sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d
rm -rf $HOME/.kube
sudo systemctl stop kubelet
sudo ss -lntp | grep -E '10250|6443|2379'-f は確認プロンプトを省略します。リセットでは、init または join が行った変更を可能な範囲で元に戻します。ローカルファイルと設定を削除し、control plane node 上のローカル etcd member を削除し、/etc/kubernetes/pki 内の証明書を消去して、kubelet の設定とマニフェストを削除します。
ドキュメントには、リセット後に残るものが明記されています。どれも見落としやすい項目です。/etc/cni/net.d は消去されないため、古い CNI plugin の設定が残り、新しい cluster がそれを読み込みます。kube-proxy が host に適用した iptables、nftables、IPVS のルールも消去されません。$HOME/.kube には影響しないため、kubectl は存在しなくなった cluster への通信を続け、別の問題に見える証明書エラーを返します。
残ったパケットルールの処理が難しい点です。手動でテーブルをフラッシュすると、ufw がインストールしたルールも消去されます。Ubuntu の ufw は同じ backend を介して書き込むためです。その結果、sudo ufw reload を実行するまでサーバーがフィルタリングされない状態になります。再構築する node であれば、リセット後に再起動してください。再起動すると kube-proxy が追加したランタイムルールが消去されます。中途半端にフラッシュされたルールセットを手作業で整理するより、時間を節約できます。iptables ルールと nftables ルールが互いの出力に表示される理由では、内部で何が起きているかを説明しています。
最後の ss コマンドは何も出力しないはずです。10250、6443、2379 で待ち受ける listener がなければ、node は新しい kubeadm init を構築できる状態です。
kubectl logs と kubectl exec がポート 10250 でタイムアウトする理由
これは逆の問題です。ポートの問題としては現れません。クラスターは起動します。ノードは Ready です。Pod も実行されます。その後、1 つのコマンドが失敗します。
Error from server: Get "https://10.0.0.12:10250/containerLogs/default/web-0/web": dial tcp 10.0.0.12:10250: i/o timeoutこのメッセージは末尾から読みます。API server はノードのポート 10250 への TCP 接続を開こうとしましたが、応答がありませんでした。i/o timeout はパケットが応答なしで破棄されたことを示します。つまり、何かが通信をフィルタリングしています。原因はノードのホストファイアウォール、またはプロバイダーの管理パネルにある別のネットワークファイアウォールです。同じ位置に connect: connection refused と表示される場合は、逆の意味です。パケットは到達しましたが、待ち受けているプロセスがありません。つまり kubelet が停止しています。これは connection refused と connection timed out の違い で説明した 2 つの原因と同じで、ここでは別のポートに対して発生しています。
この間もノードが Ready のままなのは、ノードの状態が逆方向に伝達されるためです。kubelet はポート 6443 で API server に外向きに接続し、自身のハートビートを送信します。これには 10250 への受信接続は必要ありません。そのため、10250 がブロックされても、クラスターは通常どおり Pod をスケジュールできます。一方で、logs、exec、port-forward、metrics だけが失敗します。
kubectl top node が error: Metrics API not available に応答する場合も、metrics-server を通して同じ障害が確認できます。metrics-server のログにはノードとポートが記録されます。
unable to fully scrape metrics from node worker-1: unable to fetch metrics from node worker-1: Get "https://10.0.0.12:10250/metrics/resource": dial tcp 10.0.0.12:10250: i/o timeoutファイアウォール規則を変更する前に経路をテストする
コントロールプレーンノードから、ワーカーのアドレスを指定して次を実行します。
nc -zv 10.0.0.12 10250
curl -sk -o /dev/null -w '%{http_code}\n' https://10.0.0.12:10250/healthznc -zは接続を確立して切断し、ポートが接続を受け付けると succeeded! を出力します。kubelet が実際にサービスを提供していることを確認できるため、ポートが単に開いていることしか確認できない方法よりも、curl の行によるテストの方が適しています。401 が出力されます。これが正常な結果です。TLS (transport layer security) ハンドシェイクが完了した後、kubelet が認証されていないリクエストを拒否しています。これは kubelet の正しい動作です。-k は証明書の検証をスキップします。ここでは信頼チェーンではなく、経路をテストしているため問題ありません。
長い待機の後にタイムアウトになる場合、パケットが破棄されています。curl: (7) Failed to connect が即座に返る場合は、到達可能なホスト上でポートが閉じています。テストはノート PC ではなく、コントロールプレーンノードから実行してください。ここで重要なのは、コントロールプレーンからのアクセスだけだからです。
コントロールプレーンとワーカーに必要なポート
以下は、upstream が一覧化している受信ポートです。コントロールプレーンノードでは、API server 用の TCP 6443 を、kubectl を実行するすべての対象に対して開放します。etcd のクライアント API と peer API 用の TCP 2379〜2380 は、API server と etcd 自身が使用します。kubelet API 用の TCP 10250 は、ノード自身とコントロールプレーンが使用します。kube-scheduler 用の TCP 10259 と kube-controller-manager 用の TCP 10257 は、どちらもノード自身だけが使用します。
ワーカーノードでは、kubelet API 用の TCP 10250 を、ノード自身とコントロールプレーンに対して開放します。kube-proxy 用の TCP 10256 は、ノード自身と、ヘルスチェックを実行するロードバランサーが使用します。NodePort サービス用の TCP および UDP 30000〜32767 はデフォルトの範囲です。これらのサービスを必要とする対象から到達できるようにします。
CNI plugin は、この一覧にない独自のポートを追加で使用します。Flannel と VXLAN モードの Calico では、ノード間に UDP 4789 が必要です。BGP を使用する Calico では、TCP 179 が必要です。CNI plugin のドキュメントを確認し、これらのポートをノード間で開放してください。開放しないと、このセクションのすべてのポートを開放していても、異なるノード上の pod 同士は通信できません。
インターネットに公開せずに 10250 を開く
kubelet API は、そのノード上の任意のコンテナ内でプロセスを起動できます。開放された 10250 はノードの root アクセスと同等に扱い、送信元アドレスで制限してください。どの送信元からも許可しないでください。
sudo ufw allow from 10.0.0.0/24 to any port 10250 proto tcp comment 'kubelet API'
sudo ufw allow from 10.0.0.0/24 to any port 10256 proto tcp comment 'kube-proxy'
sudo ufw status numbered10.0.0.0/24 を、ノード間で共有しているネットワークに置き換えてください。ufw status numbered は有効なルールをインデックス付きで表示するため、誤ったルールは sudo ufw delete <number> で削除できます。VPS の ufw 基礎では、どの設定が実際に適用されるかを決めるルールの順序を説明しています。
ufw の設定には、それだけで Kubernetes を動作不能にするものがあります。ノードをまたぐ Pod のトラフィックはローカルに配信されず、転送されます。ufw はデフォルトで転送パケットを破棄します。/etc/default/ufw に DEFAULT_FORWARD_POLICY="ACCEPT" を設定し、sudo ufw reload を実行してください。この設定がないと、10250 が広く公開され、ノード間の Pod 間トラフィックも失敗します。
プロバイダーのファイアウォールも確認してください。多くの VPS パネルには、サーバーの前段にネットワークレベルのファイアウォールがあり、ufw status からは見えません。パケットがサーバーに到達していなければ、ノード上で追加したルールは何も変更しません。
ポートに接続できるのにリクエストが失敗する場合
10250 番ポートへの接続がハングせず即座に失敗する場合、接続自体は成功し、リクエストが拒否されたことを示します。metrics-server のログに x509: certificate signed by unknown authority と表示される場合、kubelet はスクレーパーが信頼していない自己署名証明書を提供しています。通常は、kubelet の serving certificate rotation を有効にしてクラスタ CA で証明書に署名し、その後 certificate signing request を承認します。ラボ用クラスタでリスクを受け入れられる場合は、metrics-server を --kubelet-insecure-tls 付きで実行する方法もあります。
Forbidden と nodes/proxy または nodes/metrics を含むメッセージは、RBAC(role based access control)の失敗を示します。呼び出し元は kubelet まで到達しています。kubelet は、その identity が subresource を使用できるかどうかを API server に問い合わせ、API server は許可しませんでした。呼び出し元の ClusterRole を修正してください。ブロックされたものはないため、ファイアウォールを変更しても解決しません。
小規模なクラスターを1つだけ構築する場合
初めて単一の VPS で kubeadm を構築する際にこれらのエラーが発生するなら、そもそも kubeadm が必要かどうかを検討してください。VPS 上の単一ノード k3s クラスターを使えば、1つのコマンドで動作する Kubernetes API を利用できます。kubelet、kube-proxy、CNI はすでに連携済みです。そこでもポート 10250 は存在し、同じルールが適用されます。ただし、control plane を自分で組み立てる必要はありません。
FAQ
Kubernetes でポート 10250 は何に使用されますか?
これは、すべてのノード(control plane と worker の両方)で kubelet が提供する、認証付き HTTPS API です。API server はこの API に接続して kubectl logs、kubectl exec、kubectl attach、kubectl port-forward を実行します。metrics-server はこのポートから /metrics/resource を取得し、kubectl top を提供します。ノードの状態更新には使用されません。kubelet はポート 6443 の API server に対して、ハートビートを送信するためです。そのため 10250 がブロックされると、ログの取得や exec が失敗する一方で、ノードは Ready と表示されます。
ポート 10250 で何が待ち受けているかを確認するにはどうすればよいですか?
ノード上で sudo ss -lntp | grep 10250 を実行します。行末の users:((...)) フィールドに、プロセス名と PID が表示されます。sudo が重要です。root 以外で実行すると、プロセス列が空になるためです。所有者が kubelet の場合は、sudo systemctl status kubelet --no-pager で正常な kubelet か、ループして再起動している kubelet かを確認できます。所有者が k3s の場合、1 台のサーバーに 2 つの Kubernetes ディストリビューションがインストールされています。いずれか一方を削除する必要があります。
ファイアウォールでポート 10250 を開く必要がありますか?
はい。ノード間で開く必要があります。control plane は、自身を含むすべてのノードの 10250 に接続できなければなりません。接続できないと、ログ、exec、port-forward、metrics がすべて失敗します。送信元を、ノード間で共有するネットワークに制限してください。たとえば sudo ufw allow from 10.0.0.0/24 to any port 10250 proto tcp のように設定します。インターネットに公開してはいけません。このポートで認証できる対象は、ノード上の任意のコンテナ内でプロセスを実行できるためです。
1 台のノード上の pod だけで kubectl logs が失敗するのはなぜですか?
ブロックがノード単位で発生し、API server は pod をホストしている特定のノードに接続するためです。エラーメッセージを確認してください。接続を試みたノードの IP アドレスが含まれています。次に、control plane ノードから nc -zv <node-ip> 10250 を実行します。タイムアウトの場合は、そのノードのファイアウォール、またはプロバイダーのネットワークファイアウォールが原因です。connection refused の場合、そのノードで kubelet が実行されていません。代わりに、そのノード上で systemctl status kubelet を確認してください。