kubeadmのトラブルシューティング

どのプログラムでもそうですが、kubeadmのインストールや実行でエラーが発生することがあります。このページでは、一般的な失敗例をいくつか挙げ、問題を理解して解決するための手順を示しています。

本ページに問題が記載されていない場合は、以下の手順を行ってください:

  • 問題がkubeadmのバグによるものと思った場合:

  • kubeadmがどのように動作するかわからない場合は、Slackの#kubeadmチャンネルで質問するか、StackOverflowで質問をあげてください。その際は、他の方が助けを出しやすいように#kubernetes#kubeadmといったタグをつけてください。

RBACがないため、v1.18ノードをv1.17クラスターに結合できない

v1.18では、同名のノードが既に存在する場合にクラスター内のノードに参加しないようにする機能を追加しました。これには、ブートストラップトークンユーザがNodeオブジェクトをGETできるようにRBACを追加する必要がありました。

しかし、これによりv1.18のkubeadm joinがkubeadm v1.17で作成したクラスターに参加できないという問題が発生します。

この問題を回避するには、次の2つの方法があります。

  • kubeadm v1.18を用いて、コントロールプレーンノード上でkubeadm init phase bootstrap-tokenを実行します。 これには、ブートストラップトークンの残りのパーミッションも同様に有効にすることに注意してください。

  • kubectl apply -f ...を使って以下のRBACを手動で適用します。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubeadm:get-nodes
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubeadm:get-nodes
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubeadm:get-nodes
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:bootstrappers:kubeadm:default-node-token

インストール中にebtablesもしくは他の似たような実行プログラムが見つからない

kubeadm initの実行中に以下のような警告が表示された場合は、以降に記載するやり方を行ってください。

[preflight] WARNING: ebtables not found in system path
[preflight] WARNING: ethtool not found in system path

このような場合、ノード上にebtables, ethtoolなどの実行ファイルがない可能性があります。これらをインストールするには、以下のコマンドを実行します。

  • Ubuntu/Debianユーザーは、apt install ebtables ethtoolを実行してください。
  • CentOS/Fedoraユーザーは、yum install ebtables ethtoolを実行してください。

インストール中にkubeadmがコントロールプレーンを待ち続けて止まる

以下のを出力した後にkubeadm initが止まる場合は、kubeadm initを実行してください:

[apiclient] Created API client, waiting for the control plane to become ready

これはいくつかの問題が原因となっている可能性があります。最も一般的なのは:

  • ネットワーク接続の問題が挙げられます。続行する前に、お使いのマシンがネットワークに完全に接続されていることを確認してください。

  • kubeletのデフォルトのcgroupドライバの設定がDockerで使用されているものとは異なっている場合も考えられます。 システムログファイル(例: /var/log/message)をチェックするか、journalctl -u kubeletの出力を調べてください:

    error: failed to run Kubelet: failed to create kubelet:
    misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"
    

    以上のようなエラーが現れていた場合、cgroupドライバの問題を解決するには、以下の2つの方法があります:

  1. ここの指示に従ってDockerを再度インストールします。

  2. Dockerのcgroupドライバに合わせてkubeletの設定を手動で変更します。その際は、マスターノード上でkubeletが使用するcgroupドライバを設定するを参照してください。

  • control plane Dockerコンテナがクラッシュループしたり、ハングしたりしています。これはdocker psを実行し、docker logsを実行して各コンテナを調査することで確認できます。

管理コンテナを削除する時にkubeadmが止まる

Dockerが停止して、Kubernetesで管理されているコンテナを削除しないと、以下のようなことが起こる可能性があります:

sudo kubeadm reset
[preflight] Running pre-flight checks
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Removing kubernetes-managed containers
(block)

考えられる解決策は、Dockerサービスを再起動してからkubeadm resetを再実行することです:

sudo systemctl restart docker.service
sudo kubeadm reset

dockerのログを調べるのも有効な場合があります:

journalctl -u docker

Podの状態がRunContainerErrorCrashLoopBackOff、またはErrorとなる

kubeadm initの直後には、これらの状態ではPodは存在しないはずです。

  • kubeadm init直後 にこれらの状態のいずれかにPodがある場合は、kubeadmのリポジトリにIssueを立ててください。ネットワークソリューションをデプロイするまではcoredns(またはkube-dns)はPending状態でなければなりません。
  • ネットワークソリューションをデプロイしてもcoredns(またはkube-dns)に何も起こらない場合にRunContainerErrorCrashLoopBackOffError`の状態でPodが表示された場合は、インストールしたPodネットワークソリューションが壊れている可能性が高いです。より多くのRBACの特権を付与するか、新しいバージョンを使用する必要があるかもしれません。PodネットワークプロバイダのイシュートラッカーにIssueを出して、そこで問題をトリアージしてください。
  • 1.12.1よりも古いバージョンのDockerをインストールした場合は、systemddockerdを起動する際にMountFlags=slaveオプションを削除してdockerを再起動してください。マウントフラグは/usr/lib/systemd/system/docker.serviceで確認できます。MountFlagsはKubernetesがマウントしたボリュームに干渉し、PodsをCrashLoopBackOff状態にすることがあります。このエラーは、Kubernetesがvar/run/secrets/kubernetes.io/serviceaccountファイルを見つけられない場合に発生します。

coredns(もしくはkube-dns)がPending状態でスタックする

kubeadmはネットワークプロバイダに依存しないため、管理者は選択したPodネットワークソリューションをインストールをする必要があります。CoreDNSを完全にデプロイする前にPodネットワークをインストールする必要があります。したがって、ネットワークがセットアップされる前の Pending状態になります。

HostPortサービスが動かない

HostPortHostIPの機能は、ご使用のPodネットワークプロバイダによって利用可能です。Podネットワークソリューションの作者に連絡して、HostPortHostIP機能が利用可能かどうかを確認してください。

Calico、Canal、FlannelのCNIプロバイダは、HostPortをサポートしていることが確認されています。

詳細については、[CNI portmap documentation] (https://github.com/containernetworking/plugins/blob/master/plugins/meta/portmap/README.md) を参照してください。

ネットワークプロバイダが portmap CNI プラグインをサポートしていない場合は、NodePortサービスを使用するか、HostNetwork=trueを使用してください。

サービスIP経由でPodにアクセスすることができない

  • 多くのネットワークアドオンは、PodがサービスIPを介して自分自身にアクセスできるようにするヘアピンモードを有効にしていません。これはCNIに関連する問題です。ヘアピンモードのサポート状況については、ネットワークアドオンプロバイダにお問い合わせください。

  • VirtualBoxを使用している場合(直接またはVagrant経由)は、hostname -iがルーティング可能なIPアドレスを返すことを確認する必要があります。デフォルトでは、最初のインターフェースはルーティング可能でないホスト専用のネットワークに接続されています。これを回避するには/etc/hostsを修正する必要があります。例としてはこのVagrantfileを参照してください。

TLS証明書のエラー

以下のエラーは、証明書の不一致の可能性を示しています。

# kubectl get pods
Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")
  • HOME/.kube/configファイルに有効な証明書が含まれていることを確認し、必要に応じて証明書を再生成します。kubeconfigファイル内の証明書はbase64でエンコードされています。証明書をデコードするにはbase64 --decodeコマンドを、証明書情報を表示するにはopenssl x509 -text -nooutコマンドを用いてください。

  • 環境変数KUBECONFIGの設定を解除するには以下のコマンドを実行するか:

    unset KUBECONFIG
    

    設定をデフォルトのKUBECONFIGの場所に設定します:

    export KUBECONFIG=/etc/kubernetes/admin.conf
    
  • もう一つの回避策は、既存のkubeconfigを"admin"ユーザに上書きすることです:

    mv  $HOME/.kube $HOME/.kube.bak
    mkdir $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    

Vagrant内でPodネットワークとしてflannelを使用する時のデフォルトNIC

以下のエラーは、Podネットワークに何か問題があったことを示している可能性を示しています:

Error from server (NotFound): the server could not find the requested resource
  • Vagrant内のPodネットワークとしてflannelを使用している場合は、flannelのデフォルトのインターフェース名を指定する必要があります。

    Vagrantは通常、2つのインターフェースを全てのVMに割り当てます。1つ目は全てのホストにIPアドレス10.0.2.15が割り当てられており、NATされる外部トラフィックのためのものです。

    これは、ホストの最初のインターフェイスをデフォルトにしているflannelの問題につながるかもしれません。これは、すべてのホストが同じパブリックIPアドレスを持っていると考えます。これを防ぐには、2番目のインターフェイスが選択されるように --iface eth1フラグをflannelに渡してください。

公開されていないIPがコンテナに使われている

状況によっては、kubectl logskubectl runコマンドが以下のようなエラーを返すことがあります:

Error from server: Get https://10.19.0.41:10250/containerLogs/default/mysql-ddc65b868-glc5m/mysql: dial tcp 10.19.0.41:10250: getsockopt: no route to host
  • これには、おそらくマシンプロバイダのポリシーによって、一見同じサブネット上の他のIPと通信できないIPをKubernetesが使用している可能性があります。

  • DigitalOceanはパブリックIPとプライベートIPをeth0に割り当てていますが、kubeletはパブリックIPではなく、ノードのInternalIPとして後者を選択します。

    ifconfigではエイリアスIPアドレスが表示されないため、ifconfigの代わりにip addr showを使用してこのシナリオをチェックしてください。あるいは、DigitalOcean専用のAPIエンドポイントを使用して、ドロップレットからアンカーIPを取得することもできます:

    curl http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address
    

    回避策としては、--node-ipを使ってどのIPを使うかをkubeletに伝えることです。DigitalOceanを使用する場合、オプションのプライベートネットワークを使用したい場合は、パブリックIP(eth0に割り当てられている)かプライベートIP(eth1に割り当てられている)のどちらかを指定します。これにはkubeadm NodeRegistrationOptions構造体の KubeletExtraArgsセクション が利用できます。

    kubeletを再起動してください:

    systemctl daemon-reload
    systemctl restart kubelet
    

corednsのPodがCrashLoopBackOffもしくはError状態になる

SELinuxを実行しているノードで古いバージョンのDockerを使用している場合、coredns Podが起動しないということが起きるかもしれません。この問題を解決するには、以下のオプションのいずれかを試してみてください:

kubectl -n kube-system get deployment coredns -o yaml | \
  sed 's/allowPrivilegeEscalation: false/allowPrivilegeEscalation: true/g' | \
  kubectl apply -f -

CoreDNSにCrashLoopBackOffが発生する別の原因は、KubernetesにデプロイされたCoreDNS Podがループを検出したときに発生します。CoreDNSがループを検出して終了するたびに、KubernetesがCoreDNS Podを再起動しようとするのを避けるために、いくつかの回避策が用意されています。

etcdのpodが継続的に再起動する

以下のエラーが発生した場合は:

rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "process_linux.go:110: decoding init error from pipe caused \"read parent: connection reset by peer\""

この問題は、CentOS 7をDocker 1.13.1.84で実行した場合に表示されます。このバージョンのDockerでは、kubeletがetcdコンテナに実行されないようにすることができます。

この問題を回避するには、以下のいずれかのオプションを選択します:

  • 1.13.1-75のような以前のバージョンのDockerにロールバックする
yum downgrade docker-1.13.1-75.git8633870.el7.centos.x86_64 docker-client-1.13.1-75.git8633870.el7.centos.x86_64 docker-common-1.13.1-75.git8633870.el7.centos.x86_64
  • 18.06のような最新の推奨バージョンをインストールする:
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce-18.06.1.ce-3.el7.x86_64

コンマで区切られた値のリストを--component-extra-argsフラグ内の引数に渡すことができない

-component-extra-argsのようなkubeadm initフラグを使うと、kube-apiserverのようなコントロールプレーンコンポーネントにカスタム引数を渡すことができます。しかし、このメカニズムは値の解析に使われる基本的な型 (mapStringString) のために制限されています。

もし、--apiserver-extra-args "enable-admission plugins=LimitRanger,NamespaceExists"のようにカンマで区切られた複数の値をサポートする引数を渡した場合、このフラグはflag: malformed pair, expect string=stringで失敗します。これは--apiserver-extra-argsの引数リストがkey=valueのペアを期待しており、この場合NamespacesExistsは値を欠いたキーとみなされるためです。

別の方法として、key=valueのペアを以下のように分離してみることもできます: --apiserver-extra-args "enable-admission-plugins=LimitRanger,enable-admission-plugins=NamespaceExists"しかし、この場合は、キーenable-admission-pluginsNamespaceExistsの値しか持ちません。既知の回避策としては、kubeadm設定ファイルを使用することが挙げられます。

cloud-controller-managerによってノードが初期化される前にkube-proxyがスケジューリングされる

クラウドプロバイダのシナリオでは、クラウドコントローラーマネージャがノードアドレスを初期化する前に、kube-proxyが新しいワーカーノードでスケジューリングされてしまうことがあります。これにより、kube-proxyがノードのIPアドレスを正しく拾えず、ロードバランサを管理するプロキシ機能に悪影響を及ぼします。

kube-proxy Podsでは以下のようなエラーが発生します:

server.go:610] Failed to retrieve node IP: host IP unknown; known addresses: []
proxier.go:340] invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP

既知の解決策は、初期のガード条件が緩和されるまで他のノードから離しておき、条件に関係なくコントロールプレーンノード上でスケジューリングできるように、キューブプロキシDaemonSetにパッチを当てることです:

kubectl -n kube-system patch ds kube-proxy -p='{ "spec": { "template": { "spec": { "tolerations": [ { "key": "CriticalAddonsOnly", "operator": "Exists" }, { "effect": "NoSchedule", "key": "node-role.kubernetes.io/master" } ] } } } }'

Tこの問題のトラッキング問題はこちら

kubeadmの設定をマーシャリングする際、NodeRegistration.Taintsフィールドが省略される

注意: このIssueは、kubeadmタイプをマーシャルするツール(YAML設定ファイルなど)にのみ適用されます。これはkubeadm API v1beta2で修正される予定です。

デフォルトでは、kubeadmはコントロールプレーンノードにnode-role.kubernetes.io/master:NoScheduleのテイントを適用します。kubeadmがコントロールプレーンノードに影響を与えないようにし、InitConfiguration.NodeRegistration.Taintsを空のスライスに設定すると、マーシャリング時にこのフィールドは省略されます。フィールドが省略された場合、kubeadmはデフォルトのテイントを適用します。

少なくとも2つの回避策があります:

  1. 空のスライスの代わりにnode-role.kubernetes.io/master:PreferNoScheduleテイントを使用します。他のノードに容量がない限り、Podsはマスター上でスケジュールされます

  2. kubeadm init終了後のテイントの除去:

kubectl taint nodes NODE_NAME node-role.kubernetes.io/master:NoSchedule-

ノード{#usr-mounted-read-only}に/usrが読み取り専用でマウントされる

Fedora CoreOSなどのLinuxディストリビューションでは、ディレクトリ/usrが読み取り専用のファイルシステムとしてマウントされます。 flex-volumeサポートでは、kubeletやkube-controller-managerのようなKubernetesコンポーネントはデフォルトで/usr/libexec/kubernetes/kubelet-plugins/volume/exec/のパスを使用していますが、この機能を動作させるためにはflex-volumeディレクトリは 書き込み可能 な状態でなければなりません。

この問題を回避するには、kubeadm設定ファイルを使用してflex-volumeディレクトリを設定します。

プライマリコントロールプレーンノード(kubeadm initで作成されたもの)上で、--configで以下のファイルを渡します:

apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controllerManager:
  extraArgs:
    flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"

ノードをジョインするには:

apiVersion: kubeadm.k8s.io/v1beta2
kind: JoinConfiguration
nodeRegistration:
  kubeletExtraArgs:
    volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"

あるいは、/usrマウントを書き込み可能にするために /etc/fstabを変更することもできますが、これはLinuxディストリビューションの設計原理を変更していることに注意してください。

kubeadm upgrade plancontext deadline exceededエラーメッセージを表示する

このエラーメッセージは、外部etcdを実行している場合にkubeadmでKubernetesクラスターをアップグレードする際に表示されます。これは致命的なバグではなく、古いバージョンのkubeadmが外部etcdクラスターのバージョンチェックを行うために発生します。kubeadm upgrade apply ...で進めることができます。

この問題はバージョン1.19で修正されます。

最終更新 March 31, 2023 at 1:44 AM PST: [ja] s/クラスタ/クラスター/g (26a4e5fd41)