ノード
Kubernetesはコンテナを Node 上で実行されるPodに配置することで、ワークロードを実行します。 ノードはクラスターによりますが、1つのVMまたは物理的なマシンです。 各ノードはPodやそれを制御するコントロールプレーンを実行するのに必要なサービスを含んでいます。
通常、1つのクラスターで複数のノードを持ちます。学習用途やリソースの制限がある環境では、1ノードかもしれません。
1つのノード上のコンポーネントには、kubelet、コンテナランタイム、kube-proxyが含まれます。
管理
ノードをAPIサーバーに加えるには2つの方法があります:
- ノード上のkubeletが、コントロールプレーンに自己登録する。
- あなた、もしくは他のユーザーが手動でNodeオブジェクトを追加する。
Nodeオブジェクトの作成、もしくはノード上のkubeletによる自己登録の後、コントロールプレーンはNodeオブジェクトが有効かチェックします。例えば、下記のjsonマニフェストでノードを作成してみましょう:
{
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "10.240.79.157",
"labels": {
"name": "my-first-k8s-node"
}
}
}
Kubernetesは内部的にNodeオブジェクトを作成します。 APIサーバーに登録したkubeletがノードのmetadata.name
フィールドが一致しているか検証します。ノードが有効な場合、つまり必要なサービスがすべて実行されている場合は、Podを実行する資格があります。それ以外の場合、該当ノードが有効になるまではいかなるクラスターの活動に対しても無視されます。
備考:
Kubernetesは無効なNodeのオブジェクトを保持し、それが有効になるまで検証を続けます。
ヘルスチェックを止めるためには、あなた、もしくはコントローラーが明示的にNodeを削除する必要があります。
Nodeオブジェクトの名前は有効なDNSサブドメイン名である必要があります。
ノードの自己登録
kubeletのフラグ --register-node
がtrue(デフォルト)のとき、kubeletは自分自身をAPIサーバーに登録しようとします。これはほとんどのディストリビューションで使用されている推奨パターンです。
自己登録については、kubeletは以下のオプションを伴って起動されます:
--kubeconfig
- 自分自身をAPIサーバーに対して認証するための資格情報へのパス--cloud-provider
- 自身に関するメタデータを読むためにクラウドプロバイダーと会話する方法--register-node
- 自身をAPIサーバーに自動的に登録--register-with-taints
- 与えられたtaintのリストでノードを登録します (カンマ区切りの<key>=<value>:<effect>
)。
register-node
がfalseの場合、このオプションは機能しません
--node-ip
- ノードのIPアドレス--node-labels
- ノードをクラスターに登録するときに追加するLabel(NodeRestriction許可プラグインによって適用されるラベルの制限を参照)--node-status-update-frequency
- kubeletがノードのステータスをマスターにPOSTする頻度の指定
ノード認証モードおよびNodeRestriction許可プラグインが有効になっている場合、kubeletは自分自身のノードリソースを作成/変更することのみ許可されています。
手動によるノード管理
クラスター管理者はkubectlを使用してNodeオブジェクトを作成および変更できます。
管理者が手動でNodeオブジェクトを作成したい場合は、kubeletフラグ --register-node = false
を設定してください。
管理者は--register-node
の設定に関係なくNodeオブジェクトを変更することができます。
例えば、ノードにラベルを設定し、それをunschedulableとしてマークすることが含まれます。
ノード上のラベルは、スケジューリングを制御するためにPod上のノードセレクターと組み合わせて使用できます。 例えば、Podをノードのサブセットでのみ実行する資格があるように制限します。
ノードをunschedulableとしてマークすると、新しいPodがそのノードにスケジュールされるのを防ぎますが、ノード上の既存のPodには影響しません。 これは、ノードの再起動などの前の準備ステップとして役立ちます。
ノードにスケジュール不可能のマークを付けるには、次のコマンドを実行します:
kubectl cordon $ノード名
備考:
DaemonSetによって作成されたPodはノード上のunschedulable属性を考慮しません。 これは、再起動の準備中にアプリケーションからアプリケーションが削除されている場合でも、DaemonSetがマシンに属していることを前提としているためです。ノードのステータス
ノードのステータスは以下の情報を含みます:
kubectl
を使用し、ノードのステータスや詳細を確認できます:
kubectl describe node <ノード名をここに挿入>
出力情報の各箇所について、以下で説明します。
Addresses
これらのフィールドの使い方は、お使いのクラウドプロバイダーやベアメタルの設定内容によって異なります。
- HostName: ノードのカーネルによって伝えられたホスト名です。kubeletの
--hostname-override
パラメーターによって上書きすることができます。 - ExternalIP: 通常は、外部にルーティング可能(クラスターの外からアクセス可能)なノードのIPアドレスです。
- InternalIP: 通常は、クラスター内でのみルーティング可能なノードのIPアドレスです。
Conditions
conditions
フィールドは全てのRunning
なノードのステータスを表します。例として、以下のような状態を含みます:
ノードのCondition | 概要 |
---|---|
Ready |
ノードの状態が有効でPodを配置可能な場合にTrue になります。ノードの状態に問題があり、Podが配置できない場合にFalse になります。ノードコントローラーが、node-monitor-grace-period で設定された時間内(デフォルトでは40秒)に該当ノードと疎通できない場合、Unknown になります。 |
DiskPressure |
ノードのディスク容量が圧迫されているときにTrue になります。圧迫とは、ディスクの空き容量が少ないことを指します。それ以外のときはFalse です。 |
MemoryPressure |
ノードのメモリが圧迫されているときにTrue になります。圧迫とは、メモリの空き容量が少ないことを指します。それ以外のときはFalse です。 |
PIDPressure |
プロセスが圧迫されているときにTrue になります。圧迫とは、プロセス数が多すぎることを指します。それ以外のときはFalse です。 |
NetworkUnavailable |
ノードのネットワークが適切に設定されていない場合にTrue になります。それ以外のときはFalse です。 |
備考:
コマンドラインを使用してcordonされたNodeを表示する場合、ConditionはSchedulingDisabled
を含みます。
SchedulingDisabled
はKubernetesのAPIにおけるConditionではありません;その代わり、cordonされたノードはUnschedulableとしてマークされます。Nodeの状態は、Nodeリソースの.status
の一部として表現されます。例えば、正常なノードの場合は以下のようなjson構造が表示されます。
"conditions": [
{
"type": "Ready",
"status": "True",
"reason": "KubeletReady",
"message": "kubelet is posting ready status",
"lastHeartbeatTime": "2019-06-05T18:38:35Z",
"lastTransitionTime": "2019-06-05T11:41:27Z"
}
]
Ready conditionがpod-eviction-timeout
(kube-controller-managerに渡された引数)に設定された時間を超えてもUnknown
やFalse
のままになっている場合、該当ノード上にあるPodはノードコントローラーによって削除がスケジュールされます。デフォルトの退役のタイムアウトの時間は5分です。ノードが到達不能ないくつかの場合においては、APIサーバーが該当ノードのkubeletと疎通できない状態になっています。その場合、APIサーバーがkubeletと再び通信を確立するまでの間、Podの削除を行うことはできません。削除がスケジュールされるまでの間、削除対象のPodは切り離されたノードの上で稼働を続けることになります。
ノードコントローラーはクラスター内でPodが停止するのを確認するまでは強制的に削除しないようになりました。到達不能なノード上で動いているPodはTerminating
またはUnknown
のステータスになります。Kubernetesが基盤となるインフラストラクチャーを推定できない場合、クラスター管理者は手動でNodeオブジェクトを削除する必要があります。KubernetesからNodeオブジェクトを削除すると、そのノードで実行されているすべてのPodオブジェクトがAPIサーバーから削除され、それらの名前が解放されます。
ノードのライフサイクルコントローラーがconditionを表したtaintを自動的に生成します。 スケジューラーがPodをノードに割り当てる際、ノードのtaintを考慮します。Podが許容するtaintは例外です。
詳細は条件によるtaintの付与を参照してください。
CapacityとAllocatable
ノードで利用可能なリソース(CPU、メモリ、およびノードでスケジュールできる最大Pod数)について説明します。
capacityブロック内のフィールドは、ノードが持っているリソースの合計量を示します。 allocatableブロックは、通常のPodによって消費されるノード上のリソースの量を示します。
CapacityとAllocatableについて深く知りたい場合は、ノード上でどのようにコンピュートリソースが予約されるかを読みながら学ぶことができます。
Info
カーネルのバージョン、Kubernetesのバージョン(kubeletおよびkube-proxyのバージョン)、(使用されている場合)Dockerのバージョン、OS名など、ノードに関する一般的な情報です。 この情報はノードからkubeletを通じて取得され、Kubernetes APIに公開されます。
ノードのハートビート
ハートビートは、Kubernetesノードから送信され、ノードが利用可能か判断するのに役立ちます。 以下の2つのハートビートがあります:
- Nodeの
.status
の更新 - Lease objectです。
各ノードは
kube-node-lease
というnamespaceに関連したLeaseオブジェクトを持ちます。 Leaseは軽量なリソースで、クラスターのスケールに応じてノードのハートビートにおけるパフォーマンスを改善します。
kubeletがNodeStatus
とLeaseオブジェクトの作成および更新を担当します。
- kubeletは、ステータスに変化があったり、設定した間隔の間に更新がない時に
NodeStatus
を更新します。NodeStatus
更新のデフォルト間隔は5分です。(到達不能の場合のデフォルトタイムアウトである40秒よりもはるかに長いです) - kubeletは10秒間隔(デフォルトの更新間隔)でLeaseオブジェクトの生成と更新を実施します。Leaseの更新は
NodeStatus
の更新とは独立されて行われます。Leaseの更新が失敗した場合、kubeletは200ミリ秒から始まり7秒を上限とした指数バックオフでリトライします。
ノードコントローラー
ノードコントローラーは、ノードのさまざまな側面を管理するKubernetesのコントロールプレーンコンポーネントです。
ノードコントローラーは、ノードの存続期間中に複数の役割を果たします。1つ目は、ノードが登録されたときにCIDRブロックをノードに割り当てることです(CIDR割り当てがオンになっている場合)。
2つ目は、ノードコントローラーの内部ノードリストをクラウドの利用可能なマシンのリストと一致させることです。 クラウド環境で実行している場合、ノードに異常があると、ノードコントローラーはクラウドプロバイダーにそのNodeのVMがまだ使用可能かどうかを問い合わせます。 使用可能でない場合、ノードコントローラーはノードのリストから該当ノードを削除します。
3つ目は、ノードの状態を監視することです。
ノードが到達不能(例えば、ノードがダウンしているなどので理由で、ノードコントローラーがハートビートの受信を停止した場合)になると、ノードコントローラーは、NodeStatusのNodeReady conditionをConditionUnknownに変更する役割があります。その後も該当ノードが到達不能のままであった場合、Graceful Terminationを使って全てのPodを退役させます。デフォルトのタイムアウトは、ConditionUnknownの報告を開始するまで40秒、その後Podの追い出しを開始するまで5分に設定されています。
ノードコントローラーは、--node-monitor-period
に設定された秒数ごとに各ノードの状態をチェックします。
信頼性
ほとんどの場合、排除の速度は1秒あたり--node-eviction-rate
に設定された数値(デフォルトは秒間0.1)です。つまり、10秒間に1つ以上のPodをノードから追い出すことはありません。
特定のアベイラビリティーゾーン内のノードのステータスが異常になると、ノード排除の挙動が変わります。ノードコントローラーは、ゾーン内のノードの何%が異常(NodeReady条件がConditionUnknownまたはConditionFalseである)であるかを同時に確認します。
異常なノードの割合が少なくとも --healthy-zone-threshold
に設定した値を下回る場合(デフォルトは0.55)であれば、退役率は低下します。クラスターが小さい場合(すなわち、 --large-cluster-size-threshold
の設定値よりもノード数が少ない場合。デフォルトは50)、退役は停止し、そうでない場合、退役率は秒間で--secondary-node-eviction-rate
の設定値(デフォルトは0.01)に減少します。
これらのポリシーがアベイラビリティーゾーンごとに実装されているのは、1つのアベイラビリティーゾーンがマスターから分割される一方、他のアベイラビリティーゾーンは接続されたままになる可能性があるためです。
クラスターが複数のクラウドプロバイダーのアベイラビリティーゾーンにまたがっていない場合、アベイラビリティーゾーンは1つだけです(クラスター全体)。
ノードを複数のアベイラビリティゾーンに分散させる主な理由は、1つのゾーン全体が停止したときにワークロードを正常なゾーンに移動できることです。
したがって、ゾーン内のすべてのノードが異常である場合、ノードコントローラーは通常のレート --node-eviction-rate
で退役します。
コーナーケースは、すべてのゾーンが完全にUnhealthyである(すなわち、クラスター内にHealthyなノードがない)場合です。
このような場合、ノードコントローラーはマスター接続に問題があると見なし、接続が回復するまですべての退役を停止します。
ノードコントローラーは、Podがtaintを許容しない場合、 NoExecute
のtaintを持つノード上で実行されているPodを排除する責務もあります。
さらに、ノードコントローラーはノードに到達できない、または準備ができていないなどのノードの問題に対応するtaintを追加する責務があります。これはスケジューラーが、問題のあるノードにPodを配置しない事を意味しています。
ノードのキャパシティ
Nodeオブジェクトはノードのリソースキャパシティ(CPUの数とメモリの量)を監視します。 自己登録したノードは、Nodeオブジェクトを作成するときにキャパシティを報告します。 手動によるノード管理を実行している場合は、ノードを追加するときにキャパシティを設定する必要があります。
Kubernetesスケジューラーは、ノード上のすべてのPodに十分なリソースがあることを確認します。スケジューラーは、ノード上のコンテナが要求するリソースの合計がノードキャパシティ以下であることを確認します。 これは、kubeletによって管理されたすべてのコンテナを含みますが、コンテナランタイムによって直接開始されたコンテナやkubeletの制御外で実行されているプロセスは含みません。
備考:
Pod以外のプロセス用にリソースを明示的に予約したい場合は、Systemデーモン用にリソースを予約を参照してください。ノードのトポロジー
Kubernetes v1.16 [alpha]
TopologyManager
のフィーチャーゲートを有効にすると、
kubeletはリソースの割当を決定する際にトポロジーのヒントを利用できます。
詳細は、ノードのトポロジー管理ポリシーを制御するを参照してください。
ノードの正常終了
Kubernetes v1.21 [beta]
kubeletは、ノードのシステムシャットダウンを検出すると、ノード上で動作しているPodを終了させます。
Kubelet は、ノードのシャットダウン時に、ポッドが通常の通常のポッド終了プロセスに従うようにします。
Graceful Node Shutdownはsystemdに依存しているため、systemd inhibitor locksを 利用してノードのシャットダウンを一定時間遅らせることができます。
Graceful Node Shutdownは、v1.21でデフォルトで有効になっているGracefulNodeShutdown
フィーチャーゲートで制御されます。
なお、デフォルトでは、後述の設定オプションShutdownGracePeriod
およびShutdownGracePeriodCriticalPods
の両方がゼロに設定されているため、Graceful node shutdownは有効になりません。この機能を有効にするには、この2つのkubeletの設定を適切に設定し、ゼロ以外の値を設定する必要があります。
Graceful shutdownでは、kubeletは以下の2段階でPodを終了させます。
- そのノード上で動作している通常のPodを終了させます。
- そのノード上で動作しているcritical podsを終了させます。
Graceful Node Shutdownには、2つのKubeletConfiguration
オプションを設定します。:
ShutdownGracePeriod
:- ノードがシャットダウンを遅らせるべき合計期間を指定します。これは、通常のPodとcritical podsの両方のPod終了の合計猶予期間です。
ShutdownGracePeriodCriticalPods
:- ノードのシャットダウン時にcritical podsを終了させるために使用する期間を指定します。この値は、ShutdownGracePeriodよりも小さくする必要があります。
例えば、ShutdownGracePeriod=30s
、ShutdownGracePeriodCriticalPods=10s
とすると、
kubeletはノードのシャットダウンを30秒遅らせます。シャットダウンの間、最初の20(30-10)秒は通常のポッドを優雅に終了させるために確保され、
残りの10秒は重要なポッドを終了させるために確保されることになります。
備考:
Graceful Node Shutdown中にPodが退避された場合、それらのPodの.status
はFailed
になります。
kubectl get pods
を実行すると、退避させられたPodのステータスが Shutdown
と表示されます。
また、kubectl describe pod
を実行すると、ノードのシャットダウンのためにPodが退避されたことがわかります。
Status: Failed
Reason: Shutdown
Message: Node is shutting, evicting pods
失敗したポッドオブジェクトは、明示的に削除されるか、GCによってクリーンアップされるまで保存されます。 これは、ノードが突然終了した場合とは異なった振る舞いです。
ノードの非正常終了
Kubernetes v1.26 [beta]
コマンドがkubeletのinhibitor locksメカニズムをトリガーしない場合や、ShutdownGracePeriodやShutdownGracePeriodCriticalPodsが適切に設定されていないといったユーザーによるミス等が原因で、ノードがシャットダウンしたことをkubeletのNode Shutdownマネージャーが検知できないことがあります。詳細は上記セクションノードの正常終了を参照ください。
ノードのシャットダウンがkubeletのNode Shutdownマネージャーに検知されない場合、StatefulSetを構成するPodはシャットダウン状態のノード上でterminating状態のままになってしまい、他の実行中のノードに移動することができなくなってしまいます。これは、ノードがシャットダウンしているため、その上のkubeletがPodを削除できず、それにより、StatefulSetが新しいPodを同じ名前で作成できなくなってしまうためです。Podがボリュームを使用している場合、VolumeAttachmentsはシャットダウン状態のノードによって削除されないため、Podが使用しているボリュームは他の実行中のノードにアタッチすることができなくなってしまいます。その結果として、StatefulSet上で実行中のアプリケーションは適切に機能しなくなってしまいます。シャットダウンしていたノードが復旧した場合、そのノード上のPodはkubeletに削除され、他の実行中のノード上に作成されます。また、シャットダウン状態のノードが復旧できなかった場合は、そのノード上のPodは永久にterminating状態のままとなります。
上記の状況を脱却するには、ユーザーが手動でNoExecute
またはNoSchedule
effectを設定してnode.kubernetes.io/out-of-service
taintをノードに付与することで、故障中の状態に設定することができます。kube-controller-manager
において NodeOutOfServiceVolumeDetach
フィーチャーゲートが有効になっており、かつノードがtaintによって故障中としてマークされている場合は、ノードに一致するtolerationがないPodは強制的に削除され、ノード上のterminating状態のPodに対するボリュームデタッチ操作が直ちに実行されます。これにより、故障中のノード上のPodを異なるノード上にすばやく復旧させることが可能になります。
non-graceful shutdownの間に、Podは以下の2段階で終了します:
- 一致する
out-of-service
tolerationを持たないPodを強制的に削除する。 - 上記のPodに対して即座にボリュームデタッチ操作を行う。
備考:
node.kubernetes.io/out-of-service
taintを付与する前に、ノードがシャットダウンしているか電源がオフになっていることを確認してください(再起動中ではないこと)。- Podの別ノードへの移動後、シャットダウンしていたノードが回復した場合は、ユーザーが手動で付与したout-of-service taintをユーザー自ら手動で削除する必要があります。
スワップメモリの管理
Kubernetes v1.22 [alpha]
Kubernetes 1.22以前では、ノードはスワップメモリの使用をサポートしておらず、ノード上でスワップが検出された場合、 kubeletはデフォルトで起動に失敗していました。1.22以降では、スワップメモリのサポートをノードごとに有効にすることができます。
ノードでスワップを有効にするには、kubeletの NodeSwap
フィーチャーゲートを有効にし、
--fail-swap-on
コマンドラインフラグまたはfailSwapOn
KubeletConfigurationを false に設定する必要があります。
ユーザーはオプションで、ノードがスワップメモリをどのように使用するかを指定するために、memorySwap.swapBehavior
を設定することもできます。ノードがスワップメモリをどのように使用するかを指定します。例えば、以下のようになります。
memorySwap:
swapBehavior: LimitedSwap
swapBehaviorで使用できる設定オプションは以下の通りです。:
LimitedSwap
: Kubernetesのワークロードが、使用できるスワップ量に制限を設けます。Kubernetesが管理していないノード上のワークロードは、依然としてスワップを使用できます。UnlimitedSwap
: Kubernetesのワークロードが使用できるスワップ量に制限を設けません。システムの限界まで、要求されただけのスワップメモリを使用することができます。
memorySwap
の設定が指定されておらず、フィーチャーゲートが有効な場合、デフォルトのkubeletはLimitedSwap
の設定と同じ動作を適用します。
LimitedSwap
設定の動作は、ノードがコントロールグループ(「cgroups」とも呼ばれる)のv1とv2のどちらで動作しているかによって異なります。
Kubernetesのワークロードでは、メモリとスワップを組み合わせて使用することができ、ポッドのメモリ制限が設定されている場合はその制限まで使用できます。
- cgroupsv1: Kubernetesのワークロードは、メモリとスワップを組み合わせて使用することができ、ポッドのメモリ制限が設定されている場合はその制限まで使用できます。
- cgroupsv2: Kubernetesのワークロードは、スワップメモリを使用できません。
詳しくは、KEP-2400と design proposalをご覧いただき、テストにご協力、ご意見をお聞かせください。
次の項目
- ノードコンポーネントについて学習する。
- Node APIオブジェクトについて読む。
- アーキテクチャ設計文書のNodeという章を読む。
- TaintとTolerationについて読む。