昨日、ネットワーク環境に問題が発生しました。ローカル仮想マシンで構築されたKubernetes環境には固定IPがありませんでした。その結果、ノード IP が変更されました。もちろん、最も簡単な方法はノードを以前の IP アドレスに再固定することですが、私は頑固だったので、クラスターの IP アドレスを変更したいと考えました。その結果、途中でたくさんの落とし穴に陥ってしまいました。全然そんな簡単なことじゃないよ〜 環境まず、以前の環境を見てみましょう。 ➜ ~ cat / etc /ホスト 192.168.0.111マスター1 192.168.0.109ノード1 192.168.0.110 ノード2 新しい IP アドレス: ➜ ~ cat / etc /ホスト 192.168.0.106マスター1 192.168.0.101ノード1 192.168.0.105 ノード2 したがって、すべてのノードの IP アドレスを変更する必要があります。 操作するまず、すべてのノードの /etc/hosts を新しいアドレスに変更します。 ヒント: ファイルを操作する前に、必ずバックアップすることを強くお勧めします。
マスターノードの /etc/kubernetes ディレクトリをバックアップします。 ➜ cp - Rf / etc / kubernetes / / etc / kubernetes - bak /etc/kubernetes 内のすべての構成ファイルの APIServer アドレスを置き換えます。 ➜ 古いIP = 192.168.0.111 ➜ 新しいIP = 192.168.0.106 # 前を表示 ➜ 検索 . -タイプf | xargs grep $oldip # IP アドレスを置き換えます ➜ find 。 -タイプf | xargs sed - i "s/$oldip/$newip/" # 更新を確認する ➜ find 。 -タイプf | xargs grep $newip 古い IP アドレスを代替名として持つ /etc/kubernetes/pki 内の証明書を特定します。 ➜ cd / etc / kubernetes / pki ➜ for f in $ ( find - name "*.crt" ) ;する openssl x509 - in $f - text - noout > $f .txt ; 終わり ➜ grep - Rl $oldip 。 ➜ for f in $ ( find - name "*.crt" ) ; rm $f .txtを実行します。終わり 古い IP を参照する kube-system 名前空間で ConfigMap を見つけます。 # kube - system 名前空間の下にあるすべての ConfigMap を取得します ➜ configmaps = $ ( kubectl -n kube -system get cm -o name | \ awk '{print $1}' | \ カット- d '/' - f 2 )
# すべてのConfigMapリソースリストを取得します ➜ dir = $ ( mktemp - d ) ➜ $configmaps 内のcf の場合;する kubectl - n kube - system は cm $cf - o yaml > $dir / $cf .yamlを取得します 終わり
# 古いIPを含むすべてのConfigMapを検索 ➜ grep - Hn $dir
このステップは非常に重要です。操作中にこの手順を無視したため、Flannel CNI が起動に失敗し、次のログ情報のようなエラーが報告され続けました。 ➜ kubectl ログ- f kube - flannel - ds - pspzf - n kube -システム I0512 14 : 46 : 26.044229 1 main.go : 205 ] CLIフラグconfig : { etcdEndpoints : http : //127.0.0.1 : 4001 、 http : //127.0.0.1 : 2379etcdPrefix : /coreos.com/networketcdKeyfile : etcdCertfile : etcdCAFile : etcdUsername : etcdPassword : version : falsekubeSubnetMgr : truekubeApiUrl : kubeAnnotationPrefix : flannel.alpha.coreos.comkubeConfigFile : iface: [ ens33 ] ifaceRegex :[] ipMasq : truesubnetFile : / run / flannel / subnet .env publicIP : publicIPv6 : subnetLeaseRenewMargin : 60 healthzIP : 0.0 .0 .0 healthzPort : 0 iptablesResyncSeconds : 5 iptablesForwardRules : true netConfPath : / etc / kube - flannel / net - conf .json setNodeNetworkUnavailable : true } W0512 14 : 46 : 26.044617 1 client_config .go : 614 ] E0512 14 : 46 : 56.142921 1 main .go : 222 ] SubnetManager の作成に失敗しました: 'kube-system/kube-flannel-ds-pspzf'のポッド仕様の取得中にエラーが発生しました: "https://10.96.0.1:443/api/v1/namespaces/kube-system/pods/kube-flannel-ds-pspzf"を取得しました: tcp 10.96 .0 .1にダイヤルしました: 443 : i / o タイムアウト 実際のところ、API サーバーに接続できませんでした。長時間のトラブルシューティングの後、kube-proxy ログを確認することを思い出しました。そこには次のエラー メッセージが表示されていました。 E0512 14 : 53 : 03.260817 1 reflector .go : 138 ] k8s .io / client - go / informers / factory .go : 134 : * v1 .EndpointSliceの監視に失敗しました: * v1 .EndpointSliceの一覧表示に失敗しました: "https://192.168.0.111:6443/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&limit=500&resourceVersion=0"を取得しました: tcp 192.168 .0 .111にダイヤルしました: 6443 :接続しました:ホストへのルートがありません
これは、kube-proxy ConfigMap で設定されている apiserver アドレスが古い IP アドレスであるため、新しい IP アドレスに置き換える必要があるためです。 手順 3 で抽出した証明書と秘密キーを削除し、これらの証明書を再生成します。 ➜ cd / etc / kubernetes / pki ➜ rm apiserver .crt apiserver .key ➜ kubeadm init フェーズ certs apiserver ➜ rm etcd /ピア.crt etcd /ピア.key ➜ kubeadm init フェーズ certs etcd -ピア もちろん、すべてを再生成することもできます。 ➜ kubeadm init フェーズですべての証明書を取得 新しい kubeconfig ファイルを生成します。 ➜ cd / etc / kubernetes ➜ rm -f admin .conf kubelet .confコントローラー-マネージャー.confスケジューラー.conf ➜ kubeadm initフェーズ kubeconfig all I0513 15 : 33 : 34.404780 52280バージョン.go : 255 ]リモート バージョンの方がずっと新しいです: v1 .24 .0 ;フォールバック:安定版- 1.22 [ kubeconfig ] kubeconfig フォルダ"/etc/kubernetes"を使用する [ kubeconfig ] 「admin.conf」 kubeconfig ファイルの書き込み [ kubeconfig ] 「kubelet.conf」 kubeconfigファイルの書き込み [ kubeconfig ] 「controller-manager.conf」 kubeconfigファイルの書き込み [ kubeconfig ] 「scheduler.conf」 kubeconfig ファイルの書き込み # デフォルトのkubeconfigファイルを上書きします ➜ cp /etc/kubernetes/admin.conf $ HOME / .kube / config kubelet を再起動します。 ➜ systemctl コンテナを再起動します ➜ systemctl kubeletを再起動します Kubernetes クラスターにアクセスできるようになりました。 ➜ kubectl ノードを取得する 名前 ステータス 役割 年齢 バージョン master1 準備完了コントロールプレーン、 マスター48d v1.22.8 ノード1 NotReady <なし> 48 d v1 .22 .8 ノード2 NotReady <なし> 48 d v1 .22 .8 ノードクラスターには現在アクセスできますが、Node ノードが NotReady 状態になっていることがわかります。 node2 の kubelet ログを確認できます。 ➜journalctl -u kubelet -f ...... 5 月13日15:47:55 node2 kubelet [ 1194 ] : E0513 15 : 47 : 55.470896 1194 kubelet.go : 2412 ] 「ノードの取得エラー」 err = 「ノード\ " node2\" が見つかりません」 5 月13日15:47:55 node2 kubelet [ 1194 ] : E0513 15 : 47 : 55.531695 1194 reflector.go : 138 ] k8s.io/client-go/informers/factory.go:134 :監視に失敗しました* v1.Service : 一覧表示に失敗しました* v1.Service : 「https://192.168.0.111:6443/api/v1/services?limit=500&resourceVersion=0」 を取得: tcp 192.168.0.111 にダイヤル: 6443 : 接続: ホストへのルートがありません 5 月13日15:47:55 node2 kubelet [ 1194 ] : E0513 15 : 47 : 55.571958 1194 kubelet.go : 2412 ] 「ノードの取得エラー」 err = 「ノード\ " node2\" が見つかりません」 5 月13日15:47:55 node2 kubelet [ 1194 ] : E0513 15 : 47 : 55.673379 1194 kubelet.go : 2412 ] 「ノードの取得エラー」 err = 「ノード\ " node2\" が見つかりません」 以前の APIServer アドレスが引き続きアクセスされていることがわかります。では、APIServer アドレスはどこで明示的に使用されるのでしょうか?次のコマンドで kubelet の起動パラメータを表示できます。 ➜ systemctl ステータス kubelet ● kubelet .service - kubelet : Kubernetes ノード エージェント ロード済み: ロード済み( /usr/lib/systemd/system/kubelet.service ; 有効; ベンダープリセット: 無効) ドロップイン: /usr/lib/systemd/system/kubelet.service.d └─10 - kubeadm.conf アクティブ: 2022-05-13 金曜日14:37:31 CST からアクティブ( 実行中) 。 1時間13分前 ドキュメント: https://kubernetes.io/docs/ メイン PID : 1194 ( kubelet ) タスク: 15 メモリ: 126.9M Cグループ: /system.slice/kubelet.service └─1194 / usr / bin / kubelet
5 月13 日15 : 51 : 08 node2 kubelet [ 1194 ] : E0513 15 : 51 : 08.787677 1194 kubelet .go : 2412 ] "ノード取得エラー" err = "ノード \"node2... が見つかりました" 5 月13 日15 : 51 : 08 node2 kubelet [ 1194 ] : E0513 15 : 51 : 08.888194 1194 kubelet .go : 2412 ] "ノード取得エラー" err = "ノード \"node2... が見つかりました" ...... コア設定ファイルは /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf で、その内容は次のとおりです。 ➜ cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf # 注意:このドロップインはkubeadm とkubelet v1.11 以降でのみ動作します [サービス] 環境= "KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" 環境= "KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # これは、「kubeadm init」 と「kubeadm join」が実行時に生成し、 KUBELET_KUBEADM_ARGS変数を動的に設定するファイルです。 環境ファイル=-/ var / lib / kubelet / kubeadm - flags.env # これは、ユーザーが最後の手段としてkubelet 引数をオーバーライドするために使用できるファイルです。できれば、ユーザーは # 代わりに、構成ファイル内の.NodeRegistration .KubeleExtraArgsオブジェクトを使用します。 KUBELET_EXTRA_ARGS はこのファイルから取得する必要があります。 環境ファイル=-/ etc / sysconfig / kubelet 実行開始= ExecStart =/ usr / bin / kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf という構成があり、2 つの構成ファイル bootstrap-kubelet.conf と kubelet.conf が指定されています。最初のファイルが存在しません: ➜ cat /etc/kubernetes/bootstrap-kubelet.conf cat : / etc / kubernetes / bootstrap - kubelet .conf :そのようなファイルまたはディレクトリはありません 2 番目の構成ファイルは、kubeconfig ファイルの形式です。このファイルは APIServer のアドレスを指定します。以前の IP アドレスのままであることがわかります。 ➜ /etc/kubernetes/kubelet.conf を編集します APIバージョン: v1 クラスター: -クラスター: 証明書-機関-データ: < ...... > サーバー: https://192.168.0.111:6443 名前:デフォルト-クラスター コンテキスト: -コンテクスト: クラスター:デフォルト-クラスター 名前空間:デフォルト ユーザー:デフォルト-認証 名前:デフォルト-コンテキスト 現在のコンテキスト:デフォルトのコンテキスト 種類:設定 設定: { } ユーザー: -名前:デフォルト-認証 ユーザー: クライアント- 証明書: /var/lib/kubelet/pki/kubelet-client-current.pem クライアント- キー: /var/lib/kubelet/pki/kubelet-client-current.pem したがって、最初に考えることは、ここで APIServer アドレスを新しい IP アドレスに変更することですが、関連する証明書が以前のままであり、再生成する必要があるため、明らかに問題が発生します。では、ファイルを再生成するにはどうすればよいでしょうか? まず、kubelet 作業ディレクトリをバックアップします。 ➜ cp /etc/kubernetes/kubelet.conf /etc/kubernetes/kubelet.conf .bak ➜ cp - rf / var / lib / kubelet / / var / lib / kubelet - bak kubelet クライアント証明書を削除します。 ➜ rm / var / lib / kubelet / pki / kubelet -クライアント* 次に、master1 ノード (/etc/kubernetes/pki/ca.key ファイルがあるノード) に kubelet.conf ファイルを生成します。 # マスター1ノードで ➜ kubeadm kubeconfig user 次に、kubelet.conf ファイルを node2/etc/kubernetes/kubelet.conf にコピーし、node2 で kubelet を再起動して、/var/lib/kubelet/pki/kubelet-client-current.pem が再作成されるのを待ちます。 ➜ systemctl kubeletを再起動します # 再起動後にkubeletクライアント証明書が再生成されるのを待ちます ➜ ll / var / lib / kubelet / pki / 合計12 - rw lrwxrwxrwx 1 ルートroot 59 5 月13 日16:32 kubelet - クライアント- 現在の.pem - > / var / lib / kubelet / pki / kubelet - client - 2022-05-13-16-32-35.pem - rw - r - rw kubelet.conf を手動で編集して、ローテーションする kubelet クライアント証明書を指すようにし、ファイル内の client-certificate-data と client-key-data を /var/lib/kubelet/pki/kubelet-client-current.pem に置き換えるのが最適です。 クライアント- 証明書: /var/lib/kubelet/pki/kubelet-client-current.pem クライアント- キー: /var/lib/kubelet/pki/kubelet-client-current.pem kubelet をもう一度再起動します。これでノード2は準備完了状態になります。同じ方法を使用して、node1 を再度構成します。 ➜ kubectl ノードを取得する 名前 ステータス 役割 年齢 バージョン master1 準備完了コントロールプレーン、 マスター48d v1.22.8 ノード1 準備完了<なし> 48 d v1 .22 .8 ノード2 準備完了<なし> 48 d v1 .22 .8 推奨方法上記の操作方法は通常はニーズを満たすことができますが、関連する証明書についてある程度理解している必要があります。この方法に加えて、さらに簡単な操作があります。 まず、kubelet を停止し、作業するディレクトリをバックアップします。 ➜ systemctl を停止します ➜ mv / etc / kubernetes / etc / kubernetes -バックアップ ➜ mv / var / lib / kubelet / / var / lib / kubelet - bak pki 証明書ディレクトリを保存します: ➜ mkdir -p / etc / kubernetes ➜ cp - r / etc / kubernetes - bak / pki / etc / kubernetes ➜ rm / etc / kubernetes / pki / { apiserver. * 、 etcd /ピア。 * } rm :通常のファイル' /etc/kubernetes/pki/apiserver.crt ' を削除しますか?ええ rm :通常のファイル' /etc/kubernetes/pki/apiserver.key 'を削除しますか? ええ rm :通常のファイル' /etc/kubernetes/pki/etcd/peer.crt ' を削除しますか?ええ rm :通常のファイル' /etc/kubernetes/pki/etcd/peer.key ' を削除しますか?ええ ここで、次のコマンドを使用してコントロール プレーン ノードを再初期化しますが、最も重要なことは etcd データ ディレクトリを使用することです。--ignore-preflight-errors=DirAvailable --var-lib-etcd フラグを使用して、既存の etcd データを使用するように kubeadm に指示できます。 ➜ kubeadm init [ init ] Kubernetes バージョン使用: v1.22.8 [プリフライト] プリフライトチェックの実行 [警告 DirAvailable [事前準備] Kubernetes クラスターの設定に必要なイメージを取得する ...... Kubernetes コントロールプレーンが正常に初期化されました。 クラスターの使用を開始するには、通常のユーザーとして以下を実行する必要があります。 mkdir -p $HOME / .kube sudo cp -i /etc/kubernetes/admin.conf $ HOME / .kube / config sudo chown $ ( id - u ) : $ ( id - g ) $HOME / .kube / config あるいは、 root ユーザーの場合は、以下を実行できます。 KUBECONFIG =/ etc / kubernetes / admin.confをエクスポートします。 ここで、クラスターにポッド ネットワークをデプロイする必要があります。 以下にリストされているオプションのいずれかを使用して、 「kubectl apply -f [podnetwork].yaml」を実行します。 https://kubernetes.io/docs/concepts/cluster-administration/addons/ 次に、各ワーカーノードでroot として以下を実行することで、任意の数のワーカーノードに参加できます。 kubeadm join 192.168 .0 .106 : 6443 上記の操作は、クラスターを通常どおり初期化する場合とほぼ同じです。唯一の違いは、--ignore-preflight-errors=DirAvailable--var-lib-etcd パラメータが追加されていることです。これは、以前の etcd データを使用することを意味します。次に、APIServer の IP アドレスが新しいアドレスになったかどうかを確認します。 ➜ cp -i /etc/kubernetes/admin.conf $ HOME / .kube / config cp : ' /root/.kube/config ' を上書きしますか?ええ ➜ kubectl クラスター-情報 Kubernetes コントロールプレーンはhttps://192.168.0.106:6443 で実行されています。 CoreDNS はhttps://192.168.0.106:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy で実行されています
クラスターの問題をさらにデバッグして診断するには、 「kubectl cluster-info dump」を使用します。 ノードについては、リセットしてクラスターに再参加させることができます。 # ノード上の操作 ➜ kubeadm reset リセット後、クラスターに再度参加します。 # ノード上の操作 ➜ kubeadm join 192.168.0.106:6443 --token abcdef.0123456789abcdef この方法は上記の方法よりもはるかに簡単です。正常に動作した後は、クラスターも正常です。 ➜ kubectl ノードを取得する 名前 ステータス 役割 年齢 バージョン master1 準備完了コントロールプレーン、 マスター48d v1.22.8 ノード1 準備完了<なし> 48 d v1 .22 .8 node2 準備完了<なし> 4 m50s v1 .22 .8 要約するIP 変更によるビジネスへの影響を回避するには、Kubernetes クラスター ノードの IP アドレスに静的 IP アドレスを使用するのが最適です。静的 IP でない場合は、IP が変更されたときにドメイン名を直接再マップできるように、署名用のカスタム ドメイン名を追加することを強くお勧めします。以下に示すように、kubeadm 構成ファイルの ClusterConfiguration を通じて apiServer.certSANs を構成するだけで済みます。 apiバージョン: kubeadm .k8s .io / v1beta3 apiサーバー: タイムアウトForControlPlane : 4分0秒 certSANs : -api.k8s.local -マスター1 - 192.168 .0 .106 種類: ClusterConfiguration ...... certSAN に追加する必要があるアドレスを追加します。たとえば、ここでは api.k8s.local という追加アドレスを追加します。これにより、将来 IP が変更された場合でも、このドメイン名を新しい IP アドレスに直接マッピングできます。同様に、外部ネットワーク アクセス IP を介してクラスターにアクセスする場合は、署名認証用に外部ネットワーク IP アドレスも追加する必要があります。
|