ワークロード
Kubernetesにおけるデプロイ可能な最小のオブジェクトであるPodと、高レベルな抽象化がPodの実行を助けることを理解します。
ワークロードとは、Kubernetes上で実行中のアプリケーションです。ワークロードが1つのコンポーネントからなる場合でも、複数のコンポーネントが協調して動作する場合でも、KubernetesではそれらはPod の集合として実行されます。Kubernetesでは、Podはクラスター上で実行中のコンテナ の集合として表されます。
Podには定義されたライフサイクルがあります。たとえば、一度Podがクラスター上で実行中になると、そのPodが実行中のノード 上で深刻な障害が起こったとき、そのノード上のすべてのPodは停止してしまうことになります。Kubernetesではそのようなレベルの障害を最終的なものとして扱うため、たとえノードが後で復元したとしても、ユーザーは新しいPodを作成し直す必要があります。
しかし、生活をかなり楽にするためには、それぞれのPodを直接管理する必要はありません。ワークロードリソース を利用すれば、あなたの代わりにPodの集合の管理を行ってもらえます。これらのリソースはあなたが指定した状態に一致するようにコントローラー を設定し、正しい種類のPodが正しい数だけ実行中になることを保証してくれます。
ワークロードリソースには、次のような種類があります。
多少関連のある2種類の補助的な概念もあります。
次の項目
各リソースについて読む以外にも、以下のページでそれぞれのワークロードに関連する特定のタスクについて学ぶことができます。
アプリケーションが実行できるようになったら、インターネット上で公開したくなるかもしれません。その場合には、Service として公開したり、ウェブアプリケーションだけの場合、Ingress を使用することができます。
コードを設定から分離するKubernetesのしくみについて学ぶには、設定 を読んでください。
1 - Pod
Pod は、Kubernetes内で作成・管理できるコンピューティングの最小のデプロイ可能なユニットです。
Pod (Podという名前は、たとえばクジラの群れ(pod of whales)やえんどう豆のさや(pea pod)などの表現と同じような意味です)は、1つまたは複数のコンテナ のグループであり、ストレージやネットワークの共有リソースを持ち、コンテナの実行方法に関する仕様を持っています。同じPodに含まれるリソースは、常に同じ場所で同時にスケジューリングされ、共有されたコンテキストの中で実行されます。Podはアプリケーションに特化した「論理的なホスト」をモデル化します。つまり、1つのPod内には、1つまたは複数の比較的密に結合されたアプリケーションコンテナが含まれます。クラウド外の文脈で説明すると、アプリケーションが同じ物理ホストや同じバーチャルマシンで実行されることが、クラウドアプリケーションの場合には同じ論理ホスト上で実行されることに相当します。
アプリケーションコンテナと同様に、Podでも、Podのスタートアップ時に実行されるinitコンテナ を含めることができます。また、クラスターで利用できる場合には、エフェメラルコンテナ を注入してデバッグすることもできます。
Podとは何か?
備考: KubernetesはDockerだけでなく複数の
コンテナランタイム をサポートしていますが、
Docker が最も一般的に知られたランタイムであるため、Docker由来の用語を使ってPodを説明するのが理解の助けとなります。
Podの共有コンテキストは、Dockerコンテナを隔離するのに使われているのと同じ、Linuxのnamespaces、cgroups、場合によっては他の隔離技術の集合を用いて作られます。Podのコンテキスト内では、各アプリケーションが追加の準隔離技術を適用することもあります。
Dockerの概念を使って説明すると、Podは共有の名前空間と共有ファイルシステムのボリュームを持つDockerコンテナのグループに似ています。
Podを使用する
以下は、nginx:1.14.2イメージが実行されるコンテナからなるPodの例を記載しています。
apiVersion : v1
kind : Pod
metadata :
name : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
上記のようなPodを作成するには、以下のコマンドを実行します:
kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml
Podは通常、直接作成されず、ワークロードリソースで作成されます。ワークロードリソースでPodを作成する方法の詳細については、Podを利用する を参照してください。
Podを管理するためのワークロードリソース
通常、たとえ単一のコンテナしか持たないシングルトンのPodだとしても、自分でPodを直接作成する必要はありません。その代わりに、Deployment やJob などのワークロードリソースを使用してPodを作成します。もしPodが状態を保持する必要がある場合は、StatefulSet リソースを使用することを検討してください。
Kubernetesクラスター内のPodは、主に次の2種類の方法で使われます。
単一のコンテナを稼働させるPod 。「1Pod1コンテナ」構成のモデルは、Kubernetesでは最も一般的なユースケースです。このケースでは、ユーザーはPodを単一のコンテナのラッパーとして考えることができます。Kubernetesはコンテナを直接管理するのではなく、Podを管理します。
協調して稼働させる必要がある複数のコンテナを稼働させるPod 。単一のPodは、密に結合してリソースを共有する必要があるような、同じ場所で稼働する複数のコンテナからなるアプリケーションをカプセル化することもできます。これらの同じ場所で稼働するコンテナ群は、単一のまとまりのあるサービスのユニットを構成します。たとえば、1つのコンテナが共有ボリュームからファイルをパブリックに配信し、別のサイドカー コンテナがそれらのファイルを更新するという構成が考えられます。Podはこれらの複数のコンテナ、ストレージリソース、一時的なネットワークIDなどを、単一のユニットとしてまとめます。
備考: 複数のコンテナを同じ場所で同時に管理するように単一のPod内にグループ化するのは、比較的高度なユースケースです。このパターンを使用するのは、コンテナが密に結合しているような特定のインスタンス内でのみにするべきです。
各Podは、与えられたアプリケーションの単一のインスタンスを稼働するためのものです。もしユーザーのアプリケーションを水平にスケールさせたい場合(例: 複数インスタンスを稼働させる)、複数のPodを使うべきです。1つのPodは各インスタンスに対応しています。Kubernetesでは、これは一般的にレプリケーション と呼ばれます。レプリケーションされたPodは、通常ワークロードリソースと、それに対応するコントローラー によって、作成・管理されます。
Kubernetesがワークロードリソースとそのコントローラーを活用して、スケーラブルで自動回復するアプリケーションを実装する方法については、詳しくはPodとコントローラー を参照してください。
Podが複数のコンテナを管理する方法
Podは、まとまりの強いサービスのユニットを構成する、複数の協調する(コンテナとして実行される)プロセスをサポートするために設計されました。単一のPod内の複数のコンテナは、クラスター内の同じ物理または仮想マシン上で、自動的に同じ場所に配置・スケジューリングされます。コンテナ間では、リソースや依存関係を共有したり、お互いに通信したり、停止するときにはタイミングや方法を協調して実行できます。
たとえば、あるコンテナが共有ボリューム内のファイルを配信するウェブサーバーとして動作し、別の「サイドカー」コンテナがリモートのリソースからファイルをアップデートするような構成が考えられます。この構成を以下のダイアグラムに示します。
Podによっては、appコンテナ に加えてinitコンテナ を持っている場合があります。initコンテナはappコンテナが起動する前に実行・完了するコンテナです。
Podは、Podを構成する複数のコンテナに対して、ネットワーク とストレージ の2種類の共有リソースを提供します。
Podを利用する
通常Kubernetesでは、たとえ単一のコンテナしか持たないシングルトンのPodだとしても、個別のPodを直接作成することはめったにありません。その理由は、Podがある程度一時的で使い捨てできる存在として設計されているためです。Podが作成されると(あなたが直接作成した場合でも、コントローラー が間接的に作成した場合でも)、新しいPodはクラスター内のノード 上で実行されるようにスケジューリングされます。Podは、実行が完了するか、Podオブジェクトが削除されるか、リソース不足によって強制退去 されるか、ノードが停止するまで、そのノード上にとどまります。
備考: Pod内のコンテナの再起動とPodの再起動を混同しないでください。Podはプロセスではなく、コンテナが実行するための環境です。Podは削除されるまでは残り続けます。
Podオブジェクトのためのマニフェストを作成したときは、指定したPodの名前が有効なDNSサブドメイン名 であることを確認してください。
Pod OS
FEATURE STATE:
Kubernetes v1.25 [stable]
.spec.os.nameフィールドでwindowsかlinuxのいずれかを設定し、Podを実行させたいOSを指定する必要があります。Kubernetesは今のところ、この2つのOSだけサポートしています。将来的には増える可能性があります。
Kubernetes v1.35では、このフィールドに設定した値はPodのスケジューリング に影響を与えません。.spec.os.nameを設定することで、Pod OSに権限を認証することができ、バリデーションにも使用されます。kubeletが実行されているノードのOSが、指定されたPod OSと異なる場合、kubeletはPodの実行を拒否します。Podセキュリティの標準 もこのフィールドを使用し、指定したOSと関係ないポリシーの適用を回避しています。
Podとコンテナコントローラー
ワークロードリソースは、複数のPodを作成・管理するために利用できます。リソースに対応するコントローラーが、複製やロールアウトを扱い、Podの障害時には自動回復を行います。たとえば、あるノードに障害が発生した場合、コントローラーはそのノードの動作が停止したことを検知し、代わりのPodを作成します。そして、スケジューラーが代わりのPodを健全なノード上に配置します。
以下に、1つ以上のPodを管理するワークロードリソースの一例をあげます。
Podテンプレート
workload リソース向けのコントローラーは、PodをPodテンプレート を元に作成し、あなたの代わりにPodを管理してくれます。
PodTemplateはPodを作成するための仕様で、Deployment 、Job 、DaemonSet などのワークロードリソースの中に含まれています。
ワークロードリソースに対応する各コントローラーは、ワークロードオブジェクト内にあるPodTemplateを使用して実際のPodを作成します。PodTemplateは、アプリを実行するために使われるワークロードリソースがどんな種類のものであれ、その目的の状態の一部を構成するものです。
以下は、単純なJobのマニフェストの一例で、1つのコンテナを実行するtemplateがあります。Pod内のコンテナはメッセージを出力した後、一時停止します。
apiVersion : batch/v1
kind : Job
metadata :
name : hello
spec :
template :
# これがPodテンプレートです
spec :
containers :
- name : hello
image : busybox:1.28
command : ['sh' , '-c' , 'echo "Hello, Kubernetes!" && sleep 3600' ]
restartPolicy : OnFailure
# Podテンプレートはここまでです
Podテンプレートを修正するか新しいPodに切り替えたとしても、すでに存在するPodには直接の影響はありません。ワークロードリソース内のPodテンプレートを変更すると、そのリソースは更新されたテンプレートを使用して代わりとなるPodを作成する必要があります。
たとえば、StatefulSetコントローラーは、各StatefulSetごとに、実行中のPodが現在のPodテンプレートに一致することを保証します。Podテンプレートを変更するためにStatefulSetを編集すると、StatefulSetは更新されたテンプレートを元にした新しいPodを作成するようになります。最終的に、すべての古いPodが新しいPodで置き換えられ、更新は完了します。
各ワークロードリソースは、Podテンプレートへの変更を処理するための独自のルールを実装しています。特にStatefulSetについて更に詳しく知りたい場合は、StatefulSetの基本チュートリアル内のアップデート戦略 を読んでください。
ノード上では、kubelet はPodテンプレートに関する詳細について監視や管理を直接行うわけではありません。こうした詳細は抽象化されています。こうした抽象化や関心の分離のおかげでシステムのセマンティクスが単純化され、既存のコードを変更せずにクラスターの動作を容易に拡張できるようになっているのです。
Podの更新と取替
前のセクションで述べたように、ワークロードリソースのPodテンプレートが変更されると、コントローラーは既存のPodを更新したりパッチを適用したりするのではなく、更新されたテンプレートに基づいて新しいPodを作成します。
KubernetesはPodを直接管理することを妨げません。実行中のPodの一部のフィールドをその場で更新することが可能です。しかし、patch とreplace といった、Podのアップデート操作にはいくつかの制限があります:
Podのメタデータのほとんどは固定されたものです。たとえばnamespace、name、uidまたはcreationTimestampフィールドは変更できません。generationフィールドは特別で、現在の値を増加させる更新のみを受け付けます。
metadata.deletionTimestampが設定されている場合、metadata.finalizersリストに新しい項目を追加することはできません。
Podの更新ではspec.containers[*].image、spec.initContainers[*].image、spec.activeDeadlineSecondsまたはspec.tolerations以外のフィールドを変更してはなりません。spec.tolerationsについては新しい項目のみを追加することができます。
spec.activeDeadlineSecondsフィールドを更新する場合、2種類の更新が可能です:
未割り当てのフィールドに正の数を設定する
現在の値から負の数でない、より小さい数に更新する
リソースの共有と通信
Podは、データの共有と構成するコンテナ間での通信を可能にします。
Pod内のストレージ
Podでは、共有ストレージであるボリューム の集合を指定できます。Pod内のすべてのコンテナは共有ボリュームにアクセスできるため、それら複数のコンテナでデータを共有できるようになります。また、ボリュームを利用すれば、Pod内のコンテナの1つに再起動が必要になった場合にも、Pod内の永続化データを保持し続けられるようにできます。Kubernetesの共有ストレージの実装方法とPodで利用できるようにする方法に関するさらに詳しい情報は、ストレージ を読んでください。
Podネットワーク
各Podには、各アドレスファミリーごとにユニークなIPアドレスが割り当てられます。Pod内のすべてのコンテナは、IPアドレスとネットワークポートを含むネットワーク名前空間を共有します。Podの中では(かつその場合にのみ )、そのPod内のコンテナはlocalhostを使用して他のコンテナと通信できます。Podの内部にあるコンテナがPodの外部にある エンティティと通信する場合、(ポートなどの)共有ネットワークリソースの使い方をコンテナ間で調整しなければなりません。Pod内では、コンテナはIPアドレスとポートの空間を共有するため、localhostで他のコンテナにアクセスできます。また、Pod内のコンテナは、SystemVのセマフォやPOSIXの共有メモリなど、標準のプロセス間通信を使って他のコンテナと通信することもできます。異なるPod内のコンテナは異なるIPアドレスを持つため、特別な設定をしない限り、OSレベルIPCで通信することはできません。異なるPod上で実行中のコンテナ間でやり取りをしたい場合は、IPネットワークを使用して通信できます。
Pod内のコンテナは、システムのhostnameがPodに設定したnameと同一であると考えます。ネットワークについての詳しい情報は、ネットワーク で説明しています。
コンテナの特権モード
Linuxでは、Pod内のどんなコンテナも、privilegedフラグをコンテナのspecのsecurity context に設定することで、特権モード(privileged mode)を有効にできます。これは、ネットワークスタックの操作やハードウェアデバイスへのアクセスなど、オペレーティングシステムの管理者の権限が必要なコンテナの場合に役に立ちます。
WindowsHostProcessContainers機能を有効にしたクラスターの場合、Pod仕様のsecurityContextにwindowsOptions.hostProcessフラグを設定することで、Windows HostProcess Pod を作成することが可能です。これらのPod内のすべてのコンテナは、Windows HostProcessコンテナとして実行する必要があります。HostProcess Podはホスト上で直接実行され、Linuxの特権コンテナで行われるような管理作業を行うのにも使用できます。
備考: この設定を有効にするには、
コンテナランタイム が特権コンテナの概念をサポートしていなければなりません。
static Pod
static Pod は、APIサーバー には管理されない、特定のノード上でkubeletデーモンによって直接管理されるPodのことです。大部分のPodはコントロールプレーン(たとえばDeployment )によって管理されますが、static Podの場合はkubeletが各static Podを直接管理します(障害時には再起動します)。
static Podは常に特定のノード上の1つのKubelet に紐付けられます。static Podの主な用途は、セルフホストのコントロールプレーンを実行すること、言い換えると、kubeletを使用して個別のコントロールプレーンコンポーネント を管理することです。
kubeletは自動的にKubernetes APIサーバー上に各static Podに対応するミラーPod の作成を試みます。つまり、ノード上で実行中のPodはAPIサーバー上でも見えるようになるけれども、APIサーバー上から制御はできないということです。
コンテナのProbe
Probe はkubeletがコンテナに対して行う定期診断です。診断を実行するために、kubeletはさまざまなアクションを実行できます:
ExecAction (コンテナランタイムの助けを借りて実行)
TCPSocketAction (kubeletにより直接チェック)
HTTPGetAction (kubeletにより直接チェック)
更に詳しく知りたい場合は、PodのライフサイクルドキュメントにあるProbe を読んでください。
次の項目
Kubernetesが共通のPod APIを他のリソース内(たとえばStatefulSet やDeployment など)にラッピングしている理由の文脈を理解するためには、Kubernetes以前から存在する以下のような既存技術について読むのが助けになります。
1.1 - Podのライフサイクル
このページではPodのライフサイクルについて説明します。Podは定義されたライフサイクルに従い Pendingフェーズ から始まり、少なくとも1つのプライマリーコンテナが正常に開始した場合はRunningを経由し、次に失敗により終了したコンテナの有無に応じて、SucceededまたはFailedフェーズを経由します。
Podの実行中、kubeletはコンテナを再起動して、ある種の障害を処理できます。Pod内で、Kubernetesはさまざまなコンテナのステータス を追跡して、回復させるためのアクションを決定します。
Kubernetes APIでは、Podには仕様と実際のステータスの両方があります。Podオブジェクトのステータスは、PodのCondition のセットで構成されます。カスタムのReadiness情報 をPodのConditionデータに挿入することもできます。
Podはその生存期間に1回だけスケジューリング されます。PodがNodeにスケジュール(割り当て)されると、Podは停止または終了 するまでそのNode上で実行されます。
Podのライフタイム
個々のアプリケーションコンテナと同様に、Podは(永続的ではなく)比較的短期間の存在と捉えられます。Podが作成されると、一意のID(UID )が割り当てられ、(再起動ポリシーに従って)終了または削除されるまでNodeで実行されるようにスケジュールされます。
ノード が停止した場合、そのNodeにスケジュールされたPodは、タイムアウト時間の経過後に削除 されます。
Pod自体は、自己修復しません。Podがnode にスケジュールされ、その後に失敗した場合、Podは削除されます。同様に、リソースの不足またはNodeのメンテナンスによりPodはNodeから立ち退きます。Kubernetesは、比較的使い捨てのPodインスタンスの管理作業を処理する、controller と呼ばれる上位レベルの抽象化を使用します。
特定のPod(UIDで定義)は新しいNodeに"再スケジュール"されません。代わりに、必要に応じて同じ名前で、新しいUIDを持つ同一のPodに置き換えることができます。
volume など、Podと同じ存続期間を持つものがあると言われる場合、それは(そのUIDを持つ)Podが存在する限り存在することを意味します。そのPodが何らかの理由で削除された場合、たとえ同じ代替物が作成されたとしても、関連するもの(例えばボリューム)も同様に破壊されて再作成されます。
Podの図
file puller(ファイル取得コンテナ)とWebサーバーを含むマルチコンテナのPod。コンテナ間の共有ストレージとして永続ボリュームを使用しています。
Podのフェーズ
Podのstatus項目はPodStatus オブジェクトで、それはphaseのフィールドがあります。
Podのフェーズは、そのPodがライフサイクルのどの状態にあるかを、簡単かつ高レベルにまとめたものです。このフェーズはコンテナやPodの状態を包括的にまとめることを目的としたものではなく、また包括的なステートマシンでもありません。
Podの各フェーズの値と意味は厳重に守られています。ここに記載されているもの以外にphaseの値は存在しないと思ってください。
これらがphaseの取りうる値です。
値
概要
Pending
PodがKubernetesクラスターによって承認されましたが、1つ以上のコンテナがセットアップされて稼働する準備ができていません。これには、スケジュールされるまでの時間と、ネットワーク経由でイメージをダウンロードするための時間などが含まれます。
Running
PodがNodeにバインドされ、すべてのコンテナが作成されました。少なくとも1つのコンテナがまだ実行されているか、開始または再起動中です。
Succeeded
Pod内のすべてのコンテナが正常に終了し、再起動されません。
Failed
Pod内のすべてのコンテナが終了し、少なくとも1つのコンテナが異常終了しました。つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了されました。
Unknown
何らかの理由によりPodの状態を取得できませんでした。このフェーズは通常はPodのホストとの通信エラーにより発生します。
備考: Podの削除中に、kubectlコマンドには
Terminatingが出力されることがあります。この
Terminatingステータスは、Podのフェーズではありません。Podには、正常に終了するための期間を与えられており、デフォルトは30秒です。
--forceフラグを使用して、
Podを強制的に削除する ことができます。
Nodeが停止するか、クラスターの残りの部分から切断された場合、Kubernetesは失われたNode上のすべてのPodのPhaseをFailedに設定するためのポリシーを適用します。
コンテナのステータス
Pod全体のフェーズ と同様に、KubernetesはPod内の各コンテナの状態を追跡します。container lifecycle hooks を使用して、コンテナのライフサイクルの特定のポイントで実行するイベントをトリガーできます。
Podがscheduler によってNodeに割り当てられると、kubeletはcontainer runtime を使用してコンテナの作成を開始します。コンテナの状態はWaiting、RunningまたはTerminatedの3ついずれかです。
Podのコンテナの状態を確認するにはkubectl describe pod [POD_NAME]のコマンドを使用します。Pod内のコンテナごとにStateの項目として表示されます。
各状態の意味は次のとおりです。
Waiting
コンテナがRunningまたはTerminatedのいずれの状態でもない場合コンテナはWaitingの状態になります。Waiting状態のコンテナは引き続きコンテナイメージレジストリからイメージを取得したりSecret を適用したりするなど必要な操作を実行します。Waiting状態のコンテナを持つPodに対してkubectlコマンドを使用すると、そのコンテナがWaitingの状態である理由の要約が表示されます。
Running
Running状態はコンテナが問題なく実行されていることを示します。postStartフックが構成されていた場合、それはすでに実行が完了しています。Running状態のコンテナを持つPodに対してkubectlコマンドを使用すると、そのコンテナがRunning状態になった時刻が表示されます。
Terminated
Terminated状態のコンテナは実行されて、完了したときまたは何らかの理由で失敗したことを示します。Terminated状態のコンテナを持つPodに対してkubectlコマンドを使用すると、いずれにせよ理由と終了コード、コンテナの開始時刻と終了時刻が表示されます。
コンテナがTerminatedに入る前にpreStopフックがあれば実行されます。
コンテナの再起動ポリシー
Podのspecには、Always、OnFailure、またはNeverのいずれかの値を持つrestartPolicyフィールドがあります。デフォルト値はAlwaysです。
restartPolicyは、Pod内のすべてのコンテナに適用されます。restartPolicyは、同じNode上のkubeletによるコンテナの再起動のみを参照します。Pod内のコンテナが終了した後、kubeletは5分を上限とする指数バックオフ遅延(10秒、20秒、40秒...)でコンテナを再起動します。コンテナが10分間実行されると、kubeletはコンテナの再起動バックオフタイマーをリセットします。
PodのCondition
PodにはPodStatusがあります。それにはPodが成功したかどうかの情報を持つPodCondition の配列が含まれています。kubeletは、下記のPodConditionを管理します:
PodScheduled: PodがNodeにスケジュールされました。
PodHasNetwork: (アルファ版機能; 明示的に有効 にしなければならない) Podサンドボックスが正常に作成され、ネットワークの設定が完了しました。
ContainersReady: Pod内のすべてのコンテナが準備できた状態です。
Initialized: すべてのInitコンテナ が正常に終了しました。
Ready: Podはリクエストを処理でき、一致するすべてのサービスの負荷分散プールに追加されます。
フィールド名
内容
type
このPodの状態の名前です。
status
その状態が適用可能かどうか示します。可能な値は"True"、"False"、"Unknown"のうちのいずれかです。
lastProbeTime
Pod Conditionが最後に確認されたときのタイムスタンプが表示されます。
lastTransitionTime
最後にPodのステータスの遷移があった際のタイムスタンプが表示されます。
reason
最後の状態遷移の理由を示す、機械可読のアッパーキャメルケースのテキストです。
message
ステータスの遷移に関する詳細を示す人間向けのメッセージです。
PodのReadiness
FEATURE STATE:
Kubernetes v1.14 [stable]
追加のフィードバックやシグナルをPodStatus:Pod readiness に注入できるようにします。これを使用するには、PodのspecでreadinessGatesを設定して、kubeletがPodのReadinessを評価する追加の状態のリストを指定します。
ReadinessゲートはPodのstatus.conditionsフィールドの現在の状態によって決まります。KubernetesがPodのstatus.conditionsフィールドでそのような状態を発見できない場合、ステータスはデフォルトでFalseになります。
以下はその例です。
Kind : Pod
...
spec :
readinessGates :
- conditionType : "www.example.com/feature-1"
status :
conditions :
- type : Ready # これはビルトインのPodCondition
status : "False"
lastProbeTime : null
lastTransitionTime : 2018-01-01T00:00:00Z
- type : "www.example.com/feature-1" # 追加のPodCondition
status : "False"
lastProbeTime : null
lastTransitionTime : 2018-01-01T00:00:00Z
containerStatuses :
- containerID : docker://abcd...
ready : true
...
PodのConditionは、Kubernetesのlabel key format に準拠している必要があります。
PodのReadinessの状態
kubectl patchコマンドはオブジェクトステータスのパッチ適用をまだサポートしていません。Podにこれらのstatus.conditionsを設定するには、アプリケーションとoperators はPATCHアクションを使用する必要があります。Kubernetes client library を使用して、PodのReadinessのためにカスタムのPodのConditionを設定するコードを記述できます。
カスタムのPodのConditionが導入されるとPodは次の両方の条件に当てはまる場合のみ 準備できていると評価されます:
Pod内のすべてのコンテナが準備完了している。
ReadinessGatesで指定された条件が全てTrueである。
Podのコンテナは準備完了ですが、少なくとも1つのカスタムのConditionが欠落しているか「False」の場合、kubeletはPodのCondition をContainersReadyに設定します。
PodのネットワークのReadiness
FEATURE STATE:
Kubernetes v1.25 [alpha]
Podがノードにスケジュールされた後、kubeletによって承認され、任意のボリュームがマウントされる必要があります。これらのフェーズが完了すると、kubeletはコンテナランタイム(コンテナランタイムインターフェース(CRI) を使用)と連携して、ランタイムサンドボックスのセットアップとPodのネットワークを構成します。もしPodHasNetworkConditionフィーチャーゲート が有効になっている場合、kubeletは、Podがこの初期化の節目に到達したかどうかをPodのstatus.conditionsフィールドにあるPodHasNetwork状態を使用して報告します。
ネットワークが設定されたランタイムサンドボックスがPodにないことを検出すると、PodHasNetwork状態は、kubelet によってFalseに設定されます。これは、以下のシナリオで発生します:
Podのライフサイクルの初期で、kubeletがコンテナランタイムを使用してPodのサンドボックスのセットアップをまだ開始していないとき
Podのライフサイクルの後期で、Podのサンドボックスが以下のどちらかの原因で破壊された場合:
Podを退去させず、ノードが再起動する
コンテナランタイムの隔離に仮想マシンを使用している場合、Podサンドボックスの仮想マシンが再起動し、新しいサンドボックスと新しいコンテナネットワーク設定を作成する必要があります
ランタイムプラグインによるサンドボックスの作成とPodのネットワーク設定が正常に完了すると、kubeletによってPodHasNetwork状態がTrueに設定されます。PodHasNetwork状態がTrueに設定された後、kubeletはコンテナイメージの取得とコンテナの作成を開始することができます。
initコンテナを持つPodの場合、initコンテナが正常に完了すると(ランタイムプラグインによるサンドボックスの作成とネットワーク設定が正常に行われた後に発生)、kubeletはInitialized状態をTrueに設定します。initコンテナがないPodの場合、サンドボックスの作成およびネットワーク設定が開始する前にkubeletはInitialized状態をTrueに設定します。
コンテナのProbe
Probe はkubelet により定期的に実行されるコンテナの診断です。診断を行うために、kubeletはコンテナ内でコードを実行するか、ネットワークリクエストします。
チェックのメカニズム
probeを使ってコンテナをチェックする4つの異なる方法があります。各probeは、この4つの仕組みのうち1つを正確に定義する必要があります:
exec
コンテナ内で特定のコマンドを実行します。コマンドがステータス0で終了した場合に診断を成功と見なします。
grpc
gRPC を使ってリモートプロシージャコールを実行します。ターゲットは、gRPC health checks を実装する必要があります。レスポンスのstatusがSERVINGの場合に診断を成功と見なします。gRPCはアルファ版の機能のため、GRPCContainerProbeフィーチャーゲート が有効の場合のみ利用可能です。
httpGet
PodのIPアドレスに対して、指定されたポートとパスでHTTP GETのリクエストを送信します。レスポンスのステータスコードが200以上400未満の際に診断を成功とみなします。
tcpSocket
PodのIPアドレスに対して、指定されたポートでTCPチェックを行います。そのポートが空いていれば診断を成功とみなします。オープンしてすぐにリモートシステム(コンテナ)が接続を切断した場合、健全な状態としてカウントします。
Probeの結果
各Probe 次の3つのうちの一つの結果を持ちます:
Success
コンテナの診断が成功しました。
Failure
コンテナの診断が失敗しました。
Unknown
コンテナの診断自体が失敗しました(何も実行する必要はなく、kubeletはさらにチェックを行います)。
Probeの種類
kubeletは3種類のProbeを実行中のコンテナで行い、また反応することができます:
livenessProbe
コンテナが動いているかを示します。livenessProbeに失敗すると、kubeletはコンテナを殺します、そしてコンテナはrestart policy に従います。コンテナにlivenessProbeが設定されていない場合、デフォルトの状態はSuccessです。
readinessProbe
コンテナがリクエスト応答する準備ができているかを示します。readinessProbeに失敗すると、エンドポイントコントローラーにより、ServiceからそのPodのIPアドレスが削除されます。initial delay前のデフォルトのreadinessProbeの初期値はFailureです。コンテナにreadinessProbeが設定されていない場合、デフォルトの状態はSuccessです。
startupProbe
コンテナ内のアプリケーションが起動したかどうかを示します。startupProbeが設定された場合、完了するまでその他のすべてのProbeは無効になります。startupProbeに失敗すると、kubeletはコンテナを殺します、そしてコンテナはrestart policy に従います。コンテナにstartupProbeが設定されていない場合、デフォルトの状態はSuccessです。
livenessProbe、readinessProbeまたはstartupProbeを設定する方法の詳細については、Liveness Probe、Readiness ProbeおよびStartup Probeを使用する を参照してください。
livenessProbeをいつ使うべきか?
FEATURE STATE:
Kubernetes v1.0 [stable]
コンテナ自体に問題が発生した場合や状態が悪くなった際にクラッシュすることができればlivenessProbeは不要です。この場合kubeletが自動でPodのrestartPolicyに基づいたアクションを実行します。
Probeに失敗したときにコンテナを殺したり再起動させたりするには、livenessProbeを設定しrestartPolicyをAlwaysまたはOnFailureにします。
readinessProbeをいつ使うべきか?
FEATURE STATE:
Kubernetes v1.0 [stable]
Probeが成功したときにのみPodにトラフィックを送信したい場合は、readinessProbeを指定します。この場合readinessProbeはlivenessProbeと同じになる可能性がありますが、readinessProbeが存在するということは、Podがトラフィックを受けずに開始され、Probe成功が開始した後でトラフィックを受け始めることになります。
コンテナがメンテナンスのために停止できるようにするには、livenessProbeとは異なる、特定のエンドポイントを確認するreadinessProbeを指定することができます。
アプリがバックエンドサービスと厳密な依存関係にある場合、livenessProbeとreadinessProbeの両方を実装することができます。アプリ自体が健全であればlivenessProbeはパスしますが、readinessProbeはさらに、必要なバックエンドサービスが利用可能であるかどうかをチェックします。これにより、エラーメッセージでしか応答できないPodへのトラフィックの転送を避けることができます。
コンテナの起動中に大きなデータ、構成ファイル、またはマイグレーションを読み込む必要がある場合は、startupProbe を使用できます。ただし、失敗したアプリと起動データを処理中のアプリの違いを検出したい場合は、readinessProbeを使用した方が良いかもしれません。
備考: Podが削除されたときにリクエストを来ないようにするためには必ずしもreadinessProbeが必要というわけではありません。Podの削除時にはreadinessProbeが存在するかどうかに関係なくPodは自動的に自身をunreadyにします。Pod内のコンテナが停止するのを待つ間Podはunreadyのままです。
startupProbeをいつ使うべきか?
FEATURE STATE:
Kubernetes v1.20 [stable]
startupProbeは、サービスの開始に時間がかかるコンテナを持つPodに役立ちます。livenessProbeの間隔を長く設定するのではなく、コンテナの起動時に別のProbeを構成して、livenessProbeの間隔よりも長い時間を許可できます。コンテナの起動時間が、initialDelaySeconds + failureThreshold x periodSecondsよりも長い場合は、livenessProbeと同じエンドポイントをチェックするためにstartupProbeを指定します。periodSecondsのデフォルトは10秒です。次に、failureThresholdをlivenessProbeのデフォルト値を変更せずにコンテナが起動できるように、十分に高い値を設定します。これによりデッドロックを防ぐことができます。
Podの終了
Podは、クラスター内のNodeで実行中のプロセスを表すため、不要になったときにそれらのプロセスを正常に終了できるようにすることが重要です(対照的なケースは、KILLシグナルで強制終了され、クリーンアップする機会がない場合)。
ユーザーは削除を要求可能であるべきで、プロセスがいつ終了するかを知ることができなければなりませんが、削除が最終的に完了することも保証できるべきです。ユーザーがPodの削除を要求すると、システムはPodが強制終了される前に意図された猶予期間を記録および追跡します。強制削除までの猶予期間がある場合、kubelet 正常な終了を試みます。
通常、コンテナランタイムは各コンテナのメインプロセスにTERMシグナルを送信します。多くのコンテナランタイムは、コンテナイメージで定義されたSTOPSIGNAL値を尊重し、TERMシグナルの代わりにこれを送信します。猶予期間が終了すると、プロセスにKILLシグナルが送信され、PodはAPI server から削除されます。プロセスの終了を待っている間にkubeletかコンテナランタイムの管理サービスが再起動されると、クラスターは元の猶予期間を含めて、最初からリトライされます。
フローの例は下のようになります。
ユーザーがデフォルトの猶予期間(30秒)でPodを削除するためにkubectlコマンドを送信する。
API server内のPodは、猶予期間を越えるとPodが「死んでいる」と見なされるように更新される。
削除中のPodに対してkubectl describeコマンドを使用すると、Podは「終了中」と表示される。
Podが実行されているNode上で、Podが終了しているとマークされている(正常な終了期間が設定されている)とkubeletが認識するとすぐに、kubeletはローカルでPodの終了プロセスを開始します。
Pod内のコンテナの1つがpreStopフック を定義している場合は、コンテナの内側で呼び出される。猶予期間が終了した後もpreStopフックがまだ実行されている場合は、一度だけ猶予期間を延長される(2秒)。
備考: preStopフックが完了するまでにより長い時間が必要な場合は、terminationGracePeriodSecondsを変更する必要があります。
kubeletはコンテナランタイムをトリガーして、コンテナ内のプロセス番号1にTERMシグナルを送信する。
備考: Pod内のすべてのコンテナが同時にTERMシグナルを受信するわけではなく、シャットダウンの順序が問題になる場合はそれぞれにpreStopフックを使用して同期することを検討する。
kubeletが正常な終了を開始すると同時に、コントロールプレーンは、終了中のPodをEndpointSlice(およびEndpoints)オブジェクトから削除します。これらのオブジェクトは、selector が設定されたService を表します。ReplicaSets とその他のワークロードリソースは、終了中のPodを有効なサービス中のReplicaSetとして扱いません。ゆっくりと終了するPodは、(サービスプロキシのような)ロードバランサーが終了猶予期間が始まる とエンドポイントからそれらのPodを削除するので、トラフィックを継続して処理できません。
猶予期間が終了すると、kubeletは強制削除を開始する。コンテナランタイムは、Pod内でまだ実行中のプロセスにSIGKILLを送信する。kubeletは、コンテナランタイムが非表示のpauseコンテナを使用している場合、そのコンテナをクリーンアップします。
kubeletは猶予期間を0(即時削除)に設定することでAPI server上のPodの削除を終了する。
API serverはPodのAPIオブジェクトを削除し、クライアントからは見えなくなります。
Podの強制削除
注意: 強制削除は、Podによっては潜在的に危険な場合があるため、慎重に実行する必要があります。
デフォルトでは、すべての削除は30秒以内に正常に行われます。kubectl delete コマンドは、ユーザーがデフォルト値を上書きして独自の値を指定できるようにする --grace-period=<seconds> オプションをサポートします。
--grace-periodを0に設定した場合、PodはAPI serverから即座に強制的に削除されます。PodがNode上でまだ実行されている場合、その強制削除によりkubeletがトリガーされ、すぐにクリーンアップが開始されます。
備考: 強制削除を実行するために --grace-period=0 と共に --force というフラグを追加で指定する必要があります。
強制削除が実行されると、API serverは、Podが実行されていたNode上でPodが停止されたというkubeletからの確認を待ちません。API内のPodは直ちに削除されるため、新しいPodを同じ名前で作成できるようになります。Node上では、すぐに終了するように設定されるPodは、強制終了される前にわずかな猶予期間が与えられます。
注意: 即時削除では、実行中のリソースの終了を待ちません。リソースはクラスター上で無期限に実行し続ける可能性があります。
StatefulSetのPodについては、StatefulSetからPodを削除するためのタスクのドキュメント を参照してください。
終了したPodのガベージコレクション
失敗したPodは人間またはcontroller が明示的に削除するまで存在します。
コントロールプレーンは終了状態のPod(SucceededまたはFailedのphaseを持つ)の数が設定された閾値(kube-controller-manager内のterminated-pod-gc-thresholdによって定義される)を超えたとき、それらのPodを削除します。これはPodが作成されて時間とともに終了するため、リソースリークを避けます。
次の項目
1.2 - Initコンテナ
このページでは、Initコンテナの概要について説明します。Initコンテナとは、Pod 内でアプリケーションコンテナの前に実行される特別なコンテナです。Initコンテナには、アプリケーションコンテナのイメージに存在しないユーティリティやセットアップスクリプトを含めることができます。
Podの仕様では、アプリケーションコンテナを記述するcontainers配列と同じ階層に並べて、Initコンテナを指定できます。
Kubernetesでは、サイドカーコンテナ は、メインのアプリケーションコンテナよりも前に起動し、実行し続ける コンテナです。このドキュメントでは、Podの初期化中に実行が完了するコンテナであるInitコンテナについて説明します。
Initコンテナを理解する
Pod は、内部で実行される複数のアプリケーションコンテナを持つことができますが、アプリケーションコンテナが起動する前に実行される1つ以上のInitコンテナを持つこともできます。
Initコンテナは下記の項目をのぞいて、通常のコンテナと全く同じです:
Initコンテナは常に完了するまで稼働します。
各Initコンテナは、次のInitコンテナが稼働する前に正常に完了しなくてはなりません。
Pod内のInitコンテナが失敗した場合、kubeletは成功するまで、Initコンテナの再起動を繰り返します。しかし、PodのrestartPolicyがNeverに設定されていて、Podの起動時にInitコンテナが失敗した場合、KubernetesはPod全体を失敗として扱います。
PodにInitコンテナを指定するためには、Podの仕様 にinitContainersフィールドをcontainer項目の配列として追加してください(アプリケーションのcontainersフィールドとそのコンテンツと同様です)。詳細については、APIリファレンスのコンテナ を参照してください。
Initコンテナのステータスは、.status.initContainerStatusesフィールドにコンテナのステータスの配列として返されます(.status.containerStatusesと同様です)。
通常のコンテナとの違い
Initコンテナは、リソース制限、ボリューム 、セキュリティ設定などのアプリケーションコンテナの全てのフィールドと機能をサポートしています。ただし、Initコンテナのリソース要求と制限は、コンテナ間のリソース共有 に記載されているように、異なる方法で処理されます。
通常のInitコンテナ(つまり、サイドカーコンテナを除く)は、lifecycle、livenessProbe、readinessProbe、startupProbeフィールドをサポートしていません。InitコンテナはPodの準備が完了する前に実行を完了する必要があります。一方、サイドカーコンテナはPodのライフタイム中は常に実行され続け、一部のProbeを サポートしています 。サイドカーコンテナの詳細については、サイドカーコンテナ を参照してください。
単一のPodに対して複数のInitコンテナを指定した場合、kubeletはそれらのInitコンテナを順次実行します。各Initコンテナは、次のInitコンテナが実行される前に正常に終了する必要があります。全てのInitコンテナの実行が完了すると、kubeletはPodのアプリケーションコンテナを初期化し、通常通り実行します。
サイドカーコンテナとの違い
Initコンテナは、メインのアプリケーションコンテナが起動する前にタスクを実行して完了します。サイドカーコンテナ とは異なり、Initコンテナはメインコンテナと並行して継続的に実行されることはありません。
Initコンテナは順次実行され完了します。すべてのInitコンテナが正常に完了するまで、メインコンテナは起動しません。
Initコンテナはlifecycle、livenessProbe、readinessProbe、startupProbeをサポートしていませんが、サイドカーコンテナはこれらすべてのProbe をサポートしてライフサイクルを制御します。
Initコンテナは、メインのアプリケーションコンテナとリソース(CPU、メモリ、ネットワーク)を共有しますが、直接やり取りすることはありません。ただし、共有ボリュームを使用してデータの交換を行うことは可能です。
Initコンテナを使用する
Initコンテナはアプリケーションコンテナのイメージとは分離されているため、コンテナの起動に関連したコードにおいていくつかの利点があります:
Initコンテナには、アプリケーションイメージに含まれないセットアップ用のユーティリティやカスタムコードを含めることができます。たとえば、セットアップ時にsed、awk、python、digなどのツールを使用するためだけに、別のイメージをFROMしてイメージを作成する必要はありません。
アプリケーションイメージをビルドする役割とデプロイする役割は、共同で単一のアプリケーションイメージをビルドする必要がないため、それぞれ独立して実施することができます。
Initコンテナは、同じPod内のアプリケーションコンテナとは異なる方法でファイルシステムにアクセスできます。その結果、アプリケーションコンテナがアクセスできないSecret に対するアクセス権限を得ることができます。
Initコンテナはアプリケーションコンテナが開始する前に完了するまで実行されるため、Initコンテナを使用することで、特定の前提条件が満たされるまでアプリケーションコンテナの起動をブロックしたり遅らせることができます。前提条件が満たされると、Pod内の全てのアプリケーションコンテナを並行して起動することができます。
Initコンテナは、アプリケーションコンテナイメージのセキュリティを低下させる可能性のあるユーティリティやカスタムコードを安全に実行できます。不要なツールを分離することで、アプリケーションコンテナイメージの攻撃対象領域を制限できます。
例
Initコンテナを活用する方法について、いくつかのアイデアを次に示します:
シェルのワンライナーコマンドを使ってService が作成されるのを待機する:
for i in { 1..100} ; do sleep 1; if nslookup myservice; then exit 0; fi ; done ; exit 1
以下のようなコマンドを使って、Downward APIを介してこのPodをリモートサーバーに登録する:
curl -X POST http://$MANAGEMENT_SERVICE_HOST :$MANAGEMENT_SERVICE_PORT /register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
以下のようなコマンドを使ってアプリケーションコンテナの起動を待機する:
Gitリポジトリをボリューム にクローンする。
いくつかの値を設定ファイルに配置し、メインのアプリケーションコンテナのための設定ファイルを動的に生成するためのテンプレートツールを実行する。例えば、そのPodのPOD_IPの値を設定ファイルに配置し、Jinjaを使ってメインのアプリケーションコンテナの設定ファイルを生成する。
Initコンテナの具体的な使用方法
下記の例は、2つのInitコンテナを含むシンプルなPodを定義しています。1つ目のInitコンテナはmyserviceの起動を、2つ目のInitコンテナはmydbの起動をそれぞれ待ちます。両方のInitコンテナの実行が完了すると、Podはspecセクションにあるアプリケーションコンテナを実行します。
apiVersion : v1
kind : Pod
metadata :
name : myapp-pod
labels :
app.kubernetes.io/name : MyApp
spec :
containers :
- name : myapp-container
image : busybox:1.28
command : ['sh' , '-c' , 'echo The app is running! && sleep 3600' ]
initContainers :
- name : init-myservice
image : busybox:1.28
command : ['sh' , '-c' , "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done" ]
- name : init-mydb
image : busybox:1.28
command : ['sh' , '-c' , "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done" ]
次のコマンドを実行して、このPodを開始します:
kubectl apply -f myapp.yaml
実行結果は下記のようになります:
pod/myapp-pod created
そして次のコマンドでステータスを確認します:
kubectl get -f myapp.yaml
実行結果は下記のようになります:
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
より詳細な情報は次のコマンドで確認します:
kubectl describe -f myapp.yaml
実行結果は下記のようになります:
Name: myapp-pod
Namespace: default
[...]
Labels: app.kubernetes.io/name=MyApp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container init-myservice
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container init-myservice
このPod内のInitコンテナのログを確認するためには、次のコマンドを実行します:
kubectl logs myapp-pod -c init-myservice # 1つ目のInitコンテナを調査する
kubectl logs myapp-pod -c init-mydb # 2つ目のInitコンテナを調査する
この時点で、これらのInitコンテナはmydbとmyserviceという名前のService の検出を待機しています。
これらのServiceを検出するための設定は以下の通りです:
---
apiVersion : v1
kind : Service
metadata :
name : myservice
spec :
ports :
- protocol : TCP
port : 80
targetPort : 9376
---
apiVersion : v1
kind : Service
metadata :
name : mydb
spec :
ports :
- protocol : TCP
port : 80
targetPort : 9377
mydbおよびmyserviceというServiceを作成するために、以下のコマンドを実行します:
kubectl apply -f services.yaml
実行結果は下記のようになります:
service/myservice created
service/mydb created
Initコンテナが完了し、myapp-podというPodが実行状態に移行したことを確認できます:
kubectl get -f myapp.yaml
実行結果は下記のようになります:
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
この簡単な例は、独自のinitコンテナを作成する際のヒントになるはずです。次の項目 には、さらに詳細な使用例に関するリンクがあります。
Initコンテナのふるまいに関する詳細
Podの起動時に、kubeletはネットワークおよびストレージの準備が整うまで、Initコンテナを実行可能な状態にしません。また、kubeletはPodのspecに定義された順番に従って、PodのInitコンテナを起動します。
各Initコンテナは次のInitコンテナが起動する前に正常に終了しなくてはなりません。もし、あるInitコンテナがランタイムにより起動失敗した場合、もしくはエラーで終了した場合、そのPodのrestartPolicyの値に従ってリトライされます。しかし、PodのrestartPolicyがAlwaysに設定されていた場合は、InitコンテナのrestartPolicyはOnFailureとして適用されます。
すべてのInitコンテナが成功するまで、PodはReadyになりません。InitコンテナのポートはService配下に集約されません。初期化中のPodはPending状態ですが、条件Initializedはfalseに設定されているはずです。
Podを再起動 するとき、またはPodが再起動されたとき、全てのInitコンテナは必ず再度実行されます。
Initコンテナのspecに対する変更は、コンテナイメージフィールドに制限されています。Initコンテナのimageフィールドを直接変更しても、Podの再起動や再作成はトリガー されません 。ただし、Podがまだ起動していない場合、その変更はPodの起動方法に影響を与える可能性があります。
Podテンプレート の場合、通常はInitコンテナの任意のフィールドを変更できます。その変更の影響は、Podテンプレートがどこで使用されているかによって異なります。
Initコンテナは何度も再起動、リトライおよび再実行可能であるため、べき等(Idempotent)である必要があります。特に、emptyDirにファイルを書き込むコードは、書き込み先のファイルがすでに存在している可能性を考慮に入れなければいけません。
Initコンテナは、アプリケーションコンテナが持つすべてのフィールドを持っています。ただし、KubernetesではreadinessProbeの使用が禁止されています。これは、Initコンテナでは完了とは別にreadiness状態を定義することができないためです。この制約は、バリデーション時に強制されます。
Initコンテナが永久に失敗し続けることを防ぐために、Pod上でactiveDeadlineSecondsを使用してください。activeDeadlineSecondsの設定はInitコンテナが実行中の時間にも適用されます。ただし、activeDeadlineSecondsはInitコンテナが完了した後にも影響が及ぶため、アプリケーションをJobとしてデプロイする場合にのみ使用することを推奨します。すでに正しく動作しているPodは、activeDeadlineSecondsを設定すると強制終了されます。
Pod内の各アプリケーションコンテナとInitコンテナの名前はユニークである必要があります。他のコンテナと同じ名前を共有していた場合、バリデーションエラーが返されます。
コンテナ間のリソース共有
Initコンテナ、サイドカーコンテナ、アプリケーションコンテナの実行順序を考慮すると、リソース使用に関して以下のルールが適用されます:
すべてのInitコンテナで定義された特定のリソースの要求または制限のうち、最も高い値が実効Init要求/制限 となります。リソース制限が指定されていない場合、これが最も高い制限であるとみなされます。
リソースに対するPodの実効要求/制限 は、以下のうち高い方になります。
すべてのアプリケーションコンテナのリソース要求/制限の合計
リソースに対する実効Init要求/制限
スケジューリングは実効要求/制限に基づいて行われます。つまり、Initコンテナは初期化のためにリソースを予約できますが、これらはPodのライフタイム中は使用されません。
Podの実効QoS tier は、Initコンテナとアプリケーションコンテナの両方に適用されるQoS(サービス品質) tierです。
クォータと制限は、実効的なPodの要求と制限に基づいて適用されます。
InitコンテナとLinux cgroups
Linuxでは、Podレベルのコントロールグループ(cgroups)に対するリソース割り当ては、スケジューラーと同様に、実効的なPodの要求と制限に基づいています。
Podの再起動の理由
以下の理由によりPodは再起動し、Initコンテナの再実行を引き起こす可能性があります:
Podインフラストラクチャコンテナが再起動された場合。これは稀なケースであり、ノードへのルートアクセス権を持つ人が実行する必要があります。
restartPolicyがAlwaysに設定されている状態でPod内のすべてのコンテナが終了し、再起動が強制され、かつInitコンテナの完了記録がガベージコレクション により失われた場合。
Initコンテナイメージが変更された場合、またはガベージコレクションによりInitコンテナの完了記録が失われた場合、Podは再起動されません。これはKubernetes v1.20以降に適用されます。それ以前のバージョンのKubernetesを使用している場合は、使用しているバージョンのドキュメントを参照してください。
次の項目
詳しく学ぶには、以下を参照してください:
1.3 - サイドカーコンテナ
FEATURE STATE:
Kubernetes v1.33 [stable](enabled by default)
サイドカーコンテナは、同じPod 内でメインのアプリケーションコンテナと共に実行されるセカンダリコンテナです。これらのコンテナは、ロギング、モニタリング、セキュリティ、データ同期などの追加サービスや機能を提供することで、プライマリの アプリケーションコンテナ の機能を強化または拡張するために使用されます。メインのアプリケーションコードを直接変更する必要はありません。
通常、Pod内にはアプリケーションコンテナが1つだけ含まれます。例えば、ローカルWebサーバーを必要とするWebアプリケーションがある場合、ローカルWebサーバーがサイドカーであり、Webアプリケーション自体がアプリケーションコンテナです。
Kubernetesにおけるサイドカーコンテナ
Kubernetesは、サイドカーコンテナをInitコンテナ の特殊なケースとして実装しています。サイドカーコンテナはPod起動後も実行され続けます。このドキュメントでは、Pod起動時にのみ実行されるコンテナを明確に指すために、通常のInitコンテナ という用語を使用します。
クラスターでSidecarContainersフィーチャーゲート が有効になっている場合(この機能はKubernetes v1.29以降デフォルトで有効です)、PodのinitContainersフィールドにリストされているコンテナに対してrestartPolicyを指定できます。これらの再起動可能な サイドカー コンテナは、同じPod内の他のInitコンテナやメインアプリケーションコンテナから独立しています。メインアプリケーションコンテナや他のInitコンテナに影響を与えることなく、これらを起動、停止、または再起動することができます。
また、Initコンテナやサイドカーコンテナとして定義されていない複数のコンテナでPodを実行することもできます。これは、Pod内のコンテナがPod全体の動作に必要であるが、どのコンテナを最初に起動または停止するかを制御する必要がない場合に適しています。また、コンテナレベルのrestartPolicyフィールドをサポートしていない古いバージョンのKubernetesをサポートする必要がある場合にも、この方法を使用できます。
アプリケーションの例
以下は、2つのコンテナを持つDeploymentの例で、そのうちの1つがサイドカーコンテナです:
apiVersion : apps/v1
kind : Deployment
metadata :
name : myapp
labels :
app : myapp
spec :
replicas : 1
selector :
matchLabels :
app : myapp
template :
metadata :
labels :
app : myapp
spec :
containers :
- name : myapp
image : alpine:latest
command : ['sh' , '-c' , 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done' ]
volumeMounts :
- name : data
mountPath : /opt
initContainers :
- name : logshipper
image : alpine:latest
restartPolicy : Always
command : ['sh' , '-c' , 'tail -F /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
volumes :
- name : data
emptyDir : {}
サイドカーコンテナとPodのライフサイクル
InitコンテナがrestartPolicyをAlwaysに設定して作成された場合、Podの全ライフサイクルを通じて起動し、実行され続けます。これは、メインのアプリケーションコンテナから分離した補助的なサービスを実行する際に役立ちます。
このInitコンテナにreadinessProbeが指定されている場合、その結果はPodのready状態を判定するために使用されます。
これらのコンテナはInitコンテナとして定義されているため、通常のInitコンテナと同じ順序と順次実行の保証の恩恵を受けます。これにより、複雑なPod初期化フローの際に、サイドカーコンテナと通常のInitコンテナを混在させることができます。
通常のInitコンテナと比較して、initContainers内で定義されたサイドカーコンテナは起動後も実行され続けます。これは、Podの.spec.initContainers内に複数のエントリがある場合に重要です。サイドカー形式のInitコンテナが実行状態になった後(kubeletがそのInitコンテナのstartedステータスをtrueに設定した後)、kubeletは順序付けられた.spec.initContainersリストから次のInitコンテナを起動します。このステータスは、コンテナ内でプロセスが実行されておりStartup Probeが定義されていない場合、またはstartupProbeが成功した結果として、trueになります。
Podの終了 時には、kubeletはメインのアプリケーションコンテナが完全に停止するまで、サイドカーコンテナの終了を引き延ばします。その後、サイドカーコンテナはPodの仕様内で定義された順序と逆の順序でシャットダウンされます。このアプローチにより、サイドカーコンテナは、そのサービスが不要になるまで、Pod内の他のコンテナをサポートし続けることが保証されます。
サイドカーコンテナを持つJob
Kubernetes形式のInitコンテナを使用してサイドカーコンテナを使用するJobを定義した場合、各Pod内のサイドカーコンテナは、メインコンテナが終了した後にJobが完了することを妨げません。
以下は、2つのコンテナを持つJobの例で、そのうちの1つがサイドカーコンテナです:
apiVersion : batch/v1
kind : Job
metadata :
name : myjob
spec :
template :
spec :
containers :
- name : myjob
image : alpine:latest
command : ['sh' , '-c' , 'echo "logging" > /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
initContainers :
- name : logshipper
image : alpine:latest
restartPolicy : Always
command : ['sh' , '-c' , 'tail -F /opt/logs.txt' ]
volumeMounts :
- name : data
mountPath : /opt
restartPolicy : Never
volumes :
- name : data
emptyDir : {}
アプリケーションコンテナとの違い
サイドカーコンテナは、同じPod内で アプリケーションコンテナ と並行して実行されます。ただし、サイドカーコンテナは主要なアプリケーションロジックを実行するのではなく、メインアプリケーションに補助的な機能を提供します。
サイドカーコンテナは独自の独立したライフサイクルを持ちます。アプリケーションコンテナとは独立して、起動、停止、再起動できます。これは、メインアプリケーションに影響を与えることなく、サイドカーコンテナを更新、スケール、またはメンテナンスできることを意味します。
サイドカーコンテナは、プライマリコンテナと同じネットワークおよびストレージ名前空間を共有します。このように共存することで、密接に相互作用しリソースを共有できます。
Kubernetesの観点からは、サイドカーコンテナのグレースフルな終了はそれほど重要ではありません。他のコンテナが、割り当てられたグレースフルな終了時間をすべて消費した場合、サイドカーコンテナはグレースフルに終了する時間を持つ前に、SIGTERMシグナルに続いてSIGKILLシグナルを受信します。そのため、サイドカーコンテナにおいては、Pod終了時の0以外の終了コード(0は正常終了を示します)は正常なものであり、一般的に外部ツールによって無視されるべきです。
Initコンテナとの違い
サイドカーコンテナはメインコンテナと並行して動作し、その機能を拡張して追加のサービスを提供します。
サイドカーコンテナは、メインのアプリケーションコンテナと同時に実行されます。サイドカーコンテナはPodのライフサイクル全体を通じてアクティブであり、メインコンテナとは独立して起動および停止できます。Initコンテナ とは異なり、サイドカーコンテナは、ライフサイクルを制御するためのProbe をサポートしています。
サイドカーコンテナは、メインのアプリケーションコンテナと直接やり取りできます。これは、Initコンテナと同様に常に同じネットワークを共有し、オプションでボリューム(ファイルシステム)も共有できるためです。
Initコンテナはメインコンテナが起動する前に停止するため、InitコンテナはPod内のアプリケーションコンテナとメッセージを交換できません。データの受け渡しは一方向です(例えば、InitコンテナがemptyDirボリューム内に情報を配置することはできます)。
サイドカーコンテナのイメージを変更してもPodは再起動されませんが、コンテナの再起動はトリガーされます。
コンテナ内でのリソース共有
Initコンテナ、サイドカーコンテナ、アプリケーションコンテナの実行順序を考慮すると、リソース使用に関して以下のルールが適用されます:
すべてのInitコンテナで定義された特定のリソース要求または制限のうち、最も高い値が実効Init要求/制限 となります。いずれかのリソースにリソース制限が指定されていない場合、これが最も高い制限と見なされます。
リソースに対するPodの実効要求/制限 は、Podのオーバーヘッド と以下のうち高い方の合計です:
すべての非Initコンテナ(アプリケーションコンテナとサイドカーコンテナ)のリソース要求/制限の合計
リソースに対する実効Init要求/制限
スケジューリングは実効要求/制限に基づいて行われます。これは、InitコンテナがPodのライフタイム中には使用されない初期化用のリソースを予約できることを意味します。
Podの実効QoS tier のQoS(サービス品質) tierは、Initコンテナ、サイドカーコンテナ、アプリケーションコンテナすべてに対するQoS tierです。
クォータと制限は、実効Pod要求と制限に基づいて適用されます。
サイドカーコンテナとLinux cgroup
Linuxでは、Podレベルのコントロールグループ(cgroup)に対するリソース割り当ては、スケジューラーと同様に、実効的なPod要求/制限に基づいて行われます。
次の項目
1.4 - エフェメラルコンテナ
FEATURE STATE:
Kubernetes v1.25 [stable]
このページでは、特別な種類のコンテナであるエフェメラルコンテナの概要を説明します。エフェメラルコンテナは、トラブルシューティングなどのユーザーが開始するアクションを実行するために、すでに存在するPod 内で一時的に実行するコンテナです。エフェメラルコンテナは、アプリケーションの構築ではなく、serviceの調査のために利用します。
エフェメラルコンテナを理解する
Pod は、Kubernetesのアプリケーションの基本的なビルディングブロックです。Podは破棄可能かつ置き換え可能であることが想定されているため、一度Podが作成されると新しいコンテナを追加することはできません。その代わりに、通常はDeployment を使用してPodを削除して置き換えます。
たとえば、再現困難なバグのトラブルシューティングなどのために、すでに存在するPodの状態を調査する必要が出てくることがあります。このような場合、既存のPod内でエフェメラルコンテナを実行することで、Podの状態を調査したり、任意のコマンドを実行したりできます。
エフェメラルコンテナとは何か?
エフェメラルコンテナは、他のコンテナと異なり、リソースや実行が保証されず、自動的に再起動されることも決してないため、アプリケーションを構築する目的には適しません。エフェメラルコンテナは、通常のコンテナと同じContainerSpecで記述されますが、多くのフィールドに互換性がなかったり、使用できなくなっています。
エフェメラルコンテナはポートを持つことができないため、ports、livenessProbe、readinessProbeなどは使えなくなっています。
Podリソースの割り当てはイミュータブルであるため、resourcesの設定が禁止されています。
利用が許可されているフィールドの一覧については、EphemeralContainerのリファレンスドキュメント を参照してください。
エフェメラルコンテナは、直接pod.specに追加するのではなく、API内の特別なephemeralcontainersハンドラを使用して作成します。そのため、エフェメラルコンテナをkubectl editを使用して追加することはできません。
エフェメラルコンテナをPodに追加した後は、通常のコンテナのようにエフェメラルコンテナを変更または削除することはできません。
エフェメラルコンテナの用途
エフェメラルコンテナは、コンテナがクラッシュしてしまったり、コンテナイメージにデバッグ用ユーティリティが同梱されていない場合など、kubectl execでは不十分なときにインタラクティブなトラブルシューティングを行うために役立ちます。
特に、distrolessイメージ を利用すると、攻撃対象領域を減らし、バグや脆弱性を露出する可能性を減らせる最小のコンテナイメージをデプロイできるようになります。distrolessイメージにはシェルもデバッグ用のユーティリティも含まれないため、kubectl execのみを使用してdistrolessイメージのトラブルシューティングを行うのは困難です。
エフェメラルコンテナを利用する場合には、他のコンテナ内のプロセスにアクセスできるように、プロセス名前空間の共有 を有効にすると便利です。
次の項目
1.5 - Disruption
このガイドは、高可用性アプリケーションを構築したいと考えており、そのために、Podに対してどのような種類のDisruptionが発生する可能性があるか理解する必要がある、アプリケーション所有者を対象としたものです。
また、クラスターのアップグレードやオートスケーリングなどのクラスターの操作を自動化したいクラスター管理者も対象にしています。
自発的なDisruptionと非自発的なDisruption
Podは誰か(人やコントローラー)が破壊するか、避けることができないハードウェアまたはシステムソフトウェアエラーが発生するまで、消えることはありません。
これらの不可避なケースをアプリケーションに対する非自発的なDisruption と呼びます。例えば:
ノードのバックエンドの物理マシンのハードウェア障害
クラスター管理者が誤ってVM(インスタンス)を削除した
クラウドプロバイダーまたはハイパーバイザーの障害によってVMが消えた
カーネルパニック
クラスターネットワークパーティションが原因でクラスターからノードが消えた
ノードのリソース不足 によるPodの退避
リソース不足を除いて、これら条件は全て、大半のユーザーにとって馴染みのあるものでしょう。これらはKubernetesに固有のものではありません。
それ以外のケースのことを自発的なDisruption と呼びます。これらはアプリケーションの所有者によって起こされたアクションと、クラスター管理者によって起こされたアクションの両方を含みます。典型的なアプリケーションの所有者によるアクションには次のものがあります:
Deploymentやその他のPodを管理するコントローラーの削除
再起動を伴うDeployment内のPodのテンプレートの更新
Podの直接削除(例:アクシデントによって)
クラスター管理者のアクションには、次のようなものが含まれます:
修復やアップグレードのためのノードのドレイン 。
クラスターのスケールダウンのためにクラスターからノードをドレインする(クラスター自動スケーリング について学ぶ)。
そのノードに別のものを割り当てることができるように、ノードからPodを削除する。
これらのアクションはクラスター管理者によって直接実行されるか、クラスター管理者やクラスターをホスティングしているプロバイダーによって自動的に実行される可能性があります。
クラスターに対して自発的なDisruptionの要因となるものが有効になっているかどうかについては、クラスター管理者に聞くか、クラウドプロバイダーに相談または配布文書を参照してください。有効になっているものが何もなければ、Pod Disruption Budgetの作成はスキップすることができます。
注意: 全ての自発的なDisruptionがPod Disruption Budgetによる制約を受けるわけではありません。例えばDeploymentやPodの削除はPod Disruption Budgetをバイパスします。
Disruptionへの対応
非自発的なDisruptionを軽減する方法をいくつか紹介します:
Podは必要なリソースを要求 するようにする。
高可用性が必要な場合はアプリケーションをレプリケートする。(レプリケートされたステートレス およびステートフル アプリケーションの実行について学ぶ。)
レプリケートされたアプリケーションを実行する際にさらに高い可用性を得るには、(アンチアフィニティ を使って)ラックを横断して、または(マルチゾーンクラスター を使用している場合には)ゾーンを横断してアプリケーションを分散させる。
自発的なDisruptionの頻度は様々です。基本的なKubernetesクラスターでは、自動で発生する自発的なDisruptionはありません(ユーザーによってトリガーされたものだけです)。しかし、クラスター管理者やホスティングプロバイダーが何か追加のサービスを実行して自発的なDisruptionが発生する可能性があります。例えば、ノード上のソフトウェアアップデートのロールアウトは自発的なDisruptionの原因となります。また、クラスター(ノード)自動スケーリングの実装の中には、ノードのデフラグとコンパクト化のために自発的なDisruptionを伴うものがあります。クラスタ管理者やホスティングプロバイダーは、自発的なDisruptionがある場合、どの程度のDisruptionが予想されるかを文書化しているはずです。Podのspecの中でPriorityClassesを使用している 場合など、特定の設定オプションによっても自発的(および非自発的)なDisruptionを引き起こす可能性があります。
Pod Disruption Budget
FEATURE STATE:
Kubernetes v1.21 [stable]
Kubernetesは、自発的なDisruptionが頻繁に発生する場合でも、可用性の高いアプリケーションの運用を支援する機能を提供しています。
アプリケーションの所有者として、各アプリケーションに対してPodDisruptionBudget (PDB)を作成することができます。PDBは、レプリカを持っているアプリケーションのうち、自発的なDisruptionによって同時にダウンするPodの数を制限します。例えば、クォーラムベースのアプリケーションでは、実行中のレプリカの数がクォーラムに必要な数を下回らないようにする必要があります。Webフロントエンドは、負荷に対応するレプリカの数が、全体に対して一定の割合を下回らないようにしたいかもしれません。
クラスター管理者やホスティングプロバイダーは、直接PodやDeploymentを削除するのではなく、Eviction API を呼び出す、PodDisruptionBudgetsに配慮したツールを使用すべきです。
例えば、kubectl drainサブコマンドはノードを休止中とマークします。kubectl drainを実行すると、ツールは休止中としたノード上の全てのPodを退避しようとします。kubectlがあなたの代わりに送信する退避要求は一時的に拒否される可能性があるため、ツールは対象のノード上の全てのPodが終了するか、設定可能なタイムアウト時間に達するまで、全ての失敗した要求を定期的に再試行します。
PDBはアプリケーションの意図したレプリカ数に対して、許容できるレプリカの数を指定します。例えば.spec.replicas: 5を持つDeploymentは常に5つのPodを持つことが想定されます。PDBが同時に4つまでを許容する場合、Eviction APIは1度に(2つではなく)1つのPodの自発的なDisruptionを許可します。
アプリケーションを構成するPodのグループは、アプリケーションのコントローラー(Deployment、StatefulSetなど)が使用するものと同じラベルセレクターを使用して指定されます。
"意図した"Podの数は、これらのPodを管理するワークロードリソースの.spec.replicasから計算されます。コントロールプレーンはPodの.metadata.ownerReferencesを調べることで、所有しているワークロードリソースを見つけます。
非自発的なDisruption はPDBによって防ぐことができません;しかし、予算にはカウントされます。
アプリケーションのローリングアップデートによって削除または利用できなくなったPodはDisruptionの予算にカウントされますが、ローリングアップグレードを実行している時は(DeploymentやStatefulSetなどの)ワークロードリソースはPDBによって制限されません。代わりに、アプリケーションのアップデート中の障害のハンドリングは、個々のワークロードリソースに対するspecで設定されます。
ノードのドレイン中に動作がおかしくなったアプリケーションの退避をサポートするために、Unhealthy Pod Eviction Policy にAlwaysAllowを設定することを推奨します。既定の動作は、ドレインを継続する前にアプリケーションPodがhealthy な状態になるまで待機します。
Eviction APIを使用してPodを退避した場合、PodSpec で設定したterminationGracePeriodSecondsに従って正常に終了 します。
PodDisruptionBudgetの例
node-1からnode-3まで3つのノードがあるクラスターを考えます。クラスターにはいくつかのアプリケーションが動いています。それらのうちの1つは3つのレプリカを持ち、最初はpod-a、pod-bそしてpod-cと名前が付いています。もう一つ、これとは独立したPDBなしのpod-xと呼ばれるものもあります。初期状態ではPodは次のようにレイアウトされています:
node-1
node-2
node-3
pod-a available
pod-b available
pod-c available
pod-x available
3つのPodはすべてDeploymentの一部で、これらはまとめて1つのPDBを持ち、3つのPodのうちの少なくとも2つが常に存在していることを要求します。
例えばクラスター管理者がカーネルのバグを修正するために、再起動して新しいカーネルバージョンにしたいとします。クラスター管理者はまず、kubectl drainコマンドを使ってnode-1をドレインしようとします。ツールはpod-aとpod-xを退避しようとします。これはすぐに成功します。2つのPodは同時にterminating状態になります。これにより、クラスターは次のような状態になります:
node-1 draining
node-2
node-3
pod-a terminating
pod-b available
pod-c available
pod-x terminating
DeploymentはPodの1つが終了中であることに気づき、pod-dという代わりのPodを作成します。node-1はcordonされたため、別のノードに展開されます。また、pod-xの代わりとしてpod-yも作られました。
(備考: StatefulSetの場合、pod-aはpod-0のように呼ばれ、代わりのPodが作成される前に完全に終了する必要があります。この代わりのPodは、UIDは異なりますが、同じpod-0という名前になります。それを除けば、本例はStatefulSetにも当てはまります。)
現在、クラスターは次のような状態になっています:
node-1 draining
node-2
node-3
pod-a terminating
pod-b available
pod-c available
pod-x terminating
pod-d starting
pod-y
ある時点でPodは終了し、クラスターはこのようになります:
node-1 drained
node-2
node-3
pod-b available
pod-c available
pod-d starting
pod-y
この時点で、せっかちなクラスター管理者がnode-2かnode-3をドレインしようとすると、Deploymentの利用可能なPodは2つしかなく、また、PDBによって最低2つのPodが要求されているため、drainコマンドはブロックされます。しばらくすると、pod-dが使用可能になります。
クラスターの状態はこのようになります:
node-1 drained
node-2
node-3
pod-b available
pod-c available
pod-d available
pod-y
ここでクラスター管理者がnode-2をドレインしようとします。drainコマンドは2つのPodをなんらかの順番で退避しようとします。例えば最初にpod-b、次にpod-dとします。pod-bについては退避に成功します。しかしpod-dを退避しようとすると、Deploymentに対して利用可能なPodは1つしか残らないため、退避は拒否されます。
Deploymentはpod-bの代わりとしてpod-eを作成します。クラスターにはpod-eをスケジューリングする十分なリソースがないため、ドレインは再びブロックされます。クラスターは次のような状態になります:
node-1 drained
node-2
node-3
no node
pod-b terminating
pod-c available
pod-e pending
pod-d available
pod-y
この時点で、クラスター管理者はアップグレードを継続するためにクラスターにノードを追加する必要があります。
KubernetesがどのようにDisruptionの発生率を変化させているかについては、次のようなものから知ることができます:
いくつのレプリカをアプリケーションが必要としているか
インスタンスのグレースフルシャットダウンにどれくらいの時間がかかるか
新しいインスタンスのスタートアップにどれくらいの時間がかかるか
コントローラーの種類
クラスターリソースのキャパシティ
Pod Disruption Condition
FEATURE STATE:
Kubernetes v1.26 [beta]
備考: この機能を使用するためには、クラスターで
フィーチャーゲート PodDisruptionConditionsを有効にする必要があります。
有効にすると、専用のPod DisruptionTarget Condition が追加されます。これはPodがDisruption によって削除されようとしていることを示すものです。Conditionのreasonフィールドにて、追加で以下のいずれかをPodの終了の理由として示します:
PreemptionByScheduler
Podはより高い優先度を持つ新しいPodを収容するために、スケジューラーによってプリエンプトされる 予定です。詳細についてはPodの優先度とプリエンプション を参照してください。
DeletionByTaintManager
Podが許容しないNoExecute taintによって、Podは(kube-controller-managerの中のノードライフサイクルコントローラーである)Taintマネージャーによって削除される予定です。taint ベースの退避を参照してください。
EvictionByEvictionAPI
PodはKubernetes APIを使用して退避するように マークされました。
DeletionByPodGC
すでに存在しないノードに紐づいているPodのため、Podのガベージコレクション によって削除される予定です。
TerminationByKubelet
node-pressureによる退避 またはGraceful Node Shutdown のため、Podはkubeletによって終了させられました。
備考: PodのDisruptionは一時停止する場合があります。コントロールプレーンは同じPodに対するDisruptionを継続するために再試行するかもしれませんが、保証はされていません。その結果、DisruptionTarget ConditionはPodに付与されるかもしれませんが、実際にはPodは削除されていない可能性があります。そのような状況の場合、しばらくすると、Pod Disruption Conditionはクリアされます。
フィーチャーゲートPodDisruptionConditionsを有効にすると、Podのクリーンアップと共に、Podガベージコレクタ(PodGC)が非終了フェーズにあるPodを失敗とマークします。(Podガベージコレクション も参照してください)。
Job(またはCronJob)を使用している場合、JobのPod失敗ポリシー の一部としてこれらのPod Disruption Conditionを使用したいと思うかもしれません。
クラスターオーナーとアプリケーションオーナーロールの分離
多くの場合、クラスター管理者とアプリケーションオーナーは、互いの情報を一部しか持たない別の役割であると考えるのが便利です。このような責任の分離は、次のようなシナリオで意味を持つことがあります:
多くのアプリケーションチームでKubernetesクラスターを共有していて、役割の専門化が自然に行われている場合
クラスター管理を自動化するためにサードパーティのツールやサービスを使用している場合
Pod Disruption Budgetはロール間のインターフェースを提供することによって、この役割の分離をサポートします。
もしあなたの組織でこのような責任の分担がなされていない場合は、Pod Disruption Budgetを使用する必要はないかもしれません。
クラスターで破壊的なアクションを実行する方法
あなたがクラスターの管理者で、ノードやシステムソフトウェアのアップグレードなど、クラスター内のすべてのノードに対して破壊的なアクションを実行する必要がある場合、次のような選択肢があります:
アップグレードの間のダウンタイムを許容する。
もう一つの完全なレプリカクラスターにフェールオーバーする。
ダウンタイムはありませんが、重複するノードと、切り替えを調整する人的労力の両方のコストがかかる可能性があります。
Disruptionに耐性のあるアプリケーションを書き、PDBを使用する。
ダウンタイムはありません。
リソースの重複は最小限です。
クラスター管理をより自動化できます。
Disruptionに耐えうるアプリケーションを書くことは大変ですが、自発的なDisruptionに耐えうるようにするための作業は、非自発的なDisruptionに耐えうるために必要な作業とほぼ重複しています。
次の項目
1.6 - Pod Quality of Serviceクラス
このページでは、Kubernetesにおける Quality of Service(QoS)クラス を紹介し、Pod内のコンテナに指定したリソース制約に応じて、KubernetesがどのようにPodにQoSクラスを割り当てるのかについて説明します。Kubernetesは、ノード上で利用可能なリソースが不足した際に、どのPodを退避させるかを決定するために、このクラスを利用します。
Quality of Serviceクラス
Kubernetesは、実行中のPodを分類し、各Podを特定の Quality of Service(QoS)クラス に割り当てます。Kubernetesは、このクラスを用いてそれぞれのPodの扱い方を決定します。分類は、Pod内のコンテナ のリソース要求 と、それらの要求とリソース制限との関連性に基づいて行われます。これはQuality of Service (QoS)クラスと呼ばれます。Kubernetesは、Podのコンポーネントであるコンテナのリソース要求と制限に基づいて、すべてのPodにQoSクラスを割り当てます。QoSクラスは、ノードの圧迫 が発生しているノードからどのPodを退避させるかを決定する際に使用されます。QoSクラスにはGuaranteed、Burstable、BestEffortがあります。ノードのリソースが不足すると、KubernetesはまずBestEffort Podを退避し、次にBurstable、最後にGuaranteed Podを退避させます。リソースの圧迫による退避の場合、リソース要求を超過しているPodのみが退避の候補となります。
Guaranteed
GuaranteedのPodは最も厳しいリソース制限を持ち、退避される可能性が最も低いです。制限を超過するか、ノードからプリエンプト可能なより低い優先度のPodが存在しない限り、強制終了されることはありません。ただし、指定された制限を超えてリソースを取得することはできません。これらのPodは、static CPU管理ポリシーを使って、排他的にCPUを利用することもできます。
条件
PodがGuaranteed QoSクラスとして分類されるための条件は以下の通りです:
Pod内のすべてのコンテナが、メモリ制限とメモリ要求を持っていること。
Pod内のすべてのコンテナで、メモリ制限がメモリ要求と等しいこと。
Pod内のすべてのコンテナが、CPU制限とCPU要求を持っていること。
Pod内のすべてのコンテナで、CPU制限がCPU要求と等しいこと。
もしくは、PodがPodレベルのリソース を使用する場合は以下の通りです:
FEATURE STATE:
Kubernetes v1.34 [beta](enabled by default)
PodがPodレベルのメモリ制限とメモリ要求を持ち、それらの値が等しいこと。
PodがPodレベルのCPU制限とCPU要求を持ち、それらの値が等しいこと。
Burstable
BurstableのPodは、要求に基づく下限のリソース保証を持ちますが、特定の制限は必要としません。制限が指定されていない場合、デフォルトでノードの容量と同等の制限となり、リソースが利用可能であればPodは柔軟にリソースを増やすことができます。ノードのリソース圧迫によるPod退避の際、これらのPodは、すべてのBestEffort Podが退避されてから退避されます。Burstable Podには、リソース制限や要求を持たないコンテナを含めることができるため、BurstableなPodは任意の量のノードリソースを使おうとする可能性があります。
条件
以下の場合、PodはBurstable QoSクラスとして分類されます:
PodがGuaranteed QoSクラスの条件を満たさないこと。
Pod内の少なくとも1つのコンテナがメモリまたはCPUの要求または制限を持つか、PodがPodレベルのメモリまたはCPUの要求または制限を持つこと。
BestEffort
BestEffort QoSクラスのPodは、他のQoSクラスのPodに明示的に割り当てられていないノードリソースを使用できます。たとえば、kubeletで利用可能な16個のCPUコアを持つノードがあり、Guaranteed Podに4個のCPUコアを割り当てた場合、BestEffort QoSクラスのPodは、残りの12個のCPUコアのうち任意の量を使うことができます。
kubeletは、ノードがリソース圧迫を受けた場合、BestEffort Podを優先的に退避させます。
条件
Podは、GuaranteedまたはBurstableのいずれの条件も満たさない場合、BestEffort QoSクラスになります。つまり、Pod内のどのコンテナもメモリ制限またはメモリ要求を持たず、Pod内のどのコンテナもCPU制限またはCPU要求を持たず、PodがPodレベルのメモリまたはCPUの制限または要求を持たない場合にのみ、PodはBestEffortとなります。Pod内のコンテナは、(CPUまたはメモリ以外の)他のリソースを要求していても、BestEffortとして分類されます。
cgroup v2を使用したメモリQoS
FEATURE STATE:
Kubernetes v1.22 [alpha](disabled by default)
メモリQoSは、cgroup v2のメモリコントローラーを使用して、Kubernetesでメモリリソースを保証します。Pod内のコンテナのメモリ要求と制限は、メモリコントローラーが提供するmemory.minとmemory.highインターフェースの設定に使用されます。memory.minがメモリ要求に設定されると、メモリリソースは予約され、カーネルによって回収されることはありません。これが、メモリQoSがKubernetes Podのメモリ可用性を保証する仕組みです。また、コンテナでメモリ制限が設定されている場合、システムはコンテナのメモリ使用量を制限する必要があります。メモリQoSは、memory.highを使用してメモリ制限に近づいているワークロードの動作を抑制し、瞬間的なメモリ割り当てによってシステムが圧迫されないようにします。
メモリQoSは、QoSクラスに基づいてどの設定を適用するか決定しますが、これらは異なるメカニズムであり、どちらもQuality of Serviceに対する制御を提供します。
QoSクラスに依存しない動作
Kubernetesによって割り当てられたQoSクラスとは無関係な動作もあります。例えば、以下が該当します:
リソース制限を超過したコンテナは、そのPod内の他のコンテナに影響を与えることなく、kubeletによって強制終了され、再起動されます。
コンテナがリソース要求を超過し、実行しているノードがリソース圧迫に直面している場合、そのコンテナが含まれるPodは退避 の候補となります。このような場合、Pod内のすべてのコンテナが終了されます。Kubernetesは、通常は別のノード上に、置き換えとなるPodを作成する可能性があります。
Podのリソース要求は、コンポーネントであるコンテナのリソース要求の合計に等しく、Podのリソース制限は、コンポーネントであるコンテナのリソース制限の合計に等しくなります。
kube-schedulerは、どのPodをプリエンプト するかを選択する際に、QoSクラスを考慮しません。プリエンプションは、クラスター内に、定義したすべてのPodを実行するのに十分なリソースがない場合に発生する可能性があります。
次の項目
1.7 - Podのホスト名
このページでは、Podのホスト名を設定する方法、その設定後に起こり得る副作用、そして基盤となる仕組みについて説明します。
Podのデフォルトのホスト名
Podが作成されると、(Pod内部から観測される)そのホスト名は、Podのmetadata.nameの値から導き出されます。ホスト名と、それに対応する完全修飾ドメイン名(FQDN)の両方が(Podの視点からは)metadata.nameの値に設定されます。
apiVersion : v1
kind : Pod
metadata :
name : busybox-1
spec :
containers :
- image : busybox:1.28
command :
- sleep
- "3600"
name : busybox
このmanifestで作成されたPodは、ホスト名と完全修飾ドメイン名(FQDN)がbusybox-1に設定されます。
Podのhostnameとsubdomainフィールド
Podのspecには、オプションのhostnameフィールドがあります。この値が設定されると、Podのmetadata.nameよりも優先され、(Pod内部から観測される)ホスト名として使われます。例えば、spec.hostnameがmy-hostに設定されているPodは、ホスト名がmy-hostです。
また、Podのspecにはオプションのsubdomainフィールドもあり、Podが自分のNamespace内のサブドメインに属していることを示します。もしPodのspec.hostnameが"foo"、spec.subdomainが"bar"に設定され、さらにNamespaceがmy-namespaceの場合、ホスト名はfooで、完全修飾ドメイン名(FQDN)は(Podの内部から観測される)foo.bar.my-namespace.svc.cluster-domain.exampleです。
hostnameとsubdomainの両方が設定されていると、クラスターのDNSサーバーはこれらのフィールドに基づいてA/AAAAレコードを作成します。Podのhostnameとsubdomainフィールド を参照してください。
PodのsetHostnameAsFQDNフィールド
FEATURE STATE:
Kubernetes v1.22 [stable]
Podが完全修飾ドメイン名(FQDN)を持つように設定されている場合、そのホスト名は短いホスト名です。例えば、Podの完全修飾ドメイン名がbusybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.exampleの場合、デフォルトではそのPod内でhostnameコマンドを実行するとbusybox-1が返り、hostname --fqdnコマンドを実行するとFQDNが返ります。
setHostnameAsFQDN: trueとsubdomainフィールドがPodのspecに設定されている場合、kubeletはそのPodのNamespaceに対してFQDNをホスト名として書き込みます。この場合、hostnameとhostname --fqdnの両方がPodのFQDNを返します。
PodのFQDNは前述と同じ方法で構築されます。つまり、Podのspec.hostname(設定されている場合)またはmetadata.nameフィールド、spec.subdomain、namespace名、そしてクラスタードメインサフィックスで構成されます。
備考: Linuxでは、kernelのhostnameフィールド(struct utsnameのnodenameフィールド)は64文字に制限されています。
Podがこの機能を有効にし、そのFQDNが64文字を超える場合、起動に失敗します。そのPodはPendingステータスのままになり(kubectlからはContainerCreatingと表示)、"Failed to construct FQDN from Pod hostname and cluster domain"などのエラーイベントが生成されます。
つまり、このフィールドを使う場合、Podのmetadata.name(またはspec.hostname)とspec.subdomainフィールドを組み合わせた長さが64文字を超えないようにする必要があります。
PodのhostnameOverride
FEATURE STATE:
Kubernetes v1.35 [beta](enabled by default)
PodのspecでhostnameOverrideに値を設定すると、kubeletは無条件にその値をPodのホスト名とFQDN両方に設定します。
hostnameOverrideフィールドには64文字の長さ制限があり、RFC 1123 で定義されているDNSのサブドメイン名の基準に従う必要があります。
例:
apiVersion : v1
kind : Pod
metadata :
name : busybox-2-busybox-example-domain
spec :
hostnameOverride : busybox-2.busybox.example.domain
containers :
- image : busybox:1.28
command :
- sleep
- "3600"
name : busybox
備考: これはPod内のホスト名にのみ影響し、クラスターのDNSサーバーにおけるPodのAレコードやAAAAレコードには影響しません。
hostnameOverrideがhostnameやsubdomainフィールドと同時に設定されている場合:
備考: hostnameOverrideが設定されている場合、hostNetworkとsetHostnameAsFQDNフィールドを同時に設定することはできません。APIサーバーは、この組み合わせで作成要求が行われた場合、明示的に拒否します。
hostnameOverrideが他のフィールド(hostname、subdomain、setHostnameAsFQDN、hostNetwork)と組み合わされた時の動作の詳細については、KEP-4762の設計詳細 の表を参照してください。
1.8 - Workload参照
FEATURE STATE:
Kubernetes v1.35 [alpha](disabled by default)
PodをWorkload オブジェクトに紐づけることで、そのPodがより大きなアプリケーションやグループに属していることを示すことができます。これにより、スケジューラーは各Podを独立したエンティティとして扱うのではなく、グループとしての要件を考慮してスケジューリングを行います。
Workload参照の指定
GenericWorkload フィーチャーゲートが有効な場合、Podマニフェストでspec.workloadRefフィールドを使用できます。このフィールドは、同じ名前空間内のWorkloadリソースで定義された特定のPodグループへの紐づけを行います。
apiVersion : v1
kind : Pod
metadata :
name : worker-0
namespace : some-ns
spec :
workloadRef :
# 同じ名前空間内のWorkloadオブジェクトの名前
name : training-job-workload
# このWorkload内の特定のPodグループの名前
podGroup : workers
Podグループのレプリカ
より複雑なシナリオでは、単一のPodグループを複数の独立したスケジューリング単位に複製できます。これは、PodのworkloadRef内でpodGroupReplicaKeyフィールドを使用して実現します。このキーはラベルとして機能し、論理的なサブグループを作成します。
たとえば、minCount: 2のPodグループがあり、4つのPodを作成する場合を考えます。2つにpodGroupReplicaKey: "0"を、残り2つにpodGroupReplicaKey: "1"を設定すると、それぞれ2つのPodから構成される独立した2つのグループとして扱われます。
spec :
workloadRef :
name : training-job-workload
podGroup : workers
# レプリカキー"0"を持つすべてのworkerは、1つのグループとして一緒にスケジュールされます
podGroupReplicaKey : "0"
動作
workloadRefを定義すると、Podは参照先のPodグループで定義されたポリシー に応じて異なる動作をします。
参照先のグループがbasicポリシーを使用している場合、Workload参照は主にグループ化のためのラベルとして機能します。
参照先のグループがgangポリシーを使用している場合(かつGangScheduling フィーチャーゲートが有効な場合)、Podはgangスケジューリングのライフサイクルに入ります。この場合、Podはノードにバインドされる前に、グループ内の他のPodが作成され、スケジュールされるのを待ちます。
参照が存在しない場合
スケジューラーは、配置を決定する前にworkloadRefを検証します。
Podが、存在しないWorkloadを参照している場合、またはそのWorkload内で定義されていないPodグループを参照している場合、Podは保留状態のままになります。存在しないWorkloadオブジェクトを作成するか、不足しているPodGroup定義を含んだWorkloadを再作成するまで、配置の対象とはみなされません。
この動作は、最終的なポリシーがbasicかgangかに関係なく、workloadRefを持つすべてのPodに適用されます。スケジューラーはポリシーを決定するためにWorkload定義を必要とするためです。
次の項目
1.9 - ユーザー名前空間
FEATURE STATE:
Kubernetes v1.30 [beta]
このページでは、KubernetesのPodにおけるユーザー名前空間 について説明します。ユーザー名前空間はホストのユーザーとコンテナ内プロセスが利用するユーザーを隔離するものです。
ユーザー名前空間を使うと、コンテナ内でrootとして稼働するプロセスを、ホスト側の異なる(root以外の)ユーザーとして実行することができます。言い換えれば、ユーザー名前空間内部のリソースの操作に特権をもつプロセスは、名前空間の外側では非特権のプロセスとなっています。
ホストや他のPodに危害を及ぼす、侵害されたコンテナによる被害を軽減するために、この機能を用いることができます。HIGH ないしは CRITICAL にレートされたいくつかの脆弱性 は、ユーザー名前空間が有効な場合には悪用できないものでした。ユーザー名前空間は、将来の脆弱性を緩和することも期待できます。
始める前に
備考:  このセクションでは、Kubernetesが必要とする機能を提供するサードパーティープロジェクトにリンクしています。これらのプロジェクトはアルファベット順に記載されていて、Kubernetesプロジェクトの作者は責任を持ちません。このリストにプロジェクトを追加するには、変更を提出する前に
content guide をお読みください。
詳細はこちら。
この機能はLinux固有であり、Linuxのファイルシステムでidmapマウントがサポートされている必要があります。
ノード上で/var/lib/kubelet/pods/(ないしはそのカスタムディレクトリとして設定した場所)でidmapマウントがサポートされている必要があります。
Podのボリュームとして使われる全てのファイルシステムがidmapマウントをサポートしている必要があります。
これは、最低でもLinux 6.3以降を利用していて、かつidmapマウントをサポートするtmpfsが必要であることを意味します。一般的に、いくつかのKubernetesの機能はtmpfsを利用しています。(デフォルトでは、PodがサービスアカウントトークンやSecretをマウントする時にtmpfsを使っていたりします)。
Linux 6.3でidmapマウントをサポートするポピュラーなファイルシステムはbtrfs、ext4、xfs、fat、tmpfs、overlayfsです。
さらに、コンテナランタイムとその基盤であるOCIランタイムもユーザー名前空間をサポートしている必要があります。次のOCIランタイムではサポートが提供されています。
crun バージョン1.9以上 (推奨バージョンは1.13以上).
runc バージョン1.2以上
備考: いくつかのOCIランタイムには、LinuxのPodでユーザー名前空間を利用するのに必要なサポートが含まれていません。マネージドKubernetesを利用している場合やOCIランタイムをパッケージとしてダウンロードしてセットアップした場合には、クラスタ内のノードがユーザー名前空間をサポートしない可能性があります。
Kubernetesでユーザー名前空間を利用する際、Podでこの機能を使うためにはCRIコンテナランタイム も必要です。
containerd: バージョン2.0以上ではコンテナのユーザー名前空間をサポート。
CRI-O: バージョン1.25以上でコンテナのユーザー名前空間をサポート。
ユーザー名前空間のサポート状況については、GitHubのissue で確認できます。
導入
Linuxの機能であるユーザー名前空間を用いると、コンテナのユーザーをホスト側の異なるユーザーにマップすることができます。さらに言えば、ユーザー名前空間においてPodに付与されたケーパビリティ(capability)は、ユーザー名前空間内においてのみ有効で、外側では無効です。
Podはpod.spec.hostUsersフィールドをfalseに設定することで、ユーザー名前空間を使えるようになります。
kubeletはPodに対応する(ホストの)UID/GIDを選択した上で、同一ノードの2つ以上のPodが同じ対応関係にならないよう保証するようにしつつ、ユーザーをマップします。
pod.specにおけるrunAsUserやrunAsGroup、fsGroupなどのフィールドはコンテナ内のユーザーを指すものです。
この機能が有効化された場合、UID/GIDとして正しい値の範囲は0-65535です。これはファイルとプロセスに対して適用されます。(runAsUserやrunAsGroupなど)。
この範囲を超えるUID/GIDを利用するファイルはオーバーフローしたID(一般的には65534)に所属するように見えるでしょう。(/proc/sys/kernel/overflowuidと/proc/sys/kernel/overflowgidで設定されます)。ただし、これらのファイルは65534のユーザー/グループで稼働するプロセスであっても、編集することはできません。
rootとして動かす必要があるアプリケーションであっても、ホストにおける他のユーザー名前空間や他のリソースに対してアクセスしないものの多くは、ユーザー名前空間を有効化しても動かせますし、アプリケーションを修正しなくても問題なく動作するでしょう。
Podにおけるユーザー名前空間を理解する
いくつかのコンテナランタイム(Docker Engineやcontainer、CRI-Oなど)は、デフォルトでユーザー名前空間を利用するように設定されています。
これらのランタイムとその他の既存技術を組み合わせて使うことも可能です。(例えば、Kata ContainerはLinux名前空間の代わりにVMを利用します)。このページの内容はLinux名前空間を隔離に使うコンテナランタイムに適用できるものです。
Podを作成する時、デフォルトでは、Podの隔離にいくつかの新しい名前空間が利用されます。(コンテナネットワークの隔離のためのネットワーク名前空間、プロセスの見える範囲を隔離するためのPID名前空間など)。ユーザー名前空間を利用する場合には、コンテナ内のユーザーをノードのユーザーと隔離します。
これは、コンテナがrootとしてプロセスを動かせる一方で、ホスト上では非rootユーザーとしてマップされていることを意味します。コンテナ内部のプロセスはrootとして動作しているものと思っていることでしょう。(したがって、aptやyumなどは問題なく動作します)。しかし、実際には、このプロセスにホスト上での特権はありません。これを検証するには、例えばホスト上でps auxを実行することで、コンテナのプロセスがどのユーザーを使用しているかを確認するとよいでしょう。psが示すユーザーは、コンテナ内でidを実行した場合に示されるユーザーとは異なっているはずです。
この分離によって、ホスト上で「起こせること」を制限できます。例えばコンテナ内プロセスのホストへのエスケープを処理する場合にこの制限が有効に働きます。コンテナはホスト上で非特権のユーザーとして動作しているため、ホスト上でできることが制限されているのです。
さらに言えば、それぞれのPodのユーザーは、ホスト上においては異なるユーザーにマップされており、UID/GIDは重複しません。他のPodに対してできることさえも制限されているのです。
Podに付与されたケーパビリティについても、Podのユーザー名前空間に制限されており、名前空間の外部においてはほとんどが効力を持たず、いくつかのケーパビリティは外部では完全に無効です。2つの例を挙げます:
CAP_SYS_MODULE がユーザー名前空間を使うPodに付与されている場合、Podはカーネルモジュールをロードできません。
CAP_SYS_ADMIN はPodのユーザー名前空間の内部のみに制限され、名前空間の外部では無効です。
コンテナブレークアウトのケースについて考えてみます。この場合、ユーザー名前空間を使用せずにコンテナをrootで稼働させていると、ノードのroot権限が取得されます。さらに、ケーパビリティがコンテナに付与されていた場合には、そのケーパビリティはホスト上でも有効となっています。ユーザー名前空間を利用していれば、これらはいずれも成立しません。
ユーザー名前空間を使う場合に何が変わるのかについて詳しく知りたい場合には、man 7 user_namespacesを参照してください。
ユーザー名前空間をサポートするノードを設定する
ほとんどのLinuxディストリビューションで標準的なUIDである0-65535の範囲については、kubeletはホストのファイルやプロセスがこの範囲のUIDを利用しているものとみなし、デフォルトではこれよりも上のUID/GIDの値をPodに紐付けます。言い換えれば、0-65535の範囲のIDをPodで使うことはできません。このアプローチにより、PodとホストのUID/GIDが重複することを防ぎます。
Podによる潜在的な任意のファイル読み出しの脆弱性であるCVE-2021-25741 のような脆弱性の影響を緩和する上で、UID/GIDの重複を防ぐことは重要です。PodとホストのUID/GIDが重複しなければ、Podができることは限定されます。(PodのUID/GIDはホスト上のファイル所有者やグループと一致することがないのです)。
kubeletはPodに割り当てるユーザーIDとグループIDの範囲を変更することが可能です。カスタムの範囲を設定するには、ノードが次の条件を満たす必要があります。
ユーザーkubeletがシステム上に存在していること(他のユーザー名を使うことはできません)
getsubidsバイナリ(shadow-utils の一部)がインストールされており、kubeletバイナリが参照するPATHに入っていること
kubeletユーザーのsubordinate UID/GID (man 5 subuid およびman 5 subgid を参照)
これはsubordinate UID/GIDの範囲に関する設定のみを示しており、kubeletを実行するユーザーは変更しません。
ユーザーkubeletに割り当てるsubordinate IDの範囲に関しては、いくつかの制約に従う必要があります。
subordinate UIDの起点(つまりPodのUID範囲の開始位置)が65536の倍数に設定されていて、かつ65536以上であること( 必須 )。言い換えると、0-65535の範囲をPodのUIDとして使うことはできません。偶発的にインセキュアな設定がなされることを防ぐために、kubeletはこの制約を強制します。
subordinate UID/GIDの個数が65536の倍数であること(必須)。
subordinate UID/GIDの個数は最低でも65536 x <最大Pod数>であること(必須)。<最大Pod数>
はノードで稼働できるPodの数の最大値を表します。
UIDとGIDとして同じ個数を割り当てること(必須)。他のユーザーに対して、GIDの範囲と合致しないUID範囲を指定することは問題ありません。
割り当てられたUID/GID範囲は他の割当と重複しないこと(推奨)。
subordinate UID/GIDの設定は単一行でなされること(必須)。同一のユーザーに対して複数のUID/GID範囲を定義することはできません。
例えば、ユーザーkubeletのエントリについて、/etc/subuidと/etc/subgidに次のように定義することができます。
# フォーマットは次の通り
# name:firstID:count
# この例における意味
# - firstIDは65536 (とりうる最小の値)
# - countは110 (デフォルトの制限値) * 65536
kubelet:65536:7208960
Podセキュリティのアドミッション検証への統合
FEATURE STATE:
Kubernetes v1.29 [alpha]
ユーザー名前空間を有効化したLinuxのPodでは、KubernetesはPod Security Standards で制御されるアプリケーションの制限を緩和します。この挙動はエンドユーザーの早期オプトインを可能にするためのUserNamespacesPodSecurityStandardsフィーチャーゲート で制御することが可能です。このフィーチャーゲートを使う場合、クラスタ管理者はユーザー名前空間が全てのノードで有効化されていることを確実にする必要があります。
フィーチャーゲートを有効化した上でユーザー名前空間を使うPodを作成する場合、_Baseline_ないしは_Restricted_Podセキュリティ基準のセキュリティコンテキストが強制されていても、以下のフィールドによる制約がなされません。
spec.securityContext.runAsNonRoot
spec.containers[*].securityContext.runAsNonRoot
spec.initContainers[*].securityContext.runAsNonRoot
spec.ephemeralContainers[*].securityContext.runAsNonRoot
spec.securityContext.runAsUser
spec.containers[*].securityContext.runAsUser
spec.initContainers[*].securityContext.runAsUser
spec.ephemeralContainers[*].securityContext.runAsUser
制限
Podでユーザー名前空間を利用する際には、他のホスト名前空間を利用することはできません。特にhostUsers: falseを設定している場合、次の値を設定することはできません。
hostNetwork: true
hostIPC: true
hostPID: true
次の項目
1.10 - Downward API
Podやコンテナのフィールドを実行中のコンテナに公開する方法には2つあります。 1つは環境変数で、もう1つは特殊なボリュームタイプによってファイルとして公開する方法です。 これら2つの方法をまとめてDownward APIと呼びます。
Kubernetesに過度に密結合することなく、コンテナが自分自身についての情報を持つことは有用な場合があります。downward API を用いることで、コンテナはKubernetesのクライアントやAPIサーバーを利用せずに、自分自身やクラスターに関する情報を取得することができます。
例として、特定の既知の環境変数に一意な識別子が格納されていることを前提とする既存のアプリケーションがあるとします。一つの可能性は、アプリケーションをラップすることですが、これは煩雑でエラーが起こりやすく、疎結合という目標に反します。より良い選択肢は、Pod名を識別子として使用し、Pod名をその既知の環境変数に注入することです。
Kubernetesでは、実行中のコンテナにPodおよびコンテナフィールドを公開する方法が2つあります:
これらPodおよびコンテナフィールドを公開する2つの方法を総称して、downward API と呼びます。
利用可能なフィールド
Kubernetes APIフィールドのうち、downward APIを通じて利用可能なものは一部のみです。このセクションでは、利用可能なフィールドを列挙します。
利用可能なPodレベルのフィールドからの情報は、fieldRefを使用して渡すことができます。APIレベルでは、Podのspecは常に少なくとも1つのContainer を定義します。利用可能なコンテナレベルのフィールドからの情報は、resourceFieldRefを使用して渡すことができます。
fieldRefを通じて利用可能な情報
一部のPodレベルフィールドについては、環境変数として、またはdownwardAPIボリュームを使用して、コンテナに提供することができます。どちらのメカニズムでも利用可能なフィールドは以下の通りです:
metadata.name
Podの名前
metadata.namespace
Podのネームスペース
metadata.uid
Podの一意ID
metadata.annotations['<KEY>']
<KEY>という名前のPodのアノテーション の値(例: metadata.annotations['myannotation'])
metadata.labels['<KEY>']
<KEY>という名前のPodのラベル のテキスト値(例: metadata.labels['mylabel'])
以下の情報は環境変数を通じて利用可能ですが、downwardAPIボリュームのfieldRefとしては利用できません :
spec.serviceAccountName
Podのサービスアカウント の名前
spec.nodeName
Podが実行されているノード の名前
status.hostIP
Podが割り当てられているノードのプライマリIPアドレス
status.hostIPs
status.hostIPのデュアルスタック版のIPアドレスで、最初のIPアドレスは常にstatus.hostIPと同じです
status.podIP
PodのプライマリIPアドレス(通常、IPv4アドレス)
status.podIPs
status.podIPのデュアルスタック版のIPアドレスで、最初のIPアドレスは常にstatus.podIPと同じです
以下の情報はdownwardAPIボリュームのfieldRefを通じて利用可能ですが、環境変数としては利用できません :
metadata.labels
Podのすべてのラベルで、label-key="escaped-label-value"形式でフォーマットされ、1行に1つのラベルが記載されます
metadata.annotations
Podのすべてのアノテーションで、annotation-key="escaped-annotation-value"形式でフォーマットされ、1行に1つのアノテーションが記載されます
resourceFieldRefを通じて利用可能な情報
これらのコンテナレベルフィールドを使用すると、CPUやメモリなどのリソースの要求と制限 に関する情報を提供することができます。
備考:
FEATURE STATE:
Kubernetes v1.35 [stable](enabled by default)
コンテナのCPUとメモリリソースは、コンテナの実行中にリサイズすることができます。この場合、downward APIボリュームは更新されますが、環境変数はコンテナが再起動されない限り更新されません。詳細については、コンテナに割り当てるCPUとメモリ容量を変更する を参照してください。
resource: limits.cpu
コンテナのCPU制限
resource: requests.cpu
コンテナのCPU要求
resource: limits.memory
コンテナのメモリ制限
resource: requests.memory
コンテナのメモリ要求
resource: limits.hugepages-*
コンテナのhugepages制限
resource: requests.hugepages-*
コンテナのhugepages要求
resource: limits.ephemeral-storage
コンテナの一時ストレージ制限
resource: requests.ephemeral-storage
コンテナの一時ストレージ要求
リソース制限のフォールバック情報
コンテナにCPUとメモリの制限が指定されておらず、downward APIを使用してその情報を公開しようとする場合、kubeletはノード割り当て可能量 の計算に基づいて、CPUとメモリの最大割り当て可能値をデフォルトで公開します。
次の項目
downwardAPIボリューム について詳しく読むことができます。
downward APIを使用してコンテナレベルまたはPodレベルの情報を公開することを試してみることができます:
2 - Workload API
FEATURE STATE:
Kubernetes v1.35 [alpha](disabled by default)
Workload APIリソースを使用すると、複数のPodで構成されるアプリケーションについて、スケジューリング要件とPodのグループ構成を記述できます。ワークロードコントローラーはワークロードのランタイム動作を提供しますが、Workload APIはJobなどの「真の」ワークロードに対して、スケジューリング制約を提供することを目的としています。
Workloadとは
Workload APIリソースは、scheduling.k8s.io/v1alpha1 APIグループ の一部です(このAPIを利用するには、クラスターで、そのAPIグループとGenericWorkloadフィーチャーゲート の両方を有効にする必要があります)。このリソースは、複数のPodで構成されるアプリケーションのスケジューリング要件を、構造化された機械可読な形式で定義します。Job のようなユーザー向けのワークロードは何を実行するかを定義します。一方で、Workloadリソースは、Podのグループをどのようにスケジュールし、ライフサイクル全体を通じてその配置をどう管理するかを決定します。
APIの構造
Workloadを使用すると、Podのグループを定義し、それらにスケジューリングポリシーを適用できます。これは、Podグループのリストとコントローラーへの参照という2つのセクションで構成されます。
Podグループ
podGroupsリストは、ワークロードの個別のコンポーネントを定義します。たとえば、機械学習ジョブにはdriverグループとworkerグループがある場合があります。
podGroupsの各エントリには以下が必要です:
PodのWorkload参照 で使用できる一意のname
スケジューリングポリシー (basicまたはgang)
apiVersion : scheduling.k8s.io/v1alpha1
kind : Workload
metadata :
name : training-job-workload
namespace : some-ns
spec :
controllerRef :
apiGroup : batch
kind : Job
name : training-job
podGroups :
- name : workers
policy :
gang :
# gangは4つのPodが同時に実行できる場合にのみスケジュール可能
minCount : 4
ワークロード管理オブジェクトの参照
controllerRefフィールドは、WorkloadをJob やカスタムCRDなど、アプリケーションを定義する上位のオブジェクトに紐づけます。これは可観測性とツールの利用に役立ちます。このデータは、Workloadのスケジューリングや管理には使用されません。
次の項目
2.1 - Podグループポリシー
FEATURE STATE:
Kubernetes v1.35 [alpha](disabled by default)
Workload で定義される各Podグループは、スケジューリングポリシーを宣言する必要があります。このポリシーは、スケジューラーがPodのグループをどのように扱うかを指定します。
ポリシータイプ
現在、APIはbasicとgangの2つのポリシータイプをサポートしています。各グループに対して、いずれか1つのポリシーを指定する必要があります。
basicポリシー
basicポリシーは、グループ内のすべてのPodを独立したエンティティとして扱い、標準的なKubernetesの動作でスケジューリングするようスケジューラーに指示します。
basicポリシーを使用する主な理由は、Workload内のPodを整理して、可観測性と管理性を向上させることです。このポリシーは、同時起動を必要としないが、論理的に同じアプリケーションに属するWorkloadのグループに使用できます。また、将来的に「全か無か」の配置を意味しないグループ制約を追加する余地も残されています。
gangポリシー
gangポリシーは、「全か無か」のスケジューリングを強制します。これは、一部のPodだけが起動すると、デッドロックやリソースの浪費が発生する密結合したワークロードには必須です。
これは、すべてのワーカーが同時に実行されなければ処理が進まないJob や、その他のバッチ処理に使用できます。
gangポリシーにはminCountパラメーターが必要です:
policy :
gang :
# グループが受け入れられるために、
# 同時にスケジュール可能である必要があるPodの数
minCount : 4
次の項目
3 - ワークロードリソース
3.1 - Deployment
Deployment はPod とReplicaSet の宣言的なアップデート機能を提供します。
Deploymentにおいて 理想的な状態 を記述すると、Deploymentコントローラー は指定された頻度で現在の状態を理想的な状態に変更します。Deploymentを定義することによって、新しいReplicaSetを作成したり、既存のDeploymentを削除して新しいDeploymentで全てのリソースを適用できます。
備考: Deploymentによって作成されたReplicaSetを管理しないでください。ご自身のユースケースが以下の項目に含まれない場合、メインのKubernetesリポジトリーにIssueを作成することを検討してください。
ユースケース
以下の項目はDeploymentの典型的なユースケースです。
Deploymentの作成
以下はDeploymentの例です。これはnginxPodのレプリカを3つ持つReplicaSetを作成します。
apiVersion : apps/v1
kind : Deployment
metadata :
name : nginx-deployment
labels :
app : nginx
spec :
replicas : 3
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
この例では、
.metadata.nameフィールドで指定されたnginx-deploymentという名前のDeploymentが作成されます。
このDeploymentは.spec.replicasフィールドで指定された通り、3つのレプリカPodを作成します。
.spec.selectorフィールドは、Deploymentが管理するPodのラベルを定義します。ここでは、Podテンプレートにて定義されたラベル(app: nginx)を選択しています。しかし、PodTemplate自体がそのルールを満たす限り、さらに洗練された方法でセレクターを指定することができます。
備考: `.spec.selector.matchLabels`フィールドはキーバリューペアのマップです。
`matchLabels`マップにおいて、{key, value}というペアは、keyというフィールドの値が"key"で、その演算子が"In"で、値の配列が"value"のみ含むような`matchExpressions`の要素と等しくなります。
`matchLabels`と`matchExpressions`の両方が設定された場合、条件に一致するには両方とも満たす必要があります。
.spec.templateフィールドは、以下のサブフィールドを持ちます。:
Podは.metadata.labelsフィールドによって指定されたapp: nginxというラベルがつけられます。
PodTemplate、または.specフィールドは、Podがnginxという名前でDocker Hub にあるnginxのバージョン1.14.2が動くコンテナを1つ動かすことを示します。
1つのコンテナを作成し、.spec.containers[0].nameフィールドを使ってnginxという名前をつけます。
作成を始める前に、Kubernetesクラスターが稼働していることを確認してください。上記のDeploymentを作成するためには以下のステップにしたがってください:
以下のコマンドを実行してDeploymentを作成してください。
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
Deploymentが作成されたことを確認するために、kubectl get deploymentsを実行してください。
Deploymentがまだ作成中の場合、コマンドの実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 0/3 0 0 1s
クラスターにてDeploymentを調査するとき、以下のフィールドが出力されます。
NAMEは、クラスター内にあるDeploymentの名前一覧です。
READYは、ユーザーが使用できるアプリケーションのレプリカの数です。使用可能な数/理想的な数の形式で表示されます。
UP-TO-DATEは、理想的な状態を満たすためにアップデートが完了したレプリカの数です。
AVAILABLEは、ユーザーが利用可能なレプリカの数です。
AGEは、アプリケーションが稼働してからの時間です。
.spec.replicasフィールドの値によると、理想的なレプリカ数は3であることがわかります。
Deploymentのロールアウトステータスを確認するために、kubectl rollout status deployment.v1.apps/nginx-deploymentを実行してください。
コマンドの実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
数秒後、再度kubectl get deploymentsを実行してください。コマンドの実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
Deploymentが3つ全てのレプリカを作成して、全てのレプリカが最新(Podが最新のPodテンプレートを含んでいる)になり、利用可能となっていることを確認してください。
Deploymentによって作成されたReplicaSet(rs)を確認するにはkubectl get rsを実行してください。コマンドの実行結果は以下のとおりです:
NAME DESIRED CURRENT READY AGE
nginx-deployment-75675f5897 3 3 3 18s
ReplicaSetの出力には次のフィールドが表示されます:
NAMEは、名前空間内にあるReplicaSetの名前の一覧です。
DESIREDは、アプリケーションの理想的な レプリカ の値です。これはDeploymentを作成したときに定義したもので、これが 理想的な状態 と呼ばれるものです。
CURRENTは現在実行されているレプリカの数です。
READYは、ユーザーが使用できるアプリケーションのレプリカの数です。
AGEは、アプリケーションが稼働してからの時間です。
ReplicaSetの名前は[Deployment名]-[ランダム文字列]という形式になることに注意してください。ランダム文字列はランダムに生成され、pod-template-hashをシードとして使用します。
各Podにラベルが自動的に付けられるのを確認するにはkubectl get pods --show-labelsを実行してください。コマンドの実行結果は以下のとおりです:
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
作成されたReplicaSetはnginxPodを3つ作成することを保証します。
備考: Deploymentに対して適切なセレクターとPodテンプレートのラベルを設定する必要があります(このケースではapp: nginx)。
ラベルやセレクターを他のコントローラーと重複させないでください(他のDeploymentやStatefulSetを含む)。Kubernetesはユーザーがラベルを重複させることを阻止しないため、複数のコントローラーでセレクターの重複が発生すると、コントローラー間で衝突し予期せぬふるまいをすることになります。
pod-template-hashラベル
注意: このラベルを変更しないでください。
pod-template-hashラベルはDeploymentコントローラーによってDeploymentが作成し適用した各ReplicaSetに対して追加されます。
このラベルはDeploymentが管理するReplicaSetが重複しないことを保証します。このラベルはReplicaSetのPodTemplateをハッシュ化することにより生成され、生成されたハッシュ値はラベル値としてReplicaSetセレクター、Podテンプレートラベル、ReplicaSetが作成した全てのPodに対して追加されます。
Deploymentの更新
備考: Deploymentのロールアウトは、DeploymentのPodテンプレート(この場合.spec.template)が変更された場合にのみトリガーされます。例えばテンプレートのラベルもしくはコンテナイメージが更新された場合です。Deploymentのスケールのような更新では、ロールアウトはトリガーされません。
Deploymentを更新するには以下のステップに従ってください。
nginxのPodで、nginx:1.14.2イメージの代わりにnginx:1.16.1を使うように更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:1.16.1
または単に次のコマンドを使用します。
kubectl set image deployment/nginx-deployment nginx = nginx:1.16.1
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
また、Deploymentを編集して、.spec.template.spec.containers[0].imageをnginx:1.14.2からnginx:1.16.1に変更することができます。
kubectl edit deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment edited
ロールアウトのステータスを確認するには、以下のコマンドを実行してください。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
もしくは
deployment "nginx-deployment" successfully rolled out
更新されたDeploymentのさらなる情報を取得するには、以下を確認してください。
ロールアウトが成功したあと、kubectl get deploymentsを実行してDeploymentを確認できます。実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 36s
Deploymentが新しいReplicaSetを作成してPodを更新させたり、新しいReplicaSetのレプリカを3にスケールアップさせたり、古いReplicaSetのレプリカを0にスケールダウンさせるのを確認するにはkubectl get rsを実行してください。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
get podsを実行させると、新しいPodのみ確認できます。
実行結果は以下のとおりです。
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
次にPodを更新させたいときは、DeploymentのPodテンプレートを再度更新するだけです。
Deploymentは、Podが更新されている間に特定の数のPodのみ停止状態になることを保証します。デフォルトでは、目標とするPod数の少なくとも75%が稼働状態であることを保証します(25% max unavailable)。
また、DeploymentはPodが更新されている間に、目標とするPod数を特定の数まで超えてPodを稼働させることを保証します。デフォルトでは、目標とするPod数に対して最大でも125%を超えてPodを稼働させることを保証します(25% max surge)。
例えば、上記で説明したDeploymentの状態を注意深く見ると、最初に新しいPodが作成され、次に古いPodが削除されるのを確認できます。十分な数の新しいPodが稼働するまでは、Deploymentは古いPodを削除しません。また十分な数の古いPodが削除しない限り新しいPodは作成されません。少なくとも2つのPodが利用可能で、最大でもトータルで4つのPodが利用可能になっていることを保証します。
Deploymentの詳細情報を取得します。
kubectl describe deployments
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
最初にDeploymentを作成した時、ReplicaSet(nginx-deployment-2035384211)を作成してすぐにレプリカ数を3にスケールするのを確認できます。Deploymentを更新すると新しいReplicaSet(nginx-deployment-1564180365)を作成してレプリカ数を1にスケールアップし、古いReplicaSeetを2にスケールダウンさせます。これは常に最低でも2つのPodが利用可能で、かつ最大4つのPodが作成されている状態にするためです。Deploymentは同じローリングアップ戦略に従って新しいReplicaSetのスケールアップと古いReplicaSetのスケールダウンを続けます。最終的に新しいReplicaSetを3にスケールアップさせ、古いReplicaSetを0にスケールダウンさせます。
ロールオーバー (リアルタイムでの複数のPodの更新)
Deploymentコントローラーにより、新しいDeploymentが観測される度にReplicaSetが作成され、理想とするレプリカ数のPodを作成します。Deploymentが更新されると、既存のReplicaSetが管理するPodのラベルが.spec.selectorにマッチするが、テンプレートが.spec.templateにマッチしない場合はスケールダウンされます。最終的に、新しいReplicaSetは.spec.replicasの値にスケールアップされ、古いReplicaSetは0にスケールダウンされます。
Deploymentのロールアウトが進行中にDeploymentを更新すると、Deploymentは更新する毎に新しいReplicaSetを作成してスケールアップさせ、以前にスケールアップしたReplicaSetのロールオーバーを行います。Deploymentは更新前のReplicaSetを古いReplicaSetのリストに追加し、スケールダウンを開始します。
例えば、5つのレプリカを持つnginx:1.14.2のDeploymentを作成し、nginx:1.14.2の3つのレプリカが作成されているときに5つのレプリカを持つnginx:1.16.1に更新します。このケースではDeploymentは作成済みのnginx:1.14.2の3つのPodをすぐに削除し、nginx:1.16.1のPodの作成を開始します。nginx:1.14.2の5つのレプリカを全て作成するのを待つことはありません。
ラベルセレクターの更新
通常、ラベルセレクターを更新することは推奨されません。事前にラベルセレクターの使い方を計画しておきましょう。いかなる場合であっても更新が必要なときは十分に注意を払い、変更時の影響範囲を把握しておきましょう。
備考: apps/v1API バージョンにおいて、Deploymentのラベルセレクターは作成後に不変となります。
セレクターの追加は、Deployment Specのテンプレートラベルも新しいラベルで更新する必要があります。そうでない場合はバリデーションエラーが返されます。この変更は重複がない更新となります。これは新しいセレクターは古いセレクターを持つReplicaSetとPodを選択せず、結果として古い全てのReplicaSetがみなし子状態になり、新しいReplicaSetを作成することを意味します。
セレクターの更新により、セレクターキー内の既存の値が変更されます。これにより、セレクターの追加と同じふるまいをします。
セレクターの削除により、Deploymentのセレクターから存在している値を削除します。これはPodテンプレートのラベルに関する変更を要求しません。既存のReplicaSetはみなし子状態にならず、新しいReplicaSetは作成されませんが、削除されたラベルは既存のPodとReplicaSetでは残り続けます。
Deploymentのロールバック
例えば、クラッシュループ状態などのようにDeploymentが不安定な場合においては、Deploymentをロールバックしたくなることがあります。Deploymentの全てのロールアウト履歴は、いつでもロールバックできるようにデフォルトでシステムに保持されています(リビジョン履歴の上限は設定することで変更可能です)。
備考: Deploymentのリビジョンは、Deploymentのロールアウトがトリガーされた時に作成されます。これはDeploymentのPodテンプレート(.spec.template)が変更されたときのみ新しいリビジョンが作成されることを意味します。Deploymentのスケーリングなど、他の種類の更新においてはDeploymentのリビジョンは作成されません。これは手動もしくはオートスケーリングを同時に行うことができるようにするためです。これは過去のリビジョンにロールバックするとき、DeploymentのPodテンプレートの箇所のみロールバックされることを意味します。
nginx:1.16.1の代わりにnginx:1.161というイメージに更新して、Deploymentの更新中にタイプミスをしたと仮定します。
kubectl set image deployment/nginx-deployment nginx = nginx:1.161
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
このロールアウトはうまくいきません。ロールアウトのステータスを見るとそれを確認できます。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
ロールアウトのステータスの確認は、Ctrl-Cを押すことで停止できます。ロールアウトがうまく行かないときは、Deploymentのステータス を読んでさらなる情報を得てください。
古いレプリカ数(nginx-deployment-1564180365 and nginx-deployment-2035384211)が2になっていることを確認でき、新しいレプリカ数(nginx-deployment-3066724191)は1になっています。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 25s
nginx-deployment-2035384211 0 0 0 36s
nginx-deployment-3066724191 1 1 0 6s
作成されたPodを確認していると、新しいReplicaSetによって作成された1つのPodはコンテナイメージのpullに失敗し続けているのがわかります。
実行結果は以下のとおりです。
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
nginx-deployment-1564180365-hysrc 1/1 Running 0 25s
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
備考: Deploymentコントローラーは、この悪い状態のロールアウトを自動的に停止し、新しいReplicaSetのスケールアップを止めます。これはユーザーが指定したローリングアップデートに関するパラメーター(特に`maxUnavailable`)に依存します。デフォルトではKubernetesがこの値を25%に設定します。
Deploymentの詳細情報を取得します。
kubectl describe deployment
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.161
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created)
NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
これを修正するために、Deploymentを安定した状態の過去のリビジョンに更新する必要があります。
Deploymentのロールアウト履歴の確認
ロールアウトの履歴を確認するには、以下の手順に従って下さい。
最初に、Deploymentのリビジョンを確認します。
kubectl rollout history deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
2 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
3 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161
CHANGE-CAUSEはリビジョンの作成時にDeploymentのkubernetes.io/change-causeアノテーションからリビジョンにコピーされます。以下の方法によりCHANGE-CAUSEメッセージを指定できます。
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"の実行によりアノテーションを追加します。
リソースのマニフェストを手動で編集します。
各リビジョンの詳細を確認するためには以下のコマンドを実行してください。
kubectl rollout history deployment.v1.apps/nginx-deployment --revision= 2
実行結果は以下のとおりです。
deployments "nginx-deployment" revision 2
Labels: app=nginx
pod-template-hash=1159050644
Annotations: kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
QoS Tier:
cpu: BestEffort
memory: BestEffort
Environment Variables: <none>
No volumes.
過去のリビジョンにロールバックする
現在のリビジョンから過去のリビジョン(リビジョン番号2)にロールバックさせるには、以下の手順に従ってください。
現在のリビジョンから過去のリビジョンにロールバックします。
kubectl rollout undo deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment rolled back
その他に、--to-revisionを指定することにより特定のリビジョンにロールバックできます。
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision= 2
実行結果は以下のとおりです。
deployment.apps/nginx-deployment rolled back
ロールアウトに関連したコマンドのさらなる情報はkubectl rollout を参照してください。
Deploymentが過去の安定したリビジョンにロールバックされました。Deploymentコントローラーによって、リビジョン番号2にロールバックするDeploymentRollbackイベントが作成されたのを確認できます。
ロールバックが成功し、Deploymentが正常に稼働していることを確認するために、以下のコマンドを実行してください。
kubectl get deployment nginx-deployment
実行結果は以下のとおりです。
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 30m
Deploymentの詳細情報を取得します。
kubectl describe deployment nginx-deployment
実行結果は以下のとおりです。
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=4
kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1
Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2
Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Deploymentのスケーリング
以下のコマンドを実行させてDeploymentをスケールできます。
kubectl scale deployment.v1.apps/nginx-deployment --replicas= 10
実行結果は以下のとおりです。
deployment.apps/nginx-deployment scaled
クラスター内で水平Podオートスケーラー が有効になっていると仮定します。ここでDeploymentのオートスケーラーを設定し、稼働しているPodのCPU使用量に基づいて、稼働させたいPodのレプリカ数の最小値と最大値を設定できます。
kubectl autoscale deployment.v1.apps/nginx-deployment --min= 10 --max= 15 --cpu-percent= 80
実行結果は以下のとおりです。
deployment.apps/nginx-deployment scaled
比例スケーリング
Deploymentのローリングアップデートは、同時に複数のバージョンのアプリケーションの稼働をサポートします。ユーザーやオートスケーラーがローリングアップデートをロールアウト中(更新中もしくは一時停止中)のDeploymentに対して行うと、Deploymentコントローラーはリスクを削減するために既存のアクティブなReplicaSetのレプリカのバランシングを行います。これを比例スケーリング と呼びます。
レプリカ数が10、maxSurge =3、maxUnavailable =2であるDeploymentが稼働している例です。
Deployment内で10のレプリカが稼働していることを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 10 10 10 10 50s
クラスター内で、解決できない新しいイメージに更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:sometag
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
イメージの更新は新しいReplicaSet nginx-deployment-1989198191へのロールアウトを開始させます。しかしロールアウトは、上述したmaxUnavailableの要求によりブロックされます。ここでロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 5 5 0 9s
nginx-deployment-618515232 8 8 8 1m
次にDeploymentのスケーリングをするための新しい要求が発生します。オートスケーラーはDeploymentのレプリカ数を15に増やします。Deploymentコントローラーは新しい5つのレプリカをどこに追加するか決める必要がでてきます。比例スケーリングを使用していない場合、5つのレプリカは全て新しいReplicaSetに追加されます。比例スケーリングでは、追加されるレプリカは全てのReplicaSetに分散されます。比例割合が大きいものはレプリカ数の大きいReplicaSetとなり、比例割合が低いときはレプリカ数の小さいReplicaSetとなります。残っているレプリカはもっとも大きいレプリカ数を持つReplicaSetに追加されます。レプリカ数が0のReplicaSetはスケールアップされません。
上記の例では、3つのレプリカが古いReplicaSetに追加され、2つのレプリカが新しいReplicaSetに追加されました。ロールアウトの処理では、新しいレプリカ数のPodが正常になったと仮定すると、最終的に新しいReplicaSetに全てのレプリカを移動させます。これを確認するためには以下のコマンドを実行して下さい。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
ロールアウトのステータスでレプリカがどのように各ReplicaSetに追加されるか確認できます。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Deployment更新の一時停止と再開
ユーザーは1つ以上の更新処理をトリガーする前に更新の一時停止と再開ができます。これにより、不必要なロールアウトを実行することなく一時停止と再開を行う間に複数の修正を反映できます。
例えば、作成直後のDeploymentを考えます。Deploymentの詳細情報を確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
ロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
以下のコマンドを実行して更新処理の一時停止を行います。
kubectl rollout pause deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment paused
次にDeploymentのイメージを更新します。
kubectl set image deployment.v1.apps/nginx-deployment nginx = nginx:1.16.1
実行結果は以下のとおりです。
deployment.apps/nginx-deployment image updated
新しいロールアウトが開始されていないことを確認します。
kubectl rollout history deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
Deploymentの更新に成功したことを確認するためにロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 2m
更新は何度でも実行できます。例えば、Deploymentが使用するリソースを更新します。
kubectl set resources deployment.v1.apps/nginx-deployment -c= nginx --limits= cpu = 200m,memory= 512Mi
実行結果は以下のとおりです。
deployment.apps/nginx-deployment resource requirements updated
一時停止する前の初期状態では更新処理は機能しますが、Deploymentが一時停止されている間は新しい更新処理は反映されません。
最後に、Deploymentの稼働を再開させ、新しいReplicaSetが更新内容を全て反映させているのを確認します。
kubectl rollout resume deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
deployment.apps/nginx-deployment resumed
更新処理が完了するまでロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 2 2 2 2m
nginx-3926361531 2 2 0 6s
nginx-3926361531 2 2 1 18s
nginx-2142116321 1 2 2 2m
nginx-2142116321 1 2 2 2m
nginx-3926361531 3 2 1 18s
nginx-3926361531 3 2 1 18s
nginx-2142116321 1 1 1 2m
nginx-3926361531 3 3 1 18s
nginx-3926361531 3 3 2 19s
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 20s
最新のロールアウトのステータスを確認します。
実行結果は以下のとおりです。
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
備考: Deploymentの稼働を再開させない限り、一時停止したDeploymentをロールバックすることはできません。
Deploymentのステータス
Deploymentは、そのライフサイクルの間に様々な状態に遷移します。新しいReplicaSetへのロールアウト中は進行中 になり、その後は完了 し、また失敗 にもなります。
Deploymentの更新処理
以下のタスクが実行中のとき、KubernetesはDeploymentの状態を 進行中 にします。
Deploymentが新しいReplicaSetを作成します。
Deploymentが新しいReplicaSetをスケールアップさせています。
Deploymentが古いReplicaSetをスケールダウンさせています。
新しいPodが準備中もしくは利用可能な状態になります(少なくともMinReadySeconds の間は準備中になります)。
kubectl rollout statusを実行すると、Deploymentの進行状態を確認できます。
Deploymentの更新処理の完了
Deploymentが以下の状態になったとき、KubernetesはDeploymentのステータスを 完了 にします。
Deploymentの全てのレプリカが、指定された最新のバージョンに更新されます。これは指定した更新処理が完了したことを意味します。
Deploymentの全てのレプリカが利用可能になります。
Deploymentの古いレプリカが1つも稼働していません。
kubectl rollout statusを実行して、Deploymentの更新が完了したことを確認できます。ロールアウトが正常に完了するとkubectl rollout statusの終了コードが0で返されます。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
そしてkubectl rolloutの終了ステータスが0となります(成功です):
0
Deploymentの更新処理の失敗
新しいReplicaSetのデプロイが完了せず、更新処理が止まる場合があります。これは主に以下の要因によるものです。
不十分なリソースの割り当て
ReadinessProbeの失敗
コンテナイメージの取得ができない
不十分なパーミッション
リソースリミットのレンジ
アプリケーションランタイムの設定の不備
このような状況を検知する1つの方法として、Deploymentのリソース定義でデッドラインのパラメーターを指定します(.spec.progressDeadlineSeconds )。.spec.progressDeadlineSecondsはDeploymentの更新が停止したことを示す前にDeploymentコントローラーが待つ秒数を示します。
以下のkubectlコマンドでリソース定義にprogressDeadlineSecondsを設定します。これはDeploymentの更新が止まってから10分後に、コントローラーが失敗を通知させるためです。
kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
実行結果は以下のとおりです。
deployment.apps/nginx-deployment patched
一度デッドラインを超過すると、DeploymentコントローラーはDeploymentの.status.conditionsに以下のDeploymentConditionを追加します。
Type=Progressing
Status=False
Reason=ProgressDeadlineExceeded
ステータスの状態に関するさらなる情報はKubernetes APIの規則 を参照してください。
備考: Kubernetesは停止状態のDeploymentに対して、ステータス状態を報告する以外のアクションを実行しません。高レベルのオーケストレーターはこれを利用して、状態に応じて行動できます。例えば、前のバージョンへのDeploymentのロールバックが挙げられます。
備考: Deploymentを停止すると、Kubernetesは指定したデッドラインを超えたかどうかチェックしません。ロールアウトの途中でもDeploymentを安全に一時停止でき、デッドラインを超えたイベントをトリガーすることなく再開できます。
設定したタイムアウトの秒数が小さかったり、一時的なエラーとして扱える他の種類のエラーが原因となり、Deploymentで一時的なエラーが出る場合があります。例えば、リソースの割り当てが不十分な場合を考えます。Deploymentの詳細情報を確認すると、以下のセクションが表示されます。
kubectl describe deployment nginx-deployment
実行結果は以下のとおりです。
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
kubectl get deployment nginx-deployment -o yamlを実行すると、Deploymentのステータスは以下のようになります。
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
最後に、一度Deploymentの更新処理のデッドラインを越えると、KubernetesはDeploymentのステータスと進行中の状態を更新します。
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Deploymentか他のリソースコントローラーのスケールダウンを行うか、使用している名前空間内でリソースの割り当てを増やすことで、リソースの割り当て不足の問題に対処できます。割り当て条件を満たすと、DeploymentコントローラーはDeploymentのロールアウトを完了させ、Deploymentのステータスが成功状態になるのを確認できます(Status=TrueとReason=NewReplicaSetAvailable)。
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Status=TrueのType=Availableは、Deploymentが最小可用性の状態であることを意味します。最小可用性は、Deploymentの更新戦略において指定されているパラメーターにより決定されます。Status=TrueのType=Progressingは、Deploymentのロールアウトの途中で、更新処理が進行中であるか、更新処理が完了し、必要な最小数のレプリカが利用可能であることを意味します(各TypeのReason項目を確認してください。このケースでは、Reason=NewReplicaSetAvailableはDeploymentの更新が完了したことを意味します)。
kubectl rollout statusを実行してDeploymentが更新に失敗したかどうかを確認できます。kubectl rollout statusはDeploymentが更新処理のデッドラインを超えたときに0以外の終了コードを返します。
kubectl rollout status deployment.v1.apps/nginx-deployment
実行結果は以下のとおりです。
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
そしてkubectl rolloutの終了ステータスが1となります(エラーを示しています):
1
失敗したDeploymentの操作
更新完了したDeploymentに適用した全てのアクションは、更新失敗したDeploymentに対しても適用されます。スケールアップ、スケールダウンができ、前のリビジョンへのロールバックや、Deploymentのテンプレートに複数の更新を適用させる必要があるときは一時停止もできます。
古いリビジョンのクリーンアップポリシー
Deploymentが管理する古いReplicaSetをいくつ保持するかを指定するために、.spec.revisionHistoryLimitフィールドを設定できます。この値を超えた古いReplicaSetはバックグラウンドでガーベージコレクションの対象となって削除されます。デフォルトではこの値は10です。
備考: このフィールドを明示的に0に設定すると、Deploymentの全ての履歴を削除します。従って、Deploymentはロールバックできません。
カナリアパターンによるデプロイ
Deploymentを使って一部のユーザーやサーバーに対してリリースのロールアウトをしたい場合、リソースの管理 に記載されているカナリアパターンに従って、リリース毎に1つずつ、複数のDeploymentを作成できます。
Deployment Specの記述
他の全てのKubernetesの設定と同様に、Deploymentは.apiVersion、.kindや.metadataフィールドを必要とします。設定ファイルの利用に関する情報はアプリケーションのデプロイ を参照してください。コンテナの設定に関してはリソースを管理するためのkubectlの使用 を参照してください。Deploymentオブジェクトの名前は、有効なDNSサブドメイン名 でなければなりません。Deploymentは.specセクション も必要とします。
Podテンプレート
.spec.templateと.spec.selectorは.specにおける必須のフィールドです。
.spec.templateはPodテンプレート です。これは.spec内でネストされていないことと、apiVersionやkindを持たないことを除いてはPod と同じスキーマとなります。
Podの必須フィールドに加えて、Deployment内のPodテンプレートでは適切なラベルと再起動ポリシーを設定しなくてはなりません。ラベルは他のコントローラーと重複しないようにしてください。ラベルについては、セレクター を参照してください。
.spec.template.spec.restartPolicy がAlwaysに等しいときのみ許可されます。これはテンプレートで指定されていない場合のデフォルト値です。
レプリカ数
.spec.repliasは理想的なPodの数を指定するオプションのフィールドです。デフォルトは1です。
セレクター
.spec.selectorは必須フィールドで、Deploymentによって対象とされるPodのラベルセレクター を指定します。
.spec.selectorは.spec.template.metadata.labelsと一致している必要があり、一致しない場合はAPIによって拒否されます。
apps/v1バージョンにおいて、.spec.selectorと.metadata.labelsが指定されていない場合、.spec.template.metadata.labelsの値に初期化されません。そのため.spec.selectorと.metadata.labelsを明示的に指定する必要があります。またapps/v1のDeploymentにおいて.spec.selectorは作成後に不変になります。
Deploymentのテンプレートが.spec.templateと異なる場合や、.spec.replicasの値を超えてPodが稼働している場合、Deploymentはセレクターに一致するラベルを持つPodを削除します。Podの数が理想状態より少ない場合Deploymentは.spec.templateをもとに新しいPodを作成します。
備考: Deploymentのセレクターに一致するラベルを持つPodを直接作成したり、他のDeploymentやReplicaSetやReplicationControllerによって作成するべきではありません。作成してしまうと、最初のDeploymentがラベルに一致する新しいPodを作成したとみなされます。こうなったとしても、Kubernetesは処理を止めません。
セレクターが重複する複数のコントローラーを持つとき、そのコントローラーは互いに競合状態となり、正しくふるまいません。
更新戦略
.spec.strategyは古いPodから新しいPodに置き換える際の更新戦略を指定します。.spec.strategy.typeは"Recreate"もしくは"RollingUpdate"を指定できます。デフォルトは"RollingUpdate"です。
Deploymentの再作成
.spec.strategy.type==Recreateと指定されているとき、既存の全てのPodは新しいPodが作成される前に削除されます。
備考: これは更新のための作成の前にPodを停止する事を保証するだけです。Deploymentを更新する場合、古いリビジョンのPodは全てすぐに停止されます。削除に成功するまでは、新しいリビジョンのPodは作成されません。手動でPodを削除すると、ライフサイクルがReplicaSetに制御されているのですぐに置き換えが実施されます(たとえ古いPodがまだ停止中のステータスでも)。Podに"高々この程度の"保証を求めるならば
StatefulSet の使用を検討してください。
Deploymentのローリングアップデート
.spec.strategy.type==RollingUpdateと指定されているとき、DeploymentはローリングアップデートによりPodを更新します。ローリングアップデートの処理をコントロールするためにmaxUnavailableとmaxSurgeを指定できます。
Max Unavailable
.spec.strategy.rollingUpdate.maxUnavailableはオプションのフィールドで、更新処理において利用不可となる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り捨てされて計算されます。.spec.strategy.rollingUpdate.maxSurgeが0に指定されている場合、この値を0にできません。デフォルトでは25%です。
例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると古いReplicaSetはすぐに理想状態の70%にスケールダウンされます。一度新しいPodが稼働できる状態になると、古いReplicaSetはさらにスケールダウンされ、続いて新しいReplicaSetがスケールアップされます。この間、利用可能なPodの総数は理想状態のPodの少なくとも70%以上になるように保証されます。
Max Surge
.spec.strategy.rollingUpdate.maxSurgeはオプションのフィールドで、理想状態のPod数を超えて作成できる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り上げで計算されます。MaxUnavailableが0に指定されている場合、この値を0にできません。デフォルトでは25%です。
例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると新しいReplicaSetはすぐに更新されます。このとき古いPodと新しいPodの総数は理想状態の130%を超えないように更新されます。一度古いPodが削除されると、新しいReplicaSetはさらにスケールアップされます。この間、利用可能なPodの総数は理想状態のPodに対して最大130%になるように保証されます。
Progress Deadline Seconds
.spec.progressDeadlineSecondsはオプションのフィールドで、システムがDeploymentの更新に失敗 したと判断するまでに待つ秒数を指定します。更新に失敗したと判断されたとき、リソースのステータスはType=Progressing、Status=FalseかつReason=ProgressDeadlineExceededとなるのを確認できます。DeploymentコントローラーはDeploymentの更新のリトライし続けます。デフォルト値は600です。今後、自動的なロールバックが実装されたとき、更新失敗状態になるとすぐにDeploymentコントローラーがロールバックを行うようになります。
この値が指定されているとき、.spec.minReadySecondsより大きい値を指定する必要があります。
Min Ready Seconds
.spec.minReadySecondsはオプションのフィールドで、新しく作成されたPodが利用可能となるために、最低どれくらいの秒数コンテナがクラッシュすることなく稼働し続ければよいかを指定するものです。デフォルトでは0です(Podは作成されるとすぐに利用可能と判断されます)。Podが利用可能と判断された場合についてさらに学ぶためにContainer Probes を参照してください。
リビジョン履歴の保持上限
Deploymentのリビジョン履歴は、Deploymentが管理するReplicaSetに保持されています。
.spec.revisionHistoryLimitはオプションのフィールドで、ロールバック可能な古いReplicaSetの数を指定します。この古いReplicaSetはetcd内のリソースを消費し、kubectl get rsの出力結果を見にくくします。Deploymentの各リビジョンの設定はReplicaSetに保持されます。このため一度古いReplicaSetが削除されると、そのリビジョンのDeploymentにロールバックすることができなくなります。デフォルトでは10もの古いReplicaSetが保持されます。しかし、この値の最適値は新しいDeploymentの更新頻度と安定性に依存します。
さらに詳しく言うと、この値を0にすると、0のレプリカを持つ古い全てのReplicaSetが削除されます。このケースでは、リビジョン履歴が完全に削除されているため新しいDeploymentのロールアウトを元に戻すことができません。
paused
.spec.pausedはオプションのboolean値で、Deploymentの一時停止と再開のための値です。一時停止されているものと、そうでないものとの違いは、一時停止されているDeploymentはPodTemplateSpecのいかなる変更があってもロールアウトがトリガーされないことです。デフォルトではDeploymentは一時停止していない状態で作成されます。
3.2 - ReplicaSet
ReplicaSetの目的は、どのような時でも安定したレプリカPodのセットを維持することです。これは、理想的なレプリカ数のPodが利用可能であることを保証するものとして使用されます。
ReplicaSetがどのように動くか
ReplicaSetは、ReplicaSetが対象とするPodをどう特定するかを示すためのセレクターや、稼働させたいPodのレプリカ数、Podテンプレート(理想のレプリカ数の条件を満たすために作成される新しいPodのデータを指定するために用意されるもの)といったフィールドとともに定義されます。ReplicaSetは、指定された理想のレプリカ数にするためにPodの作成と削除を行うことにより、その目的を達成します。ReplicaSetが新しいPodを作成するとき、ReplicaSetはそのPodテンプレートを使用します。
ReplicaSetがそのPod群と連携するためのリンクは、Podのmetadata.ownerReferences というフィールド(現在のオブジェクトが所有されているリソースを指定する)を介して作成されます。ReplicaSetによって所持された全てのPodは、それらのownerReferencesフィールドにReplicaSetを特定する情報を保持します。このリンクを通じて、ReplicaSetは管理しているPodの状態を把握したり、その後の実行計画を立てます。
ReplicaSetは、そのセレクターを使用することにより、所有するための新しいPodを特定します。もしownerReferenceフィールドの値を持たないPodか、ownerReferenceフィールドの値が コントローラー でないPodで、そのPodがReplicaSetのセレクターとマッチした場合に、そのPodは即座にそのReplicaSetによって所有されます。
ReplicaSetを使うとき
ReplicaSetはどんな時でも指定された数のPodのレプリカが稼働することを保証します。しかし、DeploymentはReplicaSetを管理する、より上位レベルの概念で、Deploymentはその他の多くの有益な機能と共に、宣言的なPodのアップデート機能を提供します。それゆえ、我々はユーザーが独自のアップデートオーケストレーションを必要としたり、アップデートを全く必要としないような場合を除いて、ReplicaSetを直接使うよりも代わりにDeploymentを使うことを推奨します。
これは、ユーザーがReplicaSetのオブジェクトを操作する必要が全く無いことを意味します。代わりにDeploymentを使用して、specセクションにユーザーのアプリケーションを定義してください。
ReplicaSetの使用例
apiVersion : apps/v1
kind : ReplicaSet
metadata :
name : frontend
labels :
app : guestbook
tier : frontend
spec :
# ケースに応じてレプリカを修正する
replicas : 3
selector :
matchLabels :
tier : frontend
template :
metadata :
labels :
tier : frontend
spec :
containers :
- name : php-redis
image : gcr.io/google_samples/gb-frontend:v3
上記のマニフェストをfrontend.yamlファイルに保存しKubernetesクラスターに適用すると、マニフェストに定義されたReplicaSetとそれが管理するPod群を作成します。
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
ユーザーはデプロイされた現在のReplicaSetの情報も取得できます。
そして、ユーザーが作成したfrontendリソースについての情報も取得できます。
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
ユーザーはまたReplicaSetの状態も確認できます。
kubectl describe rs/frontend
その結果は以下のようになります。
Name: frontend
Namespace: default
Selector: tier=frontend
Labels: app=guestbook
tier=frontend
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",...
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts
そして最後に、ユーザーはReplicaSetによって作成されたPodもチェックできます。
表示されるPodに関する情報は以下のようになります。
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 6m36s
frontend-vcmts 1/1 Running 0 6m36s
frontend-wtsmm 1/1 Running 0 6m36s
ユーザーはまた、それらのPodのownerReferencesがfrontendReplicaSetに設定されていることも確認できます。これを確認するためには、稼働しているPodの中のどれかのyamlファイルを取得します。
kubectl get pods frontend-b2zdv -o yaml
その表示結果は、以下のようになります。そのfrontendReplicaSetの情報がmetadataのownerReferencesフィールドにセットされています。
apiVersion : v1
kind : Pod
metadata :
creationTimestamp : "2020-02-12T07:06:16Z"
generateName : frontend-
labels :
tier : frontend
name : frontend-b2zdv
namespace : default
ownerReferences :
- apiVersion : apps/v1
blockOwnerDeletion : true
controller : true
kind : ReplicaSet
name : frontend
uid : f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf
...
テンプレートなしのPodの所有
ユーザーが問題なくベアPod(Bare Pod: ここではPodテンプレート無しのPodのこと)を作成しているとき、そのベアPodがユーザーのReplicaSetの中のいずれのセレクターともマッチしないことを確認することを強く推奨します。この理由として、ReplicaSetは、所有対象のPodがReplicaSetのテンプレートによって指定されたPodのみに限定されていないからです(ReplicaSetは前のセクションで説明した方法によって他のPodも所有できます)。
前のセクションで取り上げたfrontendReplicaSetと、下記のマニフェストのPodをみてみます。
apiVersion : v1
kind : Pod
metadata :
name : pod1
labels :
tier : frontend
spec :
containers :
- name : hello1
image : gcr.io/google-samples/hello-app:2.0
---
apiVersion : v1
kind : Pod
metadata :
name : pod2
labels :
tier : frontend
spec :
containers :
- name : hello2
image : gcr.io/google-samples/hello-app:1.0
これらのPodはownerReferencesに何のコントローラー(もしくはオブジェクト)も指定されておらず、そしてfrontendReplicaSetにマッチするセレクターをもっており、これらのPodは即座にfrontendReplicaSetによって所有されます。
このfrontendReplicaSetがデプロイされ、初期のPodレプリカがレプリカ数の要求を満たすためにセットアップされた後で、ユーザーがそのPodを作成することを考えます。
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
新しいPodはそのReplicaSetによって所有され、そのReplicaSetのレプリカ数が、設定された理想のレプリカ数を超えた場合すぐにそれらのPodは削除されます。
下記のコマンドでPodを取得できます。
その表示結果で、新しいPodがすでに削除済みか、削除中のステータスになっているのを確認できます。
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 10m
frontend-vcmts 1/1 Running 0 10m
frontend-wtsmm 1/1 Running 0 10m
pod1 0/1 Terminating 0 1s
pod2 0/1 Terminating 0 1s
もしユーザーがそのPodを最初に作成する場合
kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml
そしてその後にfrontendReplicaSetを作成すると、
kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml
ユーザーはそのReplicaSetが作成したPodを所有し、さらにもともと存在していたPodと今回新たに作成されたPodの数が、理想のレプリカ数になるまでPodを作成するのを確認できます。ここでまたPodの状態を取得します。
取得結果は下記のようになります。
NAME READY STATUS RESTARTS AGE
frontend-hmmj2 1/1 Running 0 9s
pod1 1/1 Running 0 36s
pod2 1/1 Running 0 36s
この方法で、ReplicaSetはテンプレートで指定されたもの以外のPodを所有することができます。
ReplicaSetのマニフェストを記述する。
他の全てのKubernetes APIオブジェクトのように、ReplicaSetはapiVersion、kindとmetadataフィールドを必要とします。ReplicaSetでは、kindフィールドの値はReplicaSetです。
ReplicaSetオブジェクトの名前は、有効なDNSサブドメイン名 である必要があります。
また、ReplicaSetは.spec セクション も必須です。
Pod テンプレート
.spec.templateはラベルを持つことが必要なPodテンプレート です。先ほど作成したfrontend.yamlの例では、tier: frontendというラベルを1つ持っています。他のコントローラーがこのPodを所有しようとしないためにも、他のコントローラーのセレクターでラベルを上書きしないように注意してください。
テンプレートの再起動ポリシー のためのフィールドである.spec.template.spec.restartPolicyはAlwaysのみ許可されていて、そしてそれがデフォルト値です。
Pod セレクター
.spec.selectorフィールドはラベルセレクター です。先ほど 議論したように、ReplicaSetが所有するPodを指定するためにそのラベルが使用されます。先ほどのfrontend.yamlの例では、そのセレクターは下記のようになっていました
matchLabels :
tier : frontend
そのReplicaSetにおいて、.spec.template.metadata.labelsフィールドの値はspec.selectorと一致しなくてはならず、一致しない場合はAPIによって拒否されます。
備考: 2つのReplicaSetが同じ.spec.selectorの値を設定しているが、それぞれ異なる.spec.template.metadata.labelsと.spec.template.specフィールドの値を持っていたとき、それぞれのReplicaSetはもう一方のReplicaSetによって作成されたPodを無視します。
レプリカ数について
ユーザーは.spec.replicasフィールドの値を設定することにより、いくつのPodを同時に稼働させるか指定できます。そのときReplicaSetはレプリカ数がこの値に達するまでPodを作成、または削除します。
もしユーザーが.spec.replicasを指定しない場合、デフォルト値として1がセットされます。
ReplicaSetを利用する
ReplicaSetとPodの削除
ReplicaSetとそれが所有する全てのPod削除したいときは、kubectl delete コマンドを使ってください。
ガベージコレクター がデフォルトで自動的に全ての依存するPodを削除します。
REST APIもしくはclient-goライブラリーを使用するとき、ユーザーは-dオプションでpropagationPolicyをBackgroundかForegroundと指定しなくてはなりません。例えば下記のように実行します。
kubectl proxy --port= 8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
ReplicaSetのみを削除する
ユーザーはkubectl delete コマンドで--cascade=falseオプションを付けることにより、所有するPodに影響を与えることなくReplicaSetを削除できます。REST APIもしくはclient-goライブラリーを使用するとき、ユーザーは-dオプションでpropagationPolicyをOrphanと指定しなくてはなりません。例えば下記のように実行します:
kubectl proxy --port= 8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
一度元のReplicaSetが削除されると、ユーザーは新しいものに置き換えるため新しいReplicaSetを作ることができます。新旧のReplicaSetの.spec.selectorの値が同じである間、新しいReplicaSetは古いReplicaSetで稼働していたPodを取り入れます。しかし、存在するPodが新しく異なるPodテンプレートとマッチさせようとするとき、この仕組みは機能しません。ReplicaSetはローリングアップデートを直接サポートしないため、ユーザーのコントロール下においてPodを新しいspecにアップデートしたい場合は、Deployment を使用してください。
PodをReplicaSetから分離させる
ユーザーはPodのラベルを変更することにより、ReplicaSetからそのPodを削除できます。この手法はデバッグや、データ修復などのためにサービスからPodを削除したいときに使用できます。この方法で削除されたPodは自動的に新しいものに置き換えられます。(レプリカ数は変更されないものと仮定します。)
ReplicaSetのスケーリング
ReplicaSetは、ただ.spec.replicasフィールドを更新することによって簡単にスケールアップまたはスケールダウンできます。ReplicaSetコントローラーは、ラベルセレクターにマッチするような指定した数のPodが利用可能であり、操作可能であることを保証します。
スケールダウンする場合、ReplicaSetコントローラーは以下の一般的なアルゴリズムに基づき、利用可能なPodをソートし、スケールダウンするPodの優先順位を付け、削除するPodを選択します:
保留している(またはスケジュール不可な)Podが先にスケールダウンされます。
controller.kubernetes.io/pod-deletion-costアノテーションが設定されている場合、値の小さいPodが優先されます。
レプリカ数の多いノード上のPodが、レプリカ数の少ないノード上のPodより優先されます。
Podの作成時間が異なる場合、より新しく作成されたPodが古いPodより優先されます(LogarithmicScaleDownフィーチャーゲート が有効の場合、作成時間は整数対数スケールでバケット化されます)。
上記条件のすべてに該当する場合は、ランダム選択となります。
Pod削除コスト
FEATURE STATE:
Kubernetes v1.22 [beta]
controller.kubernetes.io/pod-deletion-cost アノテーションを使用すると、ReplicaSetをスケールダウンする際に、どのPodを最初に削除するかについて、ユーザーが優先順位を設定することができます。
アノテーションはPodに設定する必要があり、範囲は[-2147483648, 2147483647]になります。同じReplicaSetに属する他のPodと比較して、Podを削除する際のコストを表しています。削除コストの低いPodは、削除コストの高いPodより優先的に削除されます。
このアノテーションを設定しないPodは暗黙的に0と設定され、負の値は許容されます。無効な値はAPIサーバーによって拒否されます。
この機能はbeta版で、デフォルトで有効になっています。kube-apiserverとkube-controller-managerでフィーチャーゲート PodDeletionCostを設定することで無効にすることができます。
備考:
これはベストエフォートで実行されているもので、Pod削除の順番を保証するものではありません。
ユーザーは、メトリック値に基づいてアノテーションを更新するなど、頻繁に更新することは避けるべきです。APIサーバー上で大量のPodの更新操作を発生させることになるためです。
使用事例
アプリケーションの異なるPodは、異なる使用レベルになる可能性があります。スケールダウンする場合、アプリケーションは使用率の低いPodを削除することを優先しています。Podを頻繁に更新することを避けるため、アプリケーションはスケールダウンする前に一度controller.kubernetes.io/pod-deletion-costを更新する必要があります(アノテーションをPod使用レベルに比例する値に設定します)。Spark DeploymentのドライバーPodのように、アプリケーション自体がスケールダウンを制御する場合も機能します。
HorizontalPodAutoscaler(HPA)のターゲットとしてのReplicaSet
ReplicaSetはまた、Horizontal Pod Autoscalers (HPA) のターゲットにもなることができます。これはつまりReplicaSetがHPAによってオートスケールされうることを意味します。ここではHPAが、前の例で作成したReplicaSetをターゲットにする例を示します。
apiVersion : autoscaling/v1
kind : HorizontalPodAutoscaler
metadata :
name : frontend-scaler
spec :
scaleTargetRef :
kind : ReplicaSet
name : frontend
minReplicas : 3
maxReplicas : 10
targetCPUUtilizationPercentage : 50
このマニフェストをhpa-rs.yamlに保存し、Kubernetesクラスターに適用すると、レプリケートされたPodのCPU使用量にもとづいてターゲットのReplicaSetをオートスケールするHPAを作成します。
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
同様のことを行うための代替案として、kubectl autoscaleコマンドも使用できます。(こちらの方がより簡単です。)
kubectl autoscale rs frontend --max= 10 --min= 3 --cpu= 50%
ReplicaSetの代替案
Deployment (推奨)
Deployment はReplicaSetを所有することのできるオブジェクトで、宣言的なサーバサイドのローリングアップデートを介してReplicaSetとPodをアップデートできます。ReplicaSetは単独で使用可能ですが、現在では、ReplicaSetは主にPodの作成、削除とアップデートを司るためのメカニズムとしてDeploymentによって使用されています。ユーザーがDeploymentを使用するとき、Deploymentによって作成されるReplicaSetの管理について心配する必要はありません。DeploymentはReplicaSetを所有し、管理します。このため、もしユーザーがReplicaSetを必要とするとき、Deploymentの使用を推奨します。
ベアPod(Bare Pods)
ユーザーがPodを直接作成するケースとは異なり、ReplicaSetはNodeの故障やカーネルのアップグレードといった破壊的なNodeのメンテナンスなど、どのような理由に限らず削除または停止されたPodを置き換えます。このため、我々はもしユーザーのアプリケーションが単一のPodのみ必要とする場合でもReplicaSetを使用することを推奨します。プロセスのスーパーバイザーについても同様に考えると、それは単一Node上での独立したプロセスの代わりに複数のNodeにまたがった複数のPodを監視します。ReplicaSetは、KubeletのようなNode上のいくつかのエージェントに対して、ローカルのコンテナ再起動を移譲します。
Job
PodをPodそれ自身で停止させたいような場合(例えば、バッチ用のジョブなど)は、ReplicaSetの代わりにJob を使用してください。
DaemonSet
マシンの監視やロギングなど、マシンレベルの機能を提供したい場合は、ReplicaSetの代わりにDaemonSet を使用してください。これらのPodはマシン自体のライフタイムに紐づいています: そのPodは他のPodが起動する前に、そのマシン上で稼働される必要があり、マシンが再起動またはシャットダウンされるときには、安全に停止されます。
ReplicationController
ReplicaSetはReplicationControllers の後継となるものです。この2つは、ReplicationControllerがラベルについてのユーザーガイド に書かれているように、集合ベース(set-based)のセレクター要求をサポートしていないことを除いては、同じ目的を果たし、同じようにふるまいます。
このように、ReplicaSetはReplicationControllerよりも好まれます。
次の項目
3.3 - StatefulSet
StatefulSetはステートフルなアプリケーションを管理するためのワークロードAPIです。
StatefulSetはPod のデプロイとスケーリングを管理し、それらのPodの順序と一意性を保証 します。
Deployment のように、StatefulSetは指定したコンテナのspecに基づいてPodを管理します。Deploymentとは異なり、StatefulSetは各Podにおいて管理が大変な同一性を維持します。これらのPodは同一のspecから作成されますが、それらは交換可能ではなく、リスケジュール処理をまたいで維持される永続的な識別子を持ちます。
ワークロードに永続性を持たせるためにストレージボリュームを使いたい場合は、解決策の1つとしてStatefulSetが利用できます。StatefulSet内の個々のPodは障害の影響を受けやすいですが、永続化したPodの識別子は既存のボリュームと障害によって置換された新しいPodの紐付けを簡単にします。
StatefulSetの使用
StatefulSetは下記の1つ以上の項目を要求するアプリケーションにおいて最適です。
安定した一意のネットワーク識別子
安定した永続ストレージ
規則的で安全なデプロイとスケーリング
規則的で自動化されたローリングアップデート
上記において安定とは、Podのスケジュール(または再スケジュール)をまたいでも永続的であることと同義です。もしアプリケーションが安定したネットワーク識別子と規則的なデプロイや削除、スケーリングを全く要求しない場合、ユーザーはステートレスなレプリカのセットを提供するワークロードを使ってアプリケーションをデプロイするべきです。Deployment やReplicaSet のようなコントローラーはこのようなステートレスな要求に対して最適です。
制限事項
提供されたPodのストレージは、要求されたstorage classにもとづいてPersistentVolume Provisioner によってプロビジョンされるか、管理者によって事前にプロビジョンされなくてはなりません。
StatefulSetの削除もしくはスケールダウンをすることにより、StatefulSetに関連したボリュームは削除されません 。 これはデータ安全性のためで、関連するStatefulSetのリソース全てを自動的に削除するよりもたいてい有効です。
StatefulSetは現在、Podのネットワークアイデンティティーに責務をもつためにHeadless Service を要求します。ユーザーはこのServiceを作成する責任があります。
StatefulSetは、StatefulSetが削除されたときにPodの停止を行うことを保証していません。StatefulSetにおいて、規則的で安全なPodの停止を行う場合、削除のために事前にそのStatefulSetの数を0にスケールダウンさせることが可能です。
デフォルト設定のPod管理ポリシー (OrderedReady)によってローリングアップデート を行う場合、修復のための手動介入 を要求するようなブロークンな状態に遷移させることが可能です。
コンポーネント
下記の例は、StatefulSetのコンポーネントのデモンストレーションとなります。
apiVersion : v1
kind : Service
metadata :
name : nginx
labels :
app : nginx
spec :
ports :
- port : 80
name : web
clusterIP : None
selector :
app : nginx
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : web
spec :
selector :
matchLabels :
app : nginx # .spec.template.metadata.labelsの値と一致する必要があります
serviceName : "nginx"
replicas : 3 # by default is 1
template :
metadata :
labels :
app : nginx # .spec.selector.matchLabelsの値と一致する必要があります
spec :
terminationGracePeriodSeconds : 10
containers :
- name : nginx
image : registry.k8s.io/nginx-slim:0.8
ports :
- containerPort : 80
name : web
volumeMounts :
- name : www
mountPath : /usr/share/nginx/html
volumeClaimTemplates :
- metadata :
name : www
spec :
accessModes : [ "ReadWriteOnce" ]
storageClassName : "my-storage-class"
resources :
requests :
storage : 1Gi
上記の例では、
nginxという名前のHeadlessServiceは、ネットワークドメインをコントロールするために使われます。
webという名前のStatefulSetは、specで3つのnginxコンテナのレプリカを持ち、そのコンテナはそれぞれ別のPodで稼働するように設定されています。
volumeClaimTemplatesは、PersistentVolumeプロビジョナーによってプロビジョンされたPersistentVolume を使って安定したストレージを提供します。
StatefulSetの名前は有効な名前 である必要があります。
Podセレクター
ユーザーは、StatefulSetの.spec.template.metadata.labelsのラベルと一致させるため、StatefulSetの.spec.selectorフィールドをセットしなくてはなりません。Kubernetes1.8以前では、.spec.selectorフィールドは省略された場合デフォルト値になります。Kubernetes1.8とそれ以降のバージョンでは、ラベルに一致するPodセレクターの指定がない場合はStatefulSetの作成時にバリデーションエラーになります。
Podアイデンティティー
StatefulSetのPodは、順番を示す番号、安定したネットワークアイデンティティー、安定したストレージからなる一意なアイデンティティーを持ちます。そのアイデンティティーはどのNode上にスケジュール(もしくは再スケジュール)されるかに関わらず、そのPodに紐付きます。
順序インデックス
N個のレプリカをもったStatefulSetにおいて、StatefulSet内の各Podは、0からはじまりN-1までの整数値を順番に割り当てられ、そのStatefulSetにおいては一意となります。
安定したネットワークID
StatefulSet内の各Podは、そのStatefulSet名とPodの順序番号から派生してホストネームが割り当てられます。作成されたホストネームの形式は$(StatefulSet名)-$(順序番号)となります。先ほどの上記の例では、web-0,web-1,web-2という3つのPodが作成されます。StatefulSetは、PodのドメインをコントロールするためにHeadless Service を使うことができます。このHeadless Serviceによって管理されたドメインは$(Service名).$(ネームスペース).svc.cluster.local形式となり、"cluster.local"というのはそのクラスターのドメインとなります。各Podが作成されると、Podは$(Pod名).$(管理するServiceドメイン名)に一致するDNSサブドメインを取得し、管理するServiceはStatefulSetのserviceNameで定義されます。
クラスターでのDNSの設定方法によっては、新たに起動されたPodのDNS名をすぐに検索できない場合があります。この動作は、クラスター内の他のクライアントが、Podが作成される前にそのPodのホスト名に対するクエリーをすでに送信していた場合に発生する可能性があります。(DNSでは通常)ネガティブキャッシュは、Podの起動後でも、少なくとも数秒間、以前に失敗したルックアップの結果が記憶され、再利用されることを意味します。
Podが作成された後、速やかにPodを検出する必要がある場合は、いくつかのオプションがあります。
DNSルックアップに依存するのではなく、Kubernetes APIに直接(例えばwatchを使って)問い合わせる。
Kubernetes DNS プロバイダーのキャッシュ時間を短縮する(これは現在30秒キャッシュされるようになっているCoreDNSのConfigMapを編集することを意味しています。)。
制限事項 セクションで言及したように、ユーザーはPodのネットワークアイデンティティーのためにHeadless Service を作成する責任があります。
ここで、クラスタードメイン、Service名、StatefulSet名の選択と、それらがStatefulSetのPodのDNS名にどう影響するかの例をあげます。
Cluster Domain
Service (ns/name)
StatefulSet (ns/name)
StatefulSet Domain
Pod DNS
Pod Hostname
cluster.local
default/nginx
default/web
nginx.default.svc.cluster.local
web-{0..N-1}.nginx.default.svc.cluster.local
web-{0..N-1}
cluster.local
foo/nginx
foo/web
nginx.foo.svc.cluster.local
web-{0..N-1}.nginx.foo.svc.cluster.local
web-{0..N-1}
kube.local
foo/nginx
foo/web
nginx.foo.svc.kube.local
web-{0..N-1}.nginx.foo.svc.kube.local
web-{0..N-1}
備考: クラスタードメインは
その他の設定 がされない限り、
cluster.localにセットされます。
安定したストレージ
StatefulSetで定義された各VolumeClaimTemplateに対して、各Podは1つのPersistentVolumeClaimを受け取ります。上記のnginxの例において、各Podはmy-storage-classというStorageClassをもち、1GiBのストレージ容量を持った単一のPersistentVolumeを受け取ります。もしStorageClassが指定されていない場合、デフォルトのStorageClassが使用されます。PodがNode上にスケジュール(もしくは再スケジュール)されたとき、そのvolumeMountsはPersistentVolume Claimに関連したPersistentVolumeをマウントします。注意点として、PodのPersistentVolume Claimと関連したPersistentVolumeは、PodやStatefulSetが削除されたときに削除されません。削除する場合は手動で行わなければなりません。
Podのネームラベル
StatefulSet コントローラー がPodを作成したとき、Podの名前として、statefulset.kubernetes.io/pod-nameにラベルを追加します。このラベルによってユーザーはServiceにStatefulSet内の指定したPodを割り当てることができます。
デプロイとスケーリングの保証
N個のレプリカをもつStatefulSetにおいて、Podがデプロイされるとき、それらのPodは{0..N-1}の番号で順番に作成されます。
Podが削除されるとき、それらのPodは{N-1..0}の番号で降順に削除されます。
Podに対してスケーリングオプションが適用される前に、そのPodの前の順番の全てのPodがRunningかつReady状態になっていなくてはなりません。
Podが停止される前に、そのPodの番号より大きい番号を持つの全てのPodは完全にシャットダウンされていなくてはなりません。
StatefulSetはpod.Spec.TerminationGracePeriodSecondsを0に指定すべきではありません。これは不安全で、やらないことを強く推奨します。さらなる説明としては、StatefulSetのPodの強制削除 を参照してください。
上記の例のnginxが作成されたとき、3つのPodはweb-0、web-1、web-2の順番でデプロイされます。web-1はweb-0がRunningかつReady状態 になるまでは決してデプロイされないのと、同様にweb-2はweb-1がRunningかつReady状態にならないとデプロイされません。もしweb-0がweb-1がRunningかつReady状態になった後だが、web-2が起動する前に失敗した場合、web-2はweb-0の再起動が成功し、RunningかつReady状態にならないと再起動されません。
もしユーザーがreplicas=1といったようにStatefulSetにパッチをあてることにより、デプロイされたものをスケールすることになった場合、web-2は最初に停止されます。web-1はweb-2が完全にシャットダウンされ削除されるまでは、停止されません。もしweb-0が、web-2が完全に停止され削除された後だが、web-1の停止の前に失敗した場合、web-1はweb-0がRunningかつReady状態になるまでは停止されません。
Podの管理ポリシー
Kubernetes1.7とそれ以降のバージョンでは、StatefulSetは.spec.podManagementPolicyフィールドを介して、Podの一意性とアイデンティティーを保証します。
OrderedReadyなPod管理
OrderedReadyなPod管理はStatefulSetにおいてデフォルトです。これはデプロイとスケーリングの保証 に記載されている項目の振る舞いを実装します。
並行なPod管理
ParallelなPod管理は、StatefulSetコントローラーに対して、他のPodが起動や停止される前にそのPodが完全に起動し準備完了になるか停止するのを待つことなく、Podが並行に起動もしくは停止するように指示します。
アップデートストラテジー
Kubernetes1.7とそれ以降のバージョンにおいて、StatefulSetの.spec.updateStrategyフィールドで、コンテナの自動のローリングアップデートの設定やラベル、リソースのリクエストとリミットや、StatefulSet内のPodのアノテーションを指定できます。
OnDelete
OnDeleteというアップデートストラテジーは、レガシーな(Kubernetes1.6以前)振る舞いとなります。StatefulSetの.spec.updateStrategy.typeがOnDeleteにセットされていたとき、そのStatefulSetコントローラーはStatefulSet内でPodを自動的に更新しません。StatefulSetの.spec.template項目の修正を反映した新しいPodの作成をコントローラーに支持するためには、ユーザーは手動でPodを削除しなければなりません。
RollingUpdate
RollingUpdateというアップデートストラテジーは、StatefulSet内のPodに対する自動化されたローリングアップデートの機能を実装します。これは.spec.updateStrategyフィールドが未指定の場合のデフォルトのストラテジーです。StatefulSetの.spec.updateStrategy.typeがRollingUpdateにセットされたとき、そのStatefulSetコントローラーは、StatefulSet内のPodを削除し、再作成します。これはPodの停止(Podの番号の降順)と同じ順番で、一度に1つのPodを更新します。コントローラーは、その前のPodの状態がRunningかつReady状態になるまで次のPodの更新を待ちます。
パーティション
RollingUpdateというアップデートストラテジーは、.spec.updateStrategy.rollingUpdate.partitionを指定することにより、パーティションに分けることができます。もしパーティションが指定されていたとき、そのパーティションの値と等しいか、大きい番号を持つPodが更新されます。パーティションの値より小さい番号を持つPodは更新されず、たとえそれらのPodが削除されたとしても、それらのPodは以前のバージョンで再作成されます。もしStatefulSetの.spec.updateStrategy.rollingUpdate.partitionが、.spec.replicasより大きい場合、.spec.templateへの更新はPodに反映されません。多くのケースの場合、ユーザーはパーティションを使う必要はありませんが、もし一部の更新を行う場合や、カナリー版のバージョンをロールアウトする場合や、段階的ロールアウトを行う場合に最適です。
強制ロールバック
デフォルトのPod管理ポリシー (OrderedReady)によるローリングアップデート を行う際、修復のために手作業が必要な状態にすることが可能です。
もしユーザーが、決してRunningかつReady状態にならないような設定になるようにPodテンプレートを更新した場合(例えば、不正なバイナリや、アプリケーションレベルの設定エラーなど)、StatefulSetはロールアウトを停止し、待機します。
この状態では、Podテンプレートを正常な状態に戻すだけでは不十分です。既知の問題 によって、StatefulSetは元の正常な状態へ戻す前に、壊れたPodがReady状態(決して起こりえない)に戻るのを待ち続けます。
そのテンプレートを戻したあと、ユーザーはまたStatefulSetが異常状態で稼働しようとしていたPodをすべて削除する必要があります。StatefulSetはその戻されたテンプレートを使ってPodの再作成を始めます。
次の項目
3.4 - DaemonSet
DaemonSet は全て(またはいくつか)のNodeが単一のPodのコピーを稼働させることを保証します。Nodeがクラスターに追加されるとき、PodがNode上に追加されます。Nodeがクラスターから削除されたとき、それらのPodはガーベージコレクターにより除去されます。DaemonSetの削除により、DaemonSetが作成したPodもクリーンアップします。
DaemonSetのいくつかの典型的な使用例は以下の通りです。
クラスターのストレージデーモンを全てのNode上で稼働させる。
ログ集計デーモンを全てのNode上で稼働させる。
Nodeのモニタリングデーモンを全てのNode上で稼働させる。
シンプルなケースとして、各タイプのデーモンにおいて、全てのNodeをカバーする1つのDaemonSetが使用されるケースがあります。さらに複雑な設定では、単一のタイプのデーモン用ですが、異なるフラグや、異なるハードウェアタイプに対するメモリー、CPUリクエストを要求する複数のDaemonSetを使用するケースもあります。
DaemonSet Specの記述
DaemonSetの作成
ユーザーはYAMLファイル内でDaemonSetの設定を記述することができます。例えば、下記のdaemonset.yamlファイルではfluentd-elasticsearchというDockerイメージを稼働させるDaemonSetの設定を記述します。
apiVersion : apps/v1
kind : DaemonSet
metadata :
name : fluentd-elasticsearch
namespace : kube-system
labels :
k8s-app : fluentd-logging
spec :
selector :
matchLabels :
name : fluentd-elasticsearch
template :
metadata :
labels :
name : fluentd-elasticsearch
spec :
tolerations :
- key : node-role.kubernetes.io/master
operator : Exists
effect : NoSchedule
containers :
- name : fluentd-elasticsearch
image : quay.io/fluentd_elasticsearch/fluentd:v5.0.1
resources :
limits :
memory : 200Mi
requests :
cpu : 100m
memory : 200Mi
volumeMounts :
- name : varlog
mountPath : /var/log
- name : varlibdockercontainers
mountPath : /var/lib/docker/containers
readOnly : true
terminationGracePeriodSeconds : 30
volumes :
- name : varlog
hostPath :
path : /var/log
- name : varlibdockercontainers
hostPath :
path : /var/lib/docker/containers
YAMLファイルに基づいてDaemonSetを作成します。
kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml
必須のフィールド
他の全てのKubernetesの設定と同様に、DaemonSetはapiVersion、kindとmetadataフィールドが必須となります。設定ファイルの活用法に関する一般的な情報は、ステートレスアプリケーションの稼働 、kubectlを用いたオブジェクトの管理 といったドキュメントを参照ください。
DaemonSetオブジェクトの名前は、有効なDNSサブドメイン名 である必要があります。
また、DaemonSetにおいて.spec セクションも必須となります。
Podテンプレート
.spec.templateは.spec内での必須のフィールドの1つです。
.spec.templateはPodテンプレート となります。これはフィールドがネストされていて、apiVersionやkindをもたないことを除いては、Pod のテンプレートと同じスキーマとなります。
Podに対する必須のフィールドに加えて、DaemonSet内のPodテンプレートは適切なラベルを指定しなくてはなりません(Podセレクター の項目を参照ください)。
DaemonSet内のPodテンプレートでは、RestartPolicy フィールドを指定せずにデフォルトのAlwaysを使用するか、明示的にAlwaysを設定するかのどちらかである必要があります。
Podセレクター
.spec.selectorフィールドはPodセレクターとなります。これはJob の.spec.selectorと同じものです。
ユーザーは.spec.templateのラベルにマッチするPodセレクターを指定しなくてはいけません。また、一度DaemonSetが作成されると、その.spec.selectorは変更不可能になります。Podセレクターの変更は、意図しないPodの孤立を引き起こし、ユーザーにとってやっかいなものとなります。
.spec.selectorは2つのフィールドからなるオブジェクトです。
matchLabels - ReplicationController の.spec.selectorと同じように機能します。
matchExpressions - キーと、値のリストとさらにはそれらのキーとバリューに関連したオペレーターを指定することにより、より洗練された形式のセレクターを構成できます。
上記の2つが指定された場合は、2つの条件をANDでどちらも満たすものを結果として返します。
spec.selectorは.spec.template.metadata.labelsとマッチしなければなりません。この2つの値がマッチしない設定をした場合、APIによってリジェクトされます。
選択したNode上でPodを稼働させる
もしユーザーが.spec.template.spec.nodeSelectorを指定したとき、DaemonSetコントローラーは、そのnode selector にマッチするNode上にPodを作成します。同様に、もし.spec.template.spec.affinityを指定したとき、DaemonSetコントローラーはnode affinity にマッチするNode上にPodを作成します。もしユーザーがどちらも指定しないとき、DaemonSetコントローラーは全てのNode上にPodを作成します。
Daemon Podがどのようにスケジューリングされるか
DaemonSetは、全ての利用可能なNodeがPodのコピーを稼働させることを保証します。DaemonSetコントローラーは対象となる各Nodeに対してPodを作成し、ターゲットホストに一致するようにPodのspec.affinity.nodeAffinityフィールドを追加します。Podが作成されると、通常はデフォルトのスケジューラーが引き継ぎ、.spec.nodeNameを設定することでPodをターゲットホストにバインドします。新しいNodeに適合できない場合、デフォルトスケジューラーは新しいPodの優先度 に基づいて、既存Podのいくつかを先取り(退避)させることがあります。
ユーザーは、DaemonSetの.spec.template.spec.schedulerNameフィールドを設定することにより、DaemonSetのPodに対して異なるスケジューラーを指定することができます。
.spec.template.spec.affinity.nodeAffinityフィールド(指定された場合)で指定された元のNodeアフィニティは、DaemonSetコントローラーが対象Nodeを評価する際に考慮されますが、作成されたPod上では対象Nodeの名前と一致するNodeアフィニティに置き換わります。
nodeAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
nodeSelectorTerms :
- matchFields :
- key : metadata.name
operator : In
values :
- target-host-name
TaintとToleration
DaemonSetコントローラーはDaemonSet Podに一連のToleration を自動的に追加します:
DaemonSetのPodテンプレートで定義すれば、DaemonSetのPodに独自のTolerationを追加することも可能です。
DaemonSetコントローラーはnode.kubernetes.io/unschedulable:NoScheduleのTolerationを自動的に設定するため、Kubernetesは スケジューリング不可能 としてマークされているNodeでDaemonSet Podを実行することが可能です。
クラスターのネットワーク のような重要なNodeレベルの機能をDaemonSetで提供する場合、KubernetesがDaemonSet PodをNodeが準備完了になる前に配置することは有用です。例えば、その特別なTolerationがなければ、ネットワークプラグインがそこで実行されていないためにNodeが準備完了としてマークされず、同時にNodeがまだ準備完了でないためにそのNode上でネットワークプラグインが実行されていないというデッドロック状態に陥ってしまう可能性があるのです。
Daemon Podとのコミュニケーション
DaemonSet内のPodとのコミュニケーションをする際に考えられるパターンは以下の通りです:
Push : DaemonSet内のPodは統計データベースなどの他のサービスに対して更新情報を送信するように設定されます。クライアントは持っていません。
NodeIPとKnown Port : PodがNodeIPを介して疎通できるようにするため、DaemonSet内のPodはhostPortを使用できます。慣例により、クライアントはNodeIPのリストとポートを知っています。
DNS : 同じPodセレクターを持つHeadlessService を作成し、endpointsリソースを使ってDaemonSetを探すか、DNSから複数のAレコードを取得します。
Service : 同じPodセレクターを持つServiceを作成し、複数のうちのいずれかのNode上のDaemonに疎通させるためにそのServiceを使います。(特定のNodeにアクセスする方法はありません。)
DaemonSetの更新
もしNodeラベルが変更されたとき、そのDaemonSetは直ちに新しくマッチしたNodeにPodを追加し、マッチしなくなったNodeからPodを削除します。
ユーザーはDaemonSetが作成したPodを修正可能です。しかし、Podは全てのフィールドの更新を許可していません。また、DaemonSetコントローラーは次のNode(同じ名前でも)が作成されたときにオリジナルのテンプレートを使ってPodを作成します。
ユーザーはDaemonSetを削除可能です。kubectlコマンドで--cascade=orphanを指定するとDaemonSetのPodはNode上に残り続けます。その後、同じセレクターで新しいDaemonSetを作成すると、新しいDaemonSetは既存のPodを再利用します。PodでDaemonSetを置き換える必要がある場合は、updateStrategyに従ってそれらを置き換えます。
ユーザーはDaemonSet上でローリングアップデートの実施 が可能です。
DaemonSetの代替案
Initスクリプト
Node上で直接起動することにより(例: init、upstartd、systemdを使用する)、デーモンプロセスを稼働することが可能です。この方法は非常に良いですが、このようなプロセスをDaemonSetを介して起動することはいくつかの利点があります。
アプリケーションと同じ方法でデーモンの監視とログの管理ができる。
デーモンとアプリケーションで同じ設定用の言語とツール(例: Podテンプレート、kubectl)を使える。
リソースリミットを使ったコンテナ内でデーモンを稼働させることにより、デーモンとアプリケーションコンテナの分離性が高まります。ただし、これはPod内ではなく、コンテナ内でデーモンを稼働させることでも可能です。
ベアPod
特定のNode上で稼働するように指定したPodを直接作成することは可能です。しかし、DaemonSetはNodeの故障やNodeの破壊的なメンテナンスやカーネルのアップグレードなど、どのような理由に限らず、削除されたもしくは停止されたPodを置き換えます。このような理由で、ユーザーはPod単体を作成するよりもむしろDaemonSetを使うべきです。
静的Pod
Kubeletによって監視されているディレクトリに対してファイルを書き込むことによって、Podを作成することが可能です。これは静的Pod と呼ばれます。DaemonSetと違い、静的Podはkubectlや他のKubernetes APIクライアントで管理できません。静的PodはApiServerに依存しておらず、クラスターの自立起動時に最適です。また、静的Podは将来的には廃止される予定です。
Deployment
DaemonSetは、Podの作成し、そのPodが停止されることのないプロセスを持つことにおいてDeployment と同様です(例: webサーバー、ストレージサーバー)。
フロントエンドのようなServiceのように、どのホスト上にPodが稼働するか制御するよりも、レプリカ数をスケールアップまたはスケールダウンしたりローリングアップデートする方が重要であるような、状態をもたないServiceに対してDeploymentを使ってください。DaemonSetがNodeレベルの機能を提供し、他のPodがその特定のNodeで正しく動作するようにする場合、Podのコピーが全てまたは特定のホスト上で常に稼働していることが重要な場合にDaemonSetを使ってください。
例えば、ネットワークプラグイン には、DaemonSetとして動作するコンポーネントが含まれていることがよくあります。DaemonSetコンポーネントは、それが動作しているNodeでクラスターネットワークが動作していることを確認します。
次の項目
3.5 - Job
Jobは一つ以上のPodを作成し、指定された数のPodが正常に終了するまで、Podの実行を再試行し続けます。Podが正常に終了すると、Jobは成功したPodの数を追跡します。指定された完了数に達すると、そのタスク(つまりJob)は完了したとみなされます。Jobを削除すると、作成されたPodも一緒に削除されます。Jobを一時停止すると、再開されるまで、稼働しているPodは全部削除されます。
単純なケースを言うと、確実に一つのPodが正常に完了するまで実行されるよう、一つのJobオブジェクトを作成します。一つ目のPodに障害が発生したり、(例えばノードのハードウェア障害またノードの再起動が原因で)削除されたりすると、Jobオブジェクトは新しいPodを作成します。
Jobで複数のPodを並列で実行することもできます。
スケジュールに沿ってJob(単一のタスクか複数タスク並列のいずれか)を実行したい場合は CronJob を参照してください。
実行例
下記にJobの定義例を記載しています。πを2000桁まで計算して出力するJobで、完了するまで約10秒かかります。
apiVersion : batch/v1
kind : Job
metadata :
name : pi
spec :
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
backoffLimit : 4
このコマンドで実行できます:
kubectl apply -f https://kubernetes.io/examples/controllers/job.yaml
実行結果はこのようになります:
job.batch/pi created
kubectlでJobの状態を確認できます:
Name: pi
Namespace: default
Selector: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
Labels: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name= pi
...
Annotations: batch.kubernetes.io/job-tracking: ""
Parallelism: 1
Completions: 1
Start Time: Mon, 02 Dec 2019 15:20:11 +0200
Completed At: Mon, 02 Dec 2019 15:21:16 +0200
Duration: 65s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: batch.kubernetes.io/controller-uid= c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name= pi
Containers:
pi:
Image: perl:5.34.0
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum= bpi
-wle
print bpi( 2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 21s job-controller Created pod: pi-xf9p4
Normal Completed 18s job-controller Job completed
apiVersion: batch/v1
kind: Job
metadata:
annotations: batch.kubernetes.io/job-tracking: ""
...
creationTimestamp: "2022-11-10T17:53:53Z"
generation: 1
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
name: pi
namespace: default
resourceVersion: "4751"
uid: 204fb678-040b-497f-9266-35ffa8716d14
spec:
backoffLimit: 4
completionMode: NonIndexed
completions: 1
parallelism: 1
selector:
matchLabels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
suspend: false
template:
metadata:
creationTimestamp: null
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
spec:
containers:
- command:
- perl
- -Mbignum= bpi
- -wle
- print bpi( 2000)
image: perl:5.34.0
imagePullPolicy: IfNotPresent
name: pi
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Never
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
active: 1
ready: 0
startTime: "2022-11-10T17:53:57Z"
uncountedTerminatedPods: {}
Jobの完了したPodを確認するには、kubectl get podsを使います。
Jobに属するPodの一覧を機械可読形式で出力するには、下記のコマンドを使います:
pods = $( kubectl get pods --selector= batch.kubernetes.io/job-name= pi --output= jsonpath = '{.items[*].metadata.name}' )
echo $pods
出力結果はこのようになります:
pi-5rwd7
ここのセレクターはJobのセレクターと同じです。--output=jsonpathオプションは、返されたリストからPodのnameフィールドを指定するための表現です。
その中の一つのPodの標準出力を確認するには:
Jobの標準出力を確認するもう一つの方法は:
出力結果はこのようになります:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Job spec(仕様)の書き方
他のKubernetesオブジェクト設定ファイルと同様に、JobにもapiVersion、kindまたはmetadataフィールドが必要です。
コントロールプレーンがJobのために新しいPodを作成するとき、Jobの.metadata.nameはそれらのPodに名前をつけるための基礎の一部になります。Jobの名前は有効なDNSサブドメイン名 である必要がありますが、これはPodのホスト名に予期しない結果をもたらす可能性があります。最高の互換性を得るためには、名前はDNSラベル のより限定的な規則に従うべきです。名前がDNSサブドメインの場合でも、名前は63文字以下でなければなりません。
Jobには.specセクション も必要です。
Jobラベル
Jobラベルのjob-nameとcontroller-uidの接頭辞はbatch.kubernetes.io/となります。
Podテンプレート
.spec.templateは.specの唯一の必須フィールドです。
.spec.templateはpodテンプレート です。ネストされていることとapiVersionやkindフィールドが不要になったことを除いて、仕様の定義がPod と全く同じです。
Podの必須フィールドに加えて、Job定義ファイルにあるPodテンプレートでは、適切なラベル(podセレクター を参照)と適切な再起動ポリシーを指定する必要があります。
RestartPolicy はNeverかOnFailureのみ設定可能です。
Podセレクター
.spec.selectorフィールドはオプションです。ほとんどの場合はむしろ指定しないほうがよいです。独自のPodセレクターを指定 セクションを参照してください。
Jobの並列実行
Jobで実行するのに適したタスクは主に3種類あります:
非並列Job
通常、Podに障害が発生しない限り、一つのPodのみが起動されます。
Podが正常に終了すると、Jobはすぐに完了します。
固定の完了数 を持つ並列Job:
.spec.completionsに0以外の正の値を指定します。
Jobは全体的なタスクを表し、.spec.completions個のPodが成功すると、Jobの完了となります。
.spec.completionMode="Indexed"を利用する場合、各Podは0から.spec.completions-1までの範囲内のインデックスがアサインされます。
ワークキュー を利用した並列Job:
.spec.completionsの指定をしない場合、デフォルトは.spec.parallelismとなります。
Pod間で調整する、または外部サービスを使う方法で、それぞれ何のタスクに着手するかを決めます。例えば、一つのPodはワークキューから最大N個のタスクを一括で取得できます。
各Podは他のPodがすべて終了したかどうか、つまりJobが完了したかどうかを単独で判断できます。
Jobに属する 任意 のPodが正常に終了すると、新しいPodは作成されません。
一つ以上のPodが正常に終了し、すべてのPodが終了すると、Jobは正常に完了します。
一つのPodが正常に終了すると、他のPodは同じタスクの作業を行ったり、出力を書き込んだりすることはできません。すべてのPodが終了プロセスに進む必要があります。
非並列 Jobの場合、.spec.completionsと.spec.parallelismの両方を未設定のままにしておくことも可能です。未設定の場合、両方がデフォルトで1になります。
完了数固定 Jobの場合、.spec.completionsを必要完了数に設定する必要があります。.spec.parallelismを設定してもいいですし、未設定の場合、デフォルトで1になります。
ワークキュー 並列Jobの場合、.spec.completionsを未設定のままにし、.spec.parallelismを非負の整数に設定する必要があります。
各種類のJobの使用方法の詳細については、Jobパターン セクションを参照してください。
並列処理の制御
必要並列数(.spec.parallelism)は任意の非負の値に設定できます。未設定の場合は、デフォルトで1になります。0に設定した際には、増加するまでJobは一時停止されます。
実際の並列数(任意の瞬間に実行されているPod数)は、さまざまな理由により、必要並列数と異なる可能性があります:
完了数固定 Jobの場合、実際に並列して実行されるPodの数は、残りの完了数を超えることはありません。 .spec.parallelismの値が高い場合は無視されます。
ワークキュー Jobの場合、任意のPodが成功すると、新しいPodは作成されません。ただし、残りのPodは終了まで実行し続けられます。
Jobコントローラー の応答する時間がなかった場合。
Jobコントローラーが何らかの理由で(ResourceQuotaの不足、権限の不足など)、Podを作成できない場合、実際の並列数は必要並列数より少なくなる可能性があります。
同じJobで過去に発生した過度のPod障害が原因で、Jobコントローラーは新しいPodの作成を抑制することがあります。
Podがグレースフルシャットダウンされた場合、停止するのに時間がかかります。
完了モード
FEATURE STATE:
Kubernetes v1.24 [stable]
完了数固定 Job、つまり.spec.completionsの値がnullではないJobは.spec.completionModeで完了モードを指定できます:
NonIndexed(デフォルト): .spec.completions個のPodが成功した場合、Jobの完了となります。言い換えれば、各Podの完了状態は同質です。ここで要注意なのは、.spec.completionsの値がnullの場合、暗黙的にNonIndexedとして指定されることです。
Indexed: Jobに属するPodはそれぞれ、0から.spec.completions-1の範囲内の完了インデックスを取得できます。インデックスは下記の三つの方法で取得できます。
Podアノテーションbatch.kubernetes.io/job-completion-index。
Podホスト名の一部として、$(job-name)-$(index)の形式になっています。インデックス付きJob(Indexed Job)とService を一緒に使用すると、Jobに属するPodはお互いにDNSを介して確定的ホスト名で通信できます。この設定方法の詳細はPod間通信を使用したJob を参照してください。
コンテナ化されたタスクの環境変数JOB_COMPLETION_INDEX。
各インデックスに1つずつ正常に完了したPodがあると、Jobは完了したとみなされます。このモードの使い方については、静的な処理の割り当てを使用した並列処理のためのインデックス付きJob を参照してください。
備考: めったに発生しませんが、同じインデックスに対して複数のPodが起動することがあります。(Nodeの障害、kubeletの再起動、Podの立ち退きなど)。この場合、正常に完了した最初のPodだけ完了数にカウントされ、Jobのステータスが更新されます。同じインデックスに対して実行中または完了した他のPodは、検出されるとJobコントローラーによって削除されます。
Podとコンテナの障害対策
Pod内のコンテナは、その中のプロセスが0以外の終了コードで終了した、またはメモリ制限を超えたためにコンテナが強制終了されたなど、様々な理由で失敗することがあります。この場合、もし.spec.template.spec.restartPolicy = "OnFailure"と設定すると、Podはノード上に残りますが、コンテナは再実行されます。そのため、プログラムがローカルで再起動した場合の処理を行うか、.spec.template.spec.restartPolicy = "Never"と指定する必要があります。restartPolicyの詳細についてはPodのライフサイクル を参照してください。
Podがノードからキックされた(ノードがアップグレード、再起動、削除されたなど)、または.spec.template.spec.restartPolicy = "Never"と設定されたときにPodに属するコンテナが失敗したなど、様々な理由でPod全体が故障することもあります。Podに障害が発生すると、Jobコントローラーは新しいPodを起動します。つまりアプリケーションは新しいPodで再起動された場合の処理を行う必要があります。特に、過去に実行した際に生じた一時ファイル、ロック、不完全な出力などを処理する必要があります。
デフォルトでは、それぞれのPodの失敗は.spec.backoffLimitにカウントされます。詳しくはPod失敗のバックオフポリシー をご覧ください。しかし、JobのPod失敗ポリシー を設定することで、Pod失敗の処理をカスタマイズすることができます。
.spec.parallelism = 1、.spec.completions = 1と.spec.template.spec.restartPolicy = "Never"を指定しても、同じプログラムが2回起動されることもありますので注意してください。
.spec.parallelismと.spec.completionsを両方とも2以上指定した場合、複数のPodが同時に実行される可能性があります。そのため、Podは並行処理を行えるようにする必要があります。
フィーチャーゲート のPodDisruptionConditionsとJobPodFailurePolicyの両方が有効で、.spec.podFailurePolicyフィールドが設定されている場合、Jobコントローラーは終了するPod(.metadata.deletionTimestampフィールドが設定されているPod)を、そのPodが終了する(.status.phaseがFailedまたはSucceededになる)までは失敗とはみなしません。ただし、Jobコントローラーは、終了が明らかになるとすみやかに代わりのPodを作成します。Podが終了すると、Jobコントローラーはこの終了したPodを考慮に入れて、該当のJobの.backoffLimitと.podFailurePolicyを評価します。
これらの要件のいずれかが満たされていない場合、Jobコントローラーは、そのPodが後にphase: "Succeeded"で終了する場合でも、終了するPodを即時に失敗として数えます。
Pod失敗のバックオフポリシー
設定の論理エラーなどにより、Jobが数回再試行した後に失敗状態にしたい場合があります。.spec.backoffLimitを設定すると、失敗したと判断するまでの再試行回数を指定できます。バックオフ制限はデフォルトで6に設定されています。Jobに属していて失敗したPodはJobコントローラーにより再作成され、バックオフ遅延は指数関数的に増加し(10秒、20秒、40秒…)、最大6分まで増加します。
再実行回数の算出方法は以下の2通りです:
.status.phase = "Failed"で設定されたPod数を計算します。
restartPolicy = "OnFailure"と設定された場合、.status.phaseがPendingまたはRunningであるPodに属するすべてのコンテナで再試行する回数を計算します。
どちらかの計算が.spec.backoffLimitに達した場合、Jobは失敗とみなされます。
JobTrackingWithFinalizers 機能が無効な場合、失敗したPodの数は、API内にまだ存在するPodのみに基づいています。
備考: restartPolicy = "OnFailure"が設定されたJobはバックオフ制限に達すると、属するPodは全部終了されるので注意してください。これにより、Jobの実行ファイルのデバッグ作業が難しくなる可能性があります。失敗したJobからの出力が不用意に失われないように、Jobのデバッグ作業をする際はrestartPolicy = "Never"を設定するか、ロギングシステムを使用することをお勧めします。
Pod失敗ポリシー
FEATURE STATE:
Kubernetes v1.26 [beta]
備考: クラスターで
JobPodFailurePolicyフィーチャーゲート が有効になっている場合のみ、Jobに対してPod失敗ポリシーを設定することができます。さらにPod失敗ポリシーでPodの中断条件を検知して処理できるように、
PodDisruptionConditionsフィーチャーゲートを有効にすることが推奨されます。(
Podの中断条件 を参照してください)。どちらのフィーチャーゲートもKubernetes 1.27で利用可能です。
.spec.podFailurePolicyフィールドで定義されるPod失敗ポリシーを使用すると、コンテナの終了コードとPodの条件に基づいてクラスターがPodの失敗を処理できるようになります。
状況によっては、Podの失敗を処理するときに、Jobの.spec.backoffLimitに基づいたPod失敗のバックオフポリシー が提供する制御よりも、Podの失敗処理に対してより良い制御を求めるかもしれません。これらはいくつかの使用例です:
不要なPodの再起動を回避してワークロードの実行コストを最適化するために、Podの1つがソフトウェアバグを示す終了コードで失敗するとすぐにJobを終了させることができます。
中断が発生してもJobが完了するように、中断によって発生したPodの失敗(preemption 、APIを起点とした退避 、taint を起点とした立ち退き)を無視し、.spec.backoffLimitのリトライ回数にカウントしないようにすることができます。
上記のユースケースを満たすために、.spec.podFailurePolicyフィールドでPod失敗ポリシーを設定できます。このポリシーは、コンテナの終了コードとPodの条件に基づいてPodの失敗を処理できます。
以下は、podFailurePolicyを定義するJobのマニフェストです:
apiVersion : batch/v1
kind : Job
metadata :
name : job-pod-failure-policy-example
spec :
completions : 12
parallelism : 3
template :
spec :
restartPolicy : Never
containers :
- name : main
image : docker.io/library/bash:5
command : ["bash" ] # example command simulating a bug which triggers the FailJob action
args :
- -c
- echo "Hello world!" && sleep 5 && exit 42
backoffLimit : 6
podFailurePolicy :
rules :
- action : FailJob
onExitCodes :
containerName : main # optional
operator: In # one of : In, NotIn
values : [42 ]
- action: Ignore # one of : Ignore, FailJob, Count
onPodConditions :
- type : DisruptionTarget # indicates Pod disruption
上記の例では、Pod失敗ポリシーの最初のルールは、mainコンテナが42の終了コードで失敗した場合、そのJobを失敗とマークすることを指定しています。以下は特に mainコンテナに関するルールです:
終了コード0はコンテナが成功したことを意味します。
終了コード42はJob全体 が失敗したことを意味します。
それ以外の終了コードは、コンテナが失敗したこと、つまりPod全体が失敗したことを示します。再起動の合計回数がbackoffLimit未満であれば、Podは再作成されます。backoffLimitに達した場合、Job全体 が失敗したことになります。
備考: PodテンプレートはrestartPolicy.Neverを指定しているため、kubeletはその特定のPodのmainコンテナを再起動しません。
Pod失敗ポリシーの2つ目のルールでは、DisruptionTargetという条件で失敗したPodに対してIgnoreアクションを指定することで、Podの中断が.spec.backoffLimitによるリトライの制限にカウントされないようにします。
備考: Pod失敗ポリシーまたはPod失敗のバックオフポリシーのいずれかによってJobが失敗し、そのJobが複数のPodを実行している場合、KubernetesはそのJob内の保留中または実行中のすべてのPodを終了します。
これらはAPIの要件と機能です:
.spec.podFailurePolicyフィールドをJobに使いたい場合は、.spec.restartPolicyをNeverに設定してそのJobのPodテンプレートも定義する必要があります。
spec.podFailurePolicy.rulesで指定したPod失敗ポリシーのルールが順番に評価されます。あるPodの失敗がルールに一致すると、残りのルールは無視されます。Pod失敗に一致するルールがない場合は、デフォルトの処理が適用されます。
spec.podFailurePolicy.rules[*].onExitCodes.containerNameを指定することで、ルールを特定のコンテナに制限することができます。指定しない場合、ルールはすべてのコンテナに適用されます。指定する場合は、Pod テンプレート内のコンテナ名またはinitContainer名のいずれかに一致する必要があります。
Pod失敗ポリシーがspec.podFailurePolicy.rules[*].actionにマッチしたときに実行されるアクションを指定できます。指定可能な値は以下のとおりです。
FailJob: PodのJobをFailedとしてマークし、実行中の Pod をすべて終了させる必要があることを示します。
Ignore: .spec.backoffLimitのカウンターは加算されず、代替のPodが作成すべきであることを示します。
Count: Podがデフォルトの方法で処理されるべきであることを示します。.spec.backoffLimitのカウンターが加算されます。
備考: PodFailurePolicyを使用すると、Jobコントローラーは
FailedフェーズのPodのみにマッチします。削除タイムスタンプを持つPodで、終了フェーズ(
Failedまたは
Succeeded)にないものは、まだ終了中と見なされます。これは、終了中Podは終了フェーズに達するまで
追跡ファイナライザー を保持することを意味します。Kubernetes 1.27以降、Kubeletは削除されたPodを終了フェーズに遷移させます(参照:
Podのフェーズ )。これにより、削除されたPodはJobコントローラーによってファイナライザーが削除されます。
Jobの終了とクリーンアップ
Jobが完了すると、それ以上Podは作成されませんが、通常 Podが削除されることもありません。これらを残しておくと、完了したPodのログを確認でき、エラーや警告などの診断出力を確認できます。またJobオブジェクトはJob完了後も残っているため、状態を確認することができます。古いJobの状態を把握した上で、削除するかどうかはユーザー次第です。Jobを削除するにはkubectl (例:kubectl delete jobs/piまたはkubectl delete -f ./job.yaml)を使います。kubectlでJobを削除する場合、Jobが作成したPodも全部削除されます。
デフォルトでは、Podが失敗しない(restartPolicy=Never)またはコンテナがエラーで終了しない(restartPolicy=OnFailure)限り、Jobは中断されることなく実行されます。.spec.backoffLimitに達するとそのJobは失敗と見なされ、実行中のPodはすべて終了します。
Jobを終了させるもう一つの方法は、活動期間を設定することです。Jobの.spec.activeDeadlineSecondsフィールドに秒数を設定することで、活動期間を設定できます。Podがいくつ作成されても、activeDeadlineSecondsはJobの存続する時間に適用されます。JobがactiveDeadlineSecondsに達すると、実行中のすべてのPodは終了され、Jobの状態はtype: Failedになり、理由はreason: DeadlineExceededになります。
ここで要注意なのは、Jobの.spec.activeDeadlineSecondsは.spec.backoffLimitよりも優先されます。したがって、失敗して再試行しているPodが一つ以上持っているJobは、backoffLimitに達していなくても、activeDeadlineSecondsで指定された設定時間に達すると、追加のPodをデプロイしなくなります。
例えば:
apiVersion : batch/v1
kind : Job
metadata :
name : pi-with-timeout
spec :
backoffLimit : 5
activeDeadlineSeconds : 100
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
Job仕様と、Jobに属するPodテンプレートの仕様 は両方ともactiveDeadlineSecondsフィールドを持っているので注意してください。適切なレベルで設定していることを確認してください。
またrestartPolicyはJob自体ではなく、Podに適用されることも注意してください: Jobの状態はtype: Failedになると、自動的に再起動されることはありません。つまり、.spec.activeDeadlineSecondsと.spec.backoffLimitによって引き起こされるJob終了メカニズムは、永久的なJob失敗につながり、手動で介入して解決する必要があります。
終了したJobの自動クリーンアップ
終了したJobは通常システムに残す必要はありません。残ったままにしておくとAPIサーバーに負担をかけることになります。Jobが上位コントローラーにより直接管理されている場合、例えばCronJobs の場合、Jobは指定された容量ベースのクリーンアップポリシーに基づき、CronJobによりクリーンアップされます。
終了したJobのTTLメカニズム
FEATURE STATE:
Kubernetes v1.23 [stable]
終了したJob(状態がCompleteかFailedになったJob)を自動的にクリーンアップするもう一つの方法はTTLコントローラー より提供されたTTLメカニズムです。.spec.ttlSecondsAfterFinishedフィールドを指定することで、終了したリソースをクリーンアップすることができます。
TTLコントローラーでJobをクリーンアップする場合、Jobはカスケード的に削除されます。つまりJobを削除する際に、Jobに属しているオブジェクト、例えばPodなども一緒に削除されます。Jobが削除される場合、Finalizerなどの、Jobのライフサイクル保証は守られることに注意してください。
例えば:
apiVersion : batch/v1
kind : Job
metadata :
name : pi-with-ttl
spec :
ttlSecondsAfterFinished : 100
template :
spec :
containers :
- name : pi
image : perl:5.34.0
command : ["perl" , "-Mbignum=bpi" , "-wle" , "print bpi(2000)" ]
restartPolicy : Never
Job pi-with-ttlは終了してからの100秒後に自動的に削除されるようになっています。
このフィールドに0を設定すると、Jobは終了後すぐに自動削除の対象になります。このフィールドに何も設定しないと、Jobが終了してもTTLコントローラーによるクリーンアップはされません。
備考: ttlSecondsAfterFinishedフィールドを設定することが推奨されます。管理されていないJob(CronJobなどの、他のワークロードAPIを経由せずに、直接作成したJob)はorphanDependentsというデフォルトの削除ポリシーがあるため、Jobが完全に削除されても、属しているPodが残ってしまうからです。コントロールプレーン は最終的に、失敗または完了して削除されたJobに属するPodをガベージコレクション しますが、Podが残っていると、クラスターのパフォーマンスが低下することがあり、最悪の場合、この低下によりクラスターがオフラインになることがあります。
LimitRanges とリソースクォータ で、指定する名前空間が消費できるリソースの量に上限を設定することができます。
Jobパターン
Jobオブジェクトは、Podの確実な並列実行をサポートするために使用されます。科学技術計算でよく見られるような、密接に通信を行う並列処理をサポートするようには設計されていません。独立だが関連性のある一連の作業項目 の並列処理をサポートします。例えば送信すべき電子メール、レンダリングすべきフレーム、トランスコードすべきファイル、スキャンすべきNoSQLデータベースのキーの範囲、などです。
複雑なシステムでは、異なる作業項目のセットが複数存在する場合があります。ここでは、ユーザーが一斉に管理したい作業項目のセットが一つだけの場合 — つまりバッチJob だけを考えます。
並列計算にはいくつかのパターンがあり、それぞれに長所と短所があります。トレードオフの関係にあるのは:
各作業項目に1つのJobオブジェクト vs. すべての作業項目に1つのJobオブジェクト。後者は大量の作業項目を処理する場合に適しています。前者は大量のJobオブジェクトを管理するため、ユーザーとシステムにオーバーヘッドをかけることになります。
作成されるPod数が作業項目数と等しい、 vs. 各Podが複数の作業項目を処理する。前者は通常、既存のコードやコンテナへの変更が少なくて済みます。後者は上記と同じ理由で、大量の作業項目を処理する場合に適しています。
ワークキューを利用するアプローチもいくつかあります。それを使うためには、キューサービスを実行し、既存のプログラムやコンテナにワークキューを利用させるための改造を行う必要があります。他のアプローチは既存のコンテナ型アプリケーションに適用しやすいです。
ここでは、上記のトレードオフをまとめてあり、それぞれ2~4列目に対応しています。またパターン名のところは、例やより詳しい説明が書いてあるページへのリンクになっています。
.spec.completionsで完了数を指定する場合、Jobコントローラーより作成された各Podは同一のspec を持ちます。これは、このタスクのすべてのPodが同じコマンドライン、同じイメージ、同じボリューム、そして(ほぼ)同じ環境変数を持つことを意味します。これらのパターンは、Podが異なる作業をするためのさまざまな配置方法になります。
この表は、各パターンで必要な.spec.parallelismと.spec.completionsの設定を示しています。ここで、Wは作業項目の数を表しています。
高度な使い方
Jobの一時停止
FEATURE STATE:
Kubernetes v1.24 [stable]
Jobが作成されると、JobコントローラーはJobの要件を満たすために直ちにPodの作成を開始し、Jobが完了するまで作成し続けます。しかし、Jobの実行を一時的に中断して後で再開したい場合、または一時停止状態のJobを再開し、再開時間は後でカスタムコントローラーに判断させたい場合はあると思います。
Jobを一時停止するには、Jobの.spec.suspendフィールドをtrueに修正し、後でまた再開したい場合にはfalseに修正すればよいです。.spec.suspendをtrueに設定してJobを作成すると、一時停止状態のままで作成されます。
一時停止状態のJobを再開すると、.status.startTimeフィールドの値は現在時刻にリセットされます。これはつまり、Jobが一時停止して再開すると、.spec.activeDeadlineSecondsタイマーは停止してリセットされることになります。
Jobを中断すると、状態がCompletedではない実行中のPodはすべてSIGTERMシグナルを受信して終了されます 。Podのグレースフル終了の猶予期間がカウントダウンされ、この期間内に、Podはこのシグナルを処理しなければなりません。場合により、その後のために処理状況を保存したり、変更を元に戻したりする処理が含まれます。この方法で終了したPodはcompletions数にカウントされません。
下記は一時停止状態のままで作成されたJobの定義例になります:
kubectl get job myjob -o yaml
apiVersion : batch/v1
kind : Job
metadata :
name : myjob
spec :
suspend : true
parallelism : 1
completions : 5
template :
spec :
...
コマンドラインを使ってJobにパッチを当てることで、Jobの一時停止状態を切り替えることもできます。
活動中のJobを一時停止する:
kubectl patch job/myjob --type= strategic --patch '{"spec":{"suspend":true}}'
一時停止中のJobを再開する:
kubectl patch job/myjob --type= strategic --patch '{"spec":{"suspend":false}}'
Jobのstatusセクションで、Jobが停止中なのか、過去に停止したことがあるかを判断できます:
kubectl get jobs/myjob -o yaml
apiVersion : batch/v1
kind : Job
# .metadata and .spec omitted
status :
conditions :
- lastProbeTime : "2021-02-05T13:14:33Z"
lastTransitionTime : "2021-02-05T13:14:33Z"
status : "True"
type : Suspended
startTime : "2021-02-05T13:13:48Z"
Jobのcondition.typeが"Suspended"で、statusが"True"になった場合、Jobは一時停止中になります。lastTransitionTimeフィールドで、どのぐらい中断されたかを判断できます。statusが"False"になった場合、Jobは一時停止状態でしたが、今は実行されていることになります。conditionが書いていない場合、Jobは一度も停止していないことになります。
Jobが一時停止して再開した場合、Eventsも作成されます:
kubectl describe jobs/myjob
Name: myjob
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 12m job-controller Created pod: myjob-hlrpl
Normal SuccessfulDelete 11m job-controller Deleted pod: myjob-hlrpl
Normal Suspended 11m job-controller Job suspended
Normal SuccessfulCreate 3s job-controller Created pod: myjob-jvb44
Normal Resumed 3s job-controller Job resumed
最後の4つのイベント、特に"Suspended"と"Resumed"のイベントは、.spec.suspendフィールドの値を切り替えた直接の結果です。この2つのイベントの間に、Podは作成されていないことがわかりますが、Jobが再開されるとすぐにPodの作成も再開されました。
可変スケジューリング命令
FEATURE STATE:
Kubernetes v1.27 [stable]
ほとんどの場合、並列Jobは、すべてのPodが同じゾーン、またはすべてのGPUモデルxかyのいずれかであるが、両方の混在ではない、などの制約付きで実行することが望ましいです。
suspend フィールドは、これらの機能を実現するための第一歩です。Suspendは、カスタムキューコントローラーがJobをいつ開始すべきかを決定することができます。しかし、Jobの一時停止が解除されると、カスタムキューコントローラーは、Job内のPodの実際の配置場所には影響を与えません。
この機能により、Jobが開始する前にスケジューリング命令を更新でき、カスタムキューコントローラーがPodの配置に影響を与えることができるようになります。同時に実際のPodからNodeへの割り当てをkube-schedulerにオフロードする能力を提供します。これは一時停止されたJobの中で、一度も一時停止解除されたことのないJobに対してのみ許可されます。
JobのPodテンプレートで更新可能なフィールドはnodeAffinity、nodeSelector、tolerations、labelsとannotations、スケジューリングゲート です。
独自のPodセレクターを指定
Jobオブジェクトを作成する際には通常、.spec.selectorを指定しません。Jobが作成された際に、システムのデフォルトロジックは、他のJobと重ならないようなセレクターの値を選択し、このフィールドに追加します。
しかし、場合によっては、この自動設定されたセレクターをオーバーライドする必要があります。そのためには、Jobの.spec.selectorを指定します。
その際には十分な注意が必要です。そのJobの他のPodと重なったラベルセレクターを指定し、無関係のPodにマッチした場合、無関係のJobのPodが削除されたり、無関係のPodが完了されてもこのJobの完了数とカウントしたり、片方または両方のJobがPodの作成または完了までの実行を拒否する可能性があります。一意でないセレクターを選択した場合、他のコントローラー(例えばReplicationController)や属しているPodが予測できない挙動をする可能性があります。Kubernetesは.spec.selectorを間違って設定しても止めることはしません。
下記はこの機能の使用例を紹介しています。
oldと名付けたJobがすでに実行されていると仮定します。既存のPodをそのまま実行し続けてほしい一方で、作成する残りのPodには別のテンプレートを使用し、そのJobには新しい名前を付けたいとしましょう。これらのフィールドは更新できないため、Jobを直接更新できません。そのため、kubectl delete jobs/old --cascade=orphanで、属しているPodが実行されたまま 、oldJobを削除します。削除する前に、どのセレクターを使用しているかをメモしておきます:
kubectl get job old -o yaml
出力結果はこのようになります:
kind : Job
metadata :
name : old
...
spec :
selector :
matchLabels :
batch.kubernetes.io/controller-uid : a8f3d00d-c6d2-11e5-9f87-42010af00002
...
次に、newという名前で新しくJobを作成し、同じセレクターを明示的に指定します。既存のPodもbatch.kubernetes.io/controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002ラベルが付いているので、同じくnewJobによってコントロールされます。
通常システムが自動的に生成するセレクターを使用しないため、新しいJobで manualSelector: trueを指定する必要があります。
kind : Job
metadata :
name : new
...
spec :
manualSelector : true
selector :
matchLabels :
batch.kubernetes.io/controller-uid : a8f3d00d-c6d2-11e5-9f87-42010af00002
...
新しいJobはa8f3d00d-c6d2-11e5-9f87-42010af00002ではなく、別のuidを持つことになります。manualSelector: trueを設定することで、自分は何をしているかを知っていて、またこのミスマッチを許容することをシステムに伝えます。
FinalizerによるJob追跡
FEATURE STATE:
Kubernetes v1.26 [stable]
備考: JobTrackingWithFinalizers機能が無効になっている時に作成されたJobについては、コントロールプレーンを1.26にアップグレードしても、ファイナライザーを使用してJobを追跡しません。
コントロールプレーンは任意のJobに属するPodを追跡し、そのPodがAPIサーバーから削除されたかどうか認識します。そのためJobコントローラーはファイナライザーbatch.kubernetes.io/job-trackingを持つPodを作成します。コントローラーがファイナライザーを削除するのは、PodがJobステータスに反映された後なので、他のコントローラーやユーザがPodを削除することができます。
Kubernetes 1.26にアップグレードする前、またはフィーチャーゲートJobTrackingWithFinalizersが有効になる前に作成されたJobは、Podファイナライザーを使用せずに追跡されます。Jobコントローラー は、クラスターに存在するPodのみに基づいて、succeededPodとfailedPodのステータスカウンタを更新します。クラスターからPodが削除されると、コントロールプレーンはJobの進捗を見失う可能性があります。
Jobがbatch.kubernetes.io/job-trackingというアノテーションを持っているかどうかをチェックすることで、コントロールプレーンがPodファイナライザーを使ってJobを追跡しているかどうかを判断できます。Jobからこのアノテーションを手動で追加したり削除したりしてはいけません 。代わりに、JobがPodファイナライザーを使用して追跡されていることを確認するために、Jobを再作成することができます。
静的なインデックス付きJob
FEATURE STATE:
Kubernetes v1.27 [beta]
.spec.parallelismと.spec.compleitionsの両方を、.spec.parallelism == .spec.compleitionsとなるように変更することで、インデックス付きJobを増減させることができます。APIサーバ のElasticIndexedJobフィーチャーゲート が無効になっている場合、.spec.compleitionsは不変です。
静的なインデックス付きJobの使用例としては、MPI、Horovod、Ray、PyTorchトレーニングジョブなど、インデックス付きJobのスケーリングを必要とするバッチワークロードがあります。
代替案
単なるPod
Podが動作しているノードが再起動または故障した場合、Podは終了し、再起動されません。しかし、終了したPodを置き換えるため、Jobが新しいPodを作成します。このため、たとえアプリケーションが1つのPodしか必要としない場合でも、単なるPodではなくJobを使用することをお勧めします。
Replication Controller
JobはReplication Controllers を補完するものです。Replication Controllerは、終了することが想定されていないPod(Webサーバーなど)を管理し、Jobは終了することが想定されているPod(バッチタスクなど)を管理します。
Podのライフサイクル で説明したように、JobはRestartPolicyがOnFailureかNeverと設定されているPodにのみ 適用されます。(注意:RestartPolicyが設定されていない場合、デフォルト値はAlwaysになります)
シングルJobによるコントローラーPodの起動
もう一つのパターンは、一つのJobが一つPodを作り、そのPodがカスタムコントローラーのような役割を果たし、他のPodを作ります。これは最も柔軟性がありますが、使い始めるにはやや複雑で、Kubernetesとの統合もあまりできません。
この方法のメリットは、全処理過程でJobオブジェクトが完了する保証がありながらも、どのPodを作成し、どのように作業を割り当てるかを完全に制御できることです。
次の項目
Pods について学ぶ。
Jobのさまざまな実行方法について学ぶ:
終了したJobの自動クリーンアップ のリンクから、クラスターが完了または失敗したJobをどのようにクリーンアップするかをご確認ください。
JobはKubernetes REST APIの一部です。JobのAPIを理解するために、
Job オブジェクトの定義をお読みください。
UNIXツールのcronと同様に、スケジュールに基づいて実行される一連のJobを定義するために使用できるCronJob についてお読みください。
段階的な例 に基づいて、PodFailurePolicyを使用して、回復可能なPod失敗と回復不可能なPod失敗の処理を構成する方法を練習します。
3.6 - 終了したリソースのためのTTLコントローラー(TTL Controller for Finished Resources)
FEATURE STATE:
Kubernetes v1.12 [alpha]
TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTL (time to live) メカニズムを提供します。
TTLコントローラーは現在Job のみ扱っていて、将来的にPodやカスタムリソースなど、他のリソースの実行終了を扱えるように拡張される予定です。
α版の免責事項: この機能は現在α版の機能で、kube-apiserverとkube-controller-managerのFeature Gate のTTLAfterFinishedを有効にすることで使用可能です。
TTLコントローラー
TTLコントローラーは現在Jobに対してのみサポートされています。クラスターオペレーターはこの例 のように、Jobの.spec.ttlSecondsAfterFinishedフィールドを指定することにより、終了したJob(完了したもしくは失敗した)を自動的に削除するためにこの機能を使うことができます。
TTLコントローラーは、そのリソースが終了したあと指定したTTLの秒数後に削除できるか推定します。言い換えると、そのTTLが期限切れになると、TTLコントローラーがリソースをクリーンアップするときに、そのリソースに紐づく従属オブジェクトも一緒に連続で削除します。注意点として、リソースが削除されるとき、ファイナライザーのようなライフサイクルに関する保証は尊重されます。
TTL秒はいつでもセット可能です。下記はJobの.spec.ttlSecondsAfterFinishedフィールドのセットに関するいくつかの例です。
Jobがその終了後にいくつか時間がたった後に自動的にクリーンアップできるように、そのリソースマニフェストにこの値を指定します。
この新しい機能を適用させるために、存在していてすでに終了したリソースに対してこのフィールドをセットします。
リソース作成時に、このフィールドを動的にセットするために、管理webhookの変更 をさせます。クラスター管理者は、終了したリソースに対して、このTTLポリシーを強制するために使うことができます。
リソースが終了した後に、このフィールドを動的にセットしたり、リソースステータスやラベルなどの値に基づいて異なるTTL値を選択するために、管理webhookの変更 をさせます。
注意
TTL秒の更新
注意点として、Jobの.spec.ttlSecondsAfterFinishedフィールドといったTTL期間はリソースが作成された後、もしくは終了した後に変更できます。しかし、一度Jobが削除可能(TTLの期限が切れたとき)になると、それがたとえTTLを伸ばすような更新に対してAPIのレスポンスで成功したと返されたとしても、そのシステムはJobが稼働し続けることをもはや保証しません。
タイムスキュー(Time Skew)
TTLコントローラーが、TTL値が期限切れかそうでないかを決定するためにKubernetesリソース内に保存されたタイムスタンプを使うため、この機能はクラスター内のタイムスキュー(時刻のずれ)に対してセンシティブとなります。タイムスキューは、誤った時間にTTLコントローラーに対してリソースオブジェクトのクリーンアップしてしまうことを引き起こすものです。
Kubernetesにおいてタイムスキューを避けるために、全てのNode上でNTPの稼働を必須とします(#6159 を参照してください)。クロックは常に正しいものではありませんが、Node間におけるその差はとても小さいものとなります。TTLに0でない値をセットするときにこのリスクに対して注意してください。
次の項目
3.7 - CronJob
FEATURE STATE:
Kubernetes v1.8 [beta]
CronJob は繰り返しのスケジュールによってJob を作成します。
CronJob オブジェクトとは crontab (cron table)ファイルでみられる一行のようなものです。Cron 形式で記述された指定のスケジュールの基づき、定期的にジョブが実行されます。
注意: すべてのCronJob スケジュール: 時刻はジョブが開始されたkube-controller-manager のタイムゾーンに基づいています。
コントロールプレーンがkube-controller-managerをPodもしくは素のコンテナで実行している場合、CronJobコントローラーのタイムゾーンとして、kube-controller-managerコンテナに設定されたタイムゾーンを使用します。
CronJobリソースのためのマニフェストを作成する場合、その名前が有効なDNSサブドメイン名 か確認してください。名前は52文字を超えることはできません。これはCronJobコントローラーが自動的に、与えられたジョブ名に11文字を追加し、ジョブ名の長さは最大で63文字以内という制約があるためです。
CronJob
CronJobは、バックアップの実行やメール送信のような定期的であったり頻発するタスクの作成に役立ちます。CronJobは、クラスターがアイドル状態になりそうなときにJobをスケジューリングするなど、特定の時間に個々のタスクをスケジュールすることもできます。
例
このCronJobマニフェスト例は、毎分ごとに現在の時刻とhelloメッセージを表示します。
apiVersion : batch/v1
kind : CronJob
metadata :
name : hello
spec :
schedule : "* * * * *"
jobTemplate :
spec :
template :
spec :
containers :
- name : hello
image : busybox
command :
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy : OnFailure
(Running Automated Tasks with a CronJob ではこの例をより詳しく説明しています。).
CronJobの制限
cronジョブは一度のスケジュール実行につき、 おおよそ 1つのジョブオブジェクトを作成します。ここで おおよそ と言っているのは、ある状況下では2つのジョブが作成される、もしくは1つも作成されない場合があるためです。通常、このようなことが起こらないようになっていますが、完全に防ぐことはできません。したがって、ジョブは 冪等 であるべきです。
startingDeadlineSecondsが大きな値、もしくは設定されていない(デフォルト)、そして、concurrencyPolicyをAllowに設定している場合には、少なくとも一度、ジョブが実行されることを保証します。
最後にスケジュールされた時刻から現在までの間に、CronJobコントローラー はどれだけスケジュールが間に合わなかったのかをCronJobごとにチェックします。もし、100回以上スケジュールが失敗していると、ジョブは開始されずに、ログにエラーが記録されます。
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
startingDeadlineSecondsフィールドが設定されると(nilではない)、最後に実行された時刻から現在までではなく、startingDeadlineSecondsの値から現在までで、どれだけジョブを逃したのかをコントローラーが数えます。 startingDeadlineSecondsが200の場合、過去200秒間にジョブが失敗した回数を記録します。
スケジュールされた時間にCronJobが作成できないと、失敗したとみなされます。たとえば、concurrencyPolicyがForbidに設定されている場合、前回のスケジュールがまだ実行中にCronJobをスケジュールしようとすると、CronJobは作成されません。
例として、CronJobが08:30:00を開始時刻として1分ごとに新しいJobをスケジュールするように設定され、startingDeadlineSecondsフィールドが設定されていない場合を想定します。CronJobコントローラーが08:29:00 から10:21:00の間にダウンしていた場合、スケジューリングを逃したジョブの数が100を超えているため、ジョブは開始されません。
このコンセプトをさらに掘り下げるために、CronJobが08:30:00から1分ごとに新しいJobを作成し、startingDeadlineSecondsが200秒に設定されている場合を想定します。CronJobコントローラーが前回の例と同じ期間(08:29:00 から10:21:00まで)にダウンしている場合でも、10:22:00時点でJobはまだ動作しています。このようなことは、過去200秒間(言い換えると、3回の失敗)に何回スケジュールが間に合わなかったをコントローラーが確認するときに発生します。これは最後にスケジュールされた時間から今までのものではありません。
CronJobはスケジュールに一致するJobの作成にのみ関与するのに対して、JobはJobが示すPod管理を担います。
次の項目
Cron表現形式 では、CronJobのscheduleフィールドのフォーマットを説明しています。
cronジョブの作成や動作の説明、CronJobマニフェストの例については、Running automated tasks with cron jobs を見てください。
3.8 - ReplicationController
水平スケーリング可能なワークロードを管理するためのレガシーAPI。 DeploymentおよびReplicaSet APIに置き換えられています。
ReplicationController は、常に指定した数のPodレプリカが実行されていることを保証します。つまり、ReplicationControllerは、単一のPodまたは同質な複数のPodが常に稼働し、利用可能であることを保証します。
ReplicationControllerの動作
Podが多すぎる場合、ReplicationControllerは余分なPodを終了します。Podが少なすぎる場合、ReplicationControllerはさらにPodを起動します。手動で作成したPodとは異なり、ReplicationControllerによって管理されるPodは、障害が発生したり、削除されたり、終了されたりすると自動的に置き換えられます。たとえば、カーネルのアップグレードなどの破壊的なメンテナンスの後には、Podはノード上で再作成されます。このため、アプリケーションが単一のPodのみを必要とする場合でも、ReplicationControllerを使用するべきです。ReplicationControllerはプロセススーパーバイザーに似ていますが、単一ノード上の個々のプロセスを監視する代わりに、ReplicationControllerは複数のノード上の複数のPodを監視します。
ReplicationControllerは、議論の中では「rc」と略されることが多く、kubectlコマンドのショートカットとしても使われます。
単純なケースとしては、ReplicationControllerオブジェクトを1つ作成し、Podインスタンスを1つ無期限に実行し続けることができます。より複雑なユースケースとしては、Webサーバーなどで、複数の同一レプリカを実行することができます。
ReplicationControllerの実行例
このReplicationController設定の例では、nginx Webサーバーの3つのコピーを実行します。
apiVersion : v1
kind : ReplicationController
metadata :
name : nginx
spec :
replicas : 3
selector :
app : nginx
template :
metadata :
name : nginx
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx
ports :
- containerPort : 80
サンプルファイルをダウンロードして、次のコマンドを実行することで、サンプルジョブを実行できます:
kubectl apply -f https://k8s.io/examples/controllers/replication.yaml
出力は次のようになります:
replicationcontroller/nginx created
次のコマンドを使用して、ReplicationControllerのステータスを確認します:
kubectl describe replicationcontrollers/nginx
出力は次のようになります:
Name: nginx
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 0 Running / 3 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- ---- ------ -------
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-qrm3m
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-3ntk0
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-4ok8v
ここでは、3つのPodが作成されていますが、おそらくイメージを取得中であるため、まだ実行状態にはなっていません。少し経ってから同じコマンドを実行すると、次のような出力が得られます:
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
ReplicationControllerに属するすべてのPodをプログラムで処理しやすい形式でリストするには、次のようなコマンドを使用できます:
pods = $( kubectl get pods --selector= app = nginx --output= jsonpath ={ .items..metadata.name} )
echo $pods
出力は次のようになります:
nginx-3ntk0 nginx-4ok8v nginx-qrm3m
ここで、セレクターは、ReplicationControllerのセレクター(kubectl describeの出力で確認できます)と同じで、replication.yamlでは異なる形式で記述されています。--output=jsonpathオプションは、返されたリスト内の各Podから名前を取得する式を指定します。
ReplicationControllerマニフェストの記述
他のすべてのKubernetes設定と同様に、ReplicationControllerにはapiVersion、kind、metadataフィールドが必要です。
コントロールプレーンがReplicationControllerの新しいPodを作成する際、ReplicationControllerの.metadata.nameが、それらのPodを命名する際の基準の一部になります。ReplicationControllerの名前は有効なDNSサブドメイン の値である必要がありますが、これはPodのホスト名に予期しない結果をもたらす可能性があります。互換性を最大限に保つために、名前はDNSラベル に準じた、より厳格なルールに従うことをお勧めします。
設定ファイルの操作に関する一般的な情報については、オブジェクト管理 を参照してください。
また、ReplicationControllerには.specセクション も必要です。
Podテンプレート
.spec.templateは.specの唯一の必須フィールドです。
.spec.templateはPodテンプレート です。Pod とまったく同じスキーマを持ちますが、ネストされている点や、apiVersionやkindを持たない点が異なります。
Podの必須フィールドに加えて、ReplicationController内のPodテンプレートは適切なラベルと適切な再起動ポリシーを指定する必要があります。ラベルについては、他のコントローラーと重複しないようにしてください。詳しくは、Podセレクター を参照してください。
.spec.template.spec.restartPolicy にはAlwaysのみが許可されており、指定されていない場合、デフォルトでAlwaysになります。
ローカルコンテナの再起動については、ReplicationControllerはKubelet などのノード上のエージェントに委任します。
ReplicationControllerのラベル
ReplicationController自体もラベル(.metadata.labels)を持つことができます。通常、これらは.spec.template.metadata.labelsと同じに設定します。.metadata.labelsが指定されていない場合、デフォルトで.spec.template.metadata.labelsになります。ただし、これらは異なる値に設定することが可能で、.metadata.labelsはReplicationControllerの動作には影響しません。
Podセレクター
.spec.selectorフィールドはラベルセレクター です。ReplicationControllerは、セレクターに一致するラベルを持つすべてのPodを管理します。ReplicationController自身が作成したPodか、他の人やプロセスが作成したPodかを区別しません。これにより、実行中のPodに影響を与えることなく、ReplicationControllerを置き換えることができます。
指定されている場合、.spec.template.metadata.labelsは.spec.selectorと等しい必要があり、そうでない場合はAPIによって拒否されます。もし、.spec.selectorが指定されていない場合は、デフォルトで.spec.template.metadata.labelsに設定されます。
また、通常は、このセレクターに一致するラベルを持つPodを、直接、または別のReplicationControllerを通して、またはJobなどの別のコントローラーで作成しないでください。もし作成すると、ReplicationControllerは他のPodを自身が作成したPodであるとみなしてしまいます。Kubernetesはこのような操作を制限しません。
複数のコントローラーのセレクターが重複してしまった場合、削除を自分で管理する必要があります(下記 を参照)。
複数のレプリカ
.spec.replicasを、同時に実行したいPodの数に設定することで、同時に実行すべきPodの数を指定できます。任意の時点で実行されているPod数は、レプリカ数の増減直後や、Podの正常なシャットダウンと代替Podの早期起動が重なった場合などに、指定した数と多少異なることがあります。
.spec.replicasを指定しない場合、デフォルトは1に設定されます。
ReplicationControllerの操作
ReplicationControllerとそのPodの削除
ReplicationControllerとそのすべてのPodを削除するには、kubectl delete を使用します。Kubectlは、ReplicationControllerをゼロにスケールし、各Podを削除するのを待ってから、ReplicationController自体を削除します。このkubectlコマンドが中断された場合、再起動できます。
REST APIまたはクライアントライブラリ を使用する場合は、明示的に手順を実行する必要があります(レプリカを0にスケール後、Pod削除を待機し、ReplicationControllerを削除する)。
ReplicationControllerのみの削除
Podに影響を与えることなく、ReplicationControllerを削除することが可能です。
kubectlを使用して、kubectl delete に--cascade=orphanオプションを指定します。
REST APIまたはクライアントライブラリ を使用する場合は、ReplicationControllerオブジェクトを削除できます。
元のコントローラーが削除されたら、新しいReplicationControllerを作成して置き換えることができます。新旧の.spec.selectorが同じである限り、新しいコントローラーは古いPodを引き継ぎます。ただし、既存のPodを新しい異なるPodテンプレートに合わせて更新することはしません。制御された方法でPodを新しい仕様に更新するには、ローリングアップデート を使用します。
ReplicationControllerからPodを分離する
Podのラベルを変更することで、ReplicationControllerの管理対象から外すことができます。この手法は、デバッグやデータ復旧の目的で、Podをサービスから削除するために使用できます。この方法で削除されたPodは、自動的に置き換えられます(レプリカ数も変更されていないと仮定)。
一般的な使用パターン
再スケジューリング
前述のとおり、実行し続けたいPodが1つでも1000でも、ReplicationControllerは、ノード障害やPodの終了(たとえば、別の制御エージェントによる操作など)が発生した場合でも、指定された数のPodが存在することを保証します。
スケーリング
ReplicationControllerは、手動またはオートスケーリング制御エージェントによって、replicasフィールドを更新することで、レプリカ数を増減させることができます。
ローリングアップデート
ReplicationControllerは、Podを1つずつ置き換えることで、サービスへのローリングアップデートを容易にするように設計されています。
#1353 で説明されているように、推奨されるアプローチは、1つのレプリカで新しいReplicationControllerを作成し、新しいコントローラー(+1)と古いコントローラー(-1)を1つずつスケールし、古いコントローラーが0レプリカに達したら削除することです。これにより、予期しない障害に左右されることなく、Podのセットが予測どおりに更新されます。
理想的には、ローリングアップデートコントローラーはアプリケーションの準備状態を考慮し、常に十分な数のPodが実際にサービスを提供できる状態にあることを保証します。
2つのReplicationControllerは、Podのプライマリコンテナのイメージタグなど、少なくとも1つのラベルで区別できるPodを作成する必要があります。ローリングアップデートのきっかけになるのは、通常はイメージの更新が原因であるためです。
複数のリリーストラック
ローリングアップデート中にアプリケーションの複数のリリースを実行するのに加えて、複数のリリーストラックを用いて、複数のリリースを長期間、あるいは継続的に実行することも一般的です。トラックはラベルで区別されます。
たとえば、とあるサービスがtier in (frontend), environment in (prod)の条件を満たすラベルを持つ、すべてのPodを対象にしているとします。このティアを構成する10個のレプリケートされたPodがあるとします。ただし、このコンポーネントの新しいバージョンを「カナリア」リリースしたいとします。大部分のレプリカについて、replicasを9に設定し、ラベルtier=frontend, environment=prod, track=stableを持つReplicationControllerを設定し、カナリア用にreplicasを1に設定し、ラベルtier=frontend, environment=prod, track=canaryを持つ別のReplicationControllerを設定できます。これで、サービスはカナリアと非カナリアの両方のPodをカバーします。一方で、ReplicationControllerを個別に操作して、テストしたり、結果を監視したりすることもできます。
ReplicationControllerとサービスの併用
複数のReplicationControllerを単一のサービスの背後に配置して、たとえば、一部のトラフィックが古いバージョンに送られ、一部が新しいバージョンに送られるようにすることができます。
ReplicationControllerは自ら終了することはありませんが、サービスほど長く存在し続けることは想定されていません。サービスは、複数のReplicationControllerによって制御されるPodで構成される場合があり、1つのサービスの存続期間中に多くのReplicationControllerが作成・破棄されることが想定されます(たとえば、サービスを実行するPodを更新する場合など)。サービス自体とそのクライアントは、サービスのPodを維持しているReplicationControllerについて意識する必要はありません。
レプリケーション用のプログラムの記述
ReplicationControllerによって作成されたPodは、交換可能で意味的に同一であることを意図していますが、時間の経過とともに構成が不均一になる可能性があります。これは、レプリケートされたステートレスなサーバーに適していることは明らかですが、ReplicationControllerは、マスター選出、シャーディング、ワーカープールアプリケーションなど可用性維持のためにも使用できます。このようなアプリケーションでは、アンチパターンと見なされる各Podの構成の静的/1回限りのカスタマイズではなく、RabbitMQワークキュー などの動的なワーク割り当てメカニズムを使用する必要があります。実行されるPodのカスタマイズ、たとえばリソースの垂直オートサイジング(cpuやメモリなど)は、ReplicationController自体と同様に、別のオンラインコントローラープロセスによって実行される必要があります。
ReplicationControllerの責任
ReplicationControllerは、ラベルセレクターに一致するPodが目的の数だけ存在し、それらが動作していることを保証します。現在は、終了したPodのみがカウントから除外されます。将来的には、readiness やシステムから利用可能なその他の情報が考慮される可能性があり、置き換えポリシーに対してより多くの制御を追加する可能性があります。また、外部クライアントが任意の洗練された置き換えポリシーやスケールダウンポリシーを実装するために使用できるイベントを発行する予定です。
ReplicationControllerは、常にこの限定された責任のみを持ちます。ReplicationController自身が、Readiness ProbeやLiveness Probeを実行することはありません。オートスケーリングを実行するのではなく、(#492 で議論されているように)外部のオートスケーラーによって制御され、そのオートスケーラーがreplicasフィールドを変更することを想定しています。ReplicationControllerにスケジューリングポリシー(たとえば、spreading )を追加することはありません。また、制御しているPodが現在指定されているテンプレートと一致することを検証すべきではありません。それは、オートサイジングやその他の自動化されたプロセスを妨げるためです。同様に、完了期限、順序依存関係、設定の展開、その他の機能は別の場所に属します。一括でのPod作成のメカニズムを分離することさえ計画しています(#170 )。
ReplicationControllerは、組み合わせ可能なビルディングブロックのプリミティブとして意図されています。将来的には、ユーザーの利便性のために、ReplicationControllerやその他の補完的なプリミティブの上に、より高レベルのAPIやツールが構築されることを期待しています。現在kubectlでサポートされている「マクロ」操作(run、scale)は、これの概念実証の例です。たとえば、ReplicationController、オートスケーラー、サービス、スケジューリングポリシー、カナリアなどを管理するAsgard のようなものが想定されます。
APIオブジェクト
ReplicationControllerは、Kubernetes REST APIのトップレベルリソースです。APIオブジェクトの詳細については、以下を参照してください:ReplicationController APIオブジェクト 。
ReplicationControllerの代替
ReplicaSet
ReplicaSet は、新しい集合ベースのラベルセレクター をサポートする次世代のReplicationControllerです。主にDeployment によって、Pod作成、削除、更新を調整するメカニズムとして使用されます。カスタムの更新オーケストレーションが必要な場合や、更新がまったく必要ない場合を除き、ReplicaSetを直接使用するのではなく、Deploymentを使用することをお勧めします。
Deployment(推奨)
Deployment は、基盤となるReplicaSetとそのPodを更新する、より高レベルのAPIオブジェクトです。Deploymentは宣言的で、サーバー側で動作し、追加機能を持つため、ローリングアップデート機能が必要な場合には推奨されます。
ベアPod
ユーザーが直接Podを作成した場合とは異なり、ReplicationControllerは、ノード障害やカーネルアップグレードなどの破壊的なノードメンテナンスなど、何らかの理由で削除または終了されたPodを置き換えます。このため、アプリケーションが単一のPodのみを必要とする場合でも、ReplicationControllerを使用することを推奨します。プロセススーパーバイザーと同様に考えてください。ただし、単一ノード上の個々のプロセスではなく、複数のノード上の複数のPodを監視する点が異なります。ReplicationControllerは、ローカルコンテナの再起動をkubeletなどのノード上のエージェントに委任します。
Job
自ら終了することが期待されるPod(つまり、バッチジョブ)には、ReplicationControllerの代わりにJob を使用してください。
DaemonSet
マシン監視やマシンログなど、マシンレベルの機能を提供するPodには、ReplicationControllerの代わりにDaemonSet を使用してください。これらのPodは、マシンの稼働期間に結び付けられた存続期間を持ちます。Podは、他のPodが起動する前にマシン上で実行されている必要があり、マシンが再起動またはシャットダウンの準備ができたときに安全に終了できます。
次の項目
4 - ワークロードの管理
アプリケーションをデプロイし、Serviceを介して公開しました。次に何をすべきでしょうか?Kubernetesには、スケーリングや更新など、アプリケーションのデプロイメントを管理するためのいくつかのツールが用意されています。
リソース構成の整理
多くのアプリケーションでは、Serviceに加えてDeploymentなどの複数のリソースを作成する必要があります。複数のリソースを管理しやすくするために、同じファイル内にまとめて記述することができます(YAMLでは---で区切ります)。例えば、以下のように定義します。
apiVersion : v1
kind : Service
metadata :
name : my-nginx-svc
labels :
app : nginx
spec :
type : LoadBalancer
ports :
- port : 80
selector :
app : nginx
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : my-nginx
labels :
app : nginx
spec :
replicas : 3
selector :
matchLabels :
app : nginx
template :
metadata :
labels :
app : nginx
spec :
containers :
- name : nginx
image : nginx:1.14.2
ports :
- containerPort : 80
複数のリソースは、単一のリソースと同じ方法で作成できます。
kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created
リソースはマニフェスト内に記述された順番で作成されます。したがって、Serviceを先に指定するのが望ましいです。これにより、DeploymentなどのコントローラーによってPodが作成される際に、スケジューラーがServiceに関連付けられたPodを適切に分散できるようになります。
また、kubectl applyは複数の-f引数を受け付けます。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml \
-f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
同じマイクロサービスやアプリケーションの階層に関連するリソースは、同じファイルにまとめることが推奨されます。また、アプリケーションに関連するすべてのファイルを同じディレクトリに整理することで、管理しやすくなります。アプリケーションの各階層がDNSを使用して相互に接続される場合、スタックのすべてのコンポーネントをまとめてデプロイできます。
さらに、設定ソースとしてURLを指定することも可能です。これにより、ソース管理システム内のマニフェストから直接デプロイする際に便利です。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created
さらに、ConfigMapを追加するなど、追加のマニフェストを定義することも可能です。
外部ツール
このセクションでは、Kubernetes上でワークロードを管理するために一般的に使用されるツールのみを紹介します。より多くのツールの一覧については、CNCF Landscapeのアプリケーション定義とイメージビルド を参照してください。
🛇 This item links to a third party project or product that is not part of Kubernetes itself.
More information
Helm は、あらかじめ設定されたKubernetesリソースのパッケージを管理するためのツールです。これらのパッケージは Helmチャート と呼ばれます。
Kustomize は、Kubernetesのマニフェストを処理し、設定オプションを追加・削除・更新するツールです。Kustomizeは単独のバイナリとして利用できるほか、kubectlのネイティブ機能 としても利用できます。
kubectlにおける一括操作
リソースの作成だけがkubectlによる一括操作の対象ではありません。設定ファイルからリソース名を抽出し、他の操作を実行することも可能です。特に、作成したリソースを削除する際に利用できます。
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
2つのリソースを対象とする場合、resource/nameの構文を使って、両方のリソースをコマンドラインで指定することができます。
kubectl delete deployments/my-nginx services/my-nginx-svc
さらに多数のリソースを扱う場合は、-lまたは--selectorを使用してラベルによるフィルタリング(ラベルクエリ)を行う方が簡単です。
kubectl delete deployment,services -l app = nginx
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
チェーン処理とフィルタリング
kubectlは、受け入れるのと同じ構文でリソース名を出力するため、$()やxargsを使用して操作を連結できます。
kubectl get $( kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service/)
kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service/ | xargs -i kubectl get '{}'
出力は次のようになります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-svc LoadBalancer 10.0.0.208 <pending> 80/TCP 0s
上記のコマンドでは、まずdocs/concepts/cluster-administration/nginx/内のリソースを作成し、-o name出力形式を使用して作成されたリソースを出力します(各リソースをresource/nameの形式で出力します)。次にgrepを使ってServiceのみを抽出し、それをkubectl get で表示します。
ローカルファイルに対する再帰的操作
特定のディレクトリ内でリソースを複数のサブディレクトリに整理している場合、--filename/-f引数とともに--recursiveまたは-Rを指定することで、サブディレクトリ内のリソースにも再帰的に操作を実行できます。
例えば、開発環境に必要なすべての マニフェスト を保持し、リソースの種類ごとに整理されたproject/k8s/developmentというディレクトリがあるとします。
project/k8s/development
├── configmap
│ └── my-configmap.yaml
├── deployment
│ └── my-deployment.yaml
└── pvc
└── my-pvc.yaml
デフォルトでは、project/k8s/developmentに対して一括操作を実行すると、ディレクトリの最上位レベルで処理が止まり、サブディレクトリ内のリソースは処理されません。そのため、以下のコマンドを使用してこのディレクトリ内のリソースを作成しようとすると、エラーが発生します。
kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)
その代わりに、--filename/-f引数とともに--recursiveまたは-Rを指定してください。
kubectl apply -f project/k8s/development --recursive
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
--recursive引数は、--filename/-f引数を受け付けるすべての操作で使用できます。例えば、kubectl create、kubectl get、kubectl delete、kubectl describe、kubectl rolloutなどに適用できます。
また、--recursive引数は、複数の-f引数が指定された場合にも機能します。
kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
kubectlについて詳しく知りたい場合は、コマンドラインツール(kubectl) を参照してください。
アプリケーションをダウンタイムなしで更新する
デプロイ済みのアプリケーションは、いずれ更新が必要になります。通常は、新しいイメージまたはイメージタグを指定することで更新を行います。kubectlには、さまざまな更新操作が用意されており、それぞれ異なるシナリオに適用できます。
アプリケーションの複数のコピーを実行し、ロールアウト を使用して新しい正常なPodへ段階的にトラフィックを移行することで、ダウンタイムなしの更新が可能です。最終的には、すべての実行中のPodが新しいソフトウェアへ更新されます。
このセクションでは、Deploymentを使用してアプリケーションを作成し、更新する方法について説明します。
例えば、nginxのバージョン1.14.2を実行しているとします。
kubectl create deployment my-nginx --image= nginx:1.14.2
deployment.apps/my-nginx created
1つのレプリカが存在することを確認します。
kubectl scale --replicas 1 deployments/my-nginx --subresource= 'scale' --type= 'merge' -p '{"spec":{"replicas": 1}}'
deployment.apps/my-nginx scaled
そして、ロールアウト時にKubernetesが一時的なレプリカをより多く追加できるようにするため、最大サージ を100%に設定します。
kubectl patch --type= 'merge' -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge": "100%" }}}}'
deployment.apps/my-nginx patched
バージョン1.16.1へ更新するには、.spec.template.spec.containers[0].imageをnginx:1.14.2からnginx:1.16.1に変更します。kubectl editを使用してマニフェストを編集します。
kubectl edit deployment/my-nginx
# 新しいコンテナイメージを使用するようにマニフェストを変更し、変更を保存
以上で完了です!Deploymentは、デプロイされたnginxアプリケーションを宣言的に更新し、バックグラウンドで段階的に処理を進めます。これにより、更新中に一定数の古いレプリカのみが停止され、新しいレプリカが必要なPod数を超えて作成されることがないように制御されます。この仕組みの詳細については、Deployment を参照してください。
ロールアウトは、DaemonSet、Deployment、StatefulSetに対して使用できます。
ロールアウトの管理
kubectl rollout を使用すると、既存のアプリケーションの段階的な更新を管理できます。
例えば、次のように実行できます。
kubectl apply -f my-deployment.yaml
# ロールアウトの完了を待機
kubectl rollout status deployment/my-deployment --timeout 10m # 10分のタイムアウト
または、次のように実行できます。
kubectl apply -f backing-stateful-component.yaml
# ロールアウトの完了を待たず、ステータスのみを確認
kubectl rollout status statefulsets/backing-stateful-component --watch= false
さらに、ロールアウトを一時停止、再開、または取り消すことも可能です。詳細については、kubectl rollout を参照してください。
カナリアデプロイ
複数のラベルが必要となる別のシナリオとして、同じコンポーネントの異なるリリースや設定を区別する場合があります。一般的な方法として、新しいアプリケーションリリース(Podテンプレート内のイメージタグで指定)を、以前のリリースと並行してカナリア デプロイすることがあります。これにより、新しいリリースが本番環境のトラフィックを受け取りつつ、完全にロールアウトする前に動作を確認できます。
例えば、trackラベルを使用して異なるリリースを区別することができます。
プライマリの安定したリリースには、trackラベルの値としてstableを設定します。
name: frontend
replicas: 3
...
labels:
app: guestbook
tier: frontend
track: stable
...
image: gb-frontend:v3
その後、trackラベルの値を異なる値(例:canary)に設定した新しいguestbook frontendのリリースを作成することで、2つのPodセットが重ならないようにすることができます。
name: frontend-canary
replicas: 1
...
labels:
app: guestbook
tier: frontend
track: canary
...
image: gb-frontend:v4
フロントエンドのServiceは、両方のレプリカセットにまたがるように、共通のラベルの部分集合(つまり、trackラベルを省略)を選択することで、トラフィックを両方のアプリケーションに振り分けることができます。
selector :
app : guestbook
tier : frontend
stableリリースとcanaryリリースのレプリカ数を調整することで、それぞれのリリースが本番トラフィックを受け取る割合(この例では、3:1)を決定できます。新しいリリースに十分な自信が持てたら、stableトラックを新しいアプリケーションリリースに更新し、canaryリリースを削除します。
アノテーションの更新
リソースにアノテーションを付与したい場合があります。アノテーションは、ツールやライブラリなどのAPIクライアントが取得できる、識別情報ではない任意のメタデータです。これを行うには、kubectl annotateを使用します。例えば、次のように実行できます。
kubectl annotate pods my-nginx-v4-9gw19 description = 'my frontend running nginx'
kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1
kind: pod
metadata:
annotations:
description: my frontend running nginx
...
詳細については、アノテーション およびkubectl annotate を参照してください。
アプリケーションのスケーリング
アプリケーションの負荷が増減した際には、kubectlを使用してスケーリングを行うことができます。例えば、nginxのレプリカ数を3から1に減らすには、次のように実行します。
kubectl scale deployment/my-nginx --replicas= 1
deployment.apps/my-nginx scaled
これで、Deploymentによって管理されるPodは1つだけになりました。
kubectl get pods -l app = my-nginx
NAME READY STATUS RESTARTS AGE
my-nginx-2035384211-j5fhi 1/1 Running 0 30m
システムに必要に応じてnginxのレプリカ数(1~3の範囲)を自動的に選択させるには、次のコマンドを実行します。
# これには、コンテナおよびPodのメトリクスの取得元が必要です
kubectl autoscale deployment/my-nginx --min= 1 --max= 3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
これで、nginxのレプリカ数は必要に応じて自動的にスケールアップおよびスケールダウンされます。
詳しくは、kubectl scale 、kubectl autoscale 、および水平Pod自動スケーリング のドキュメントを参照してください。
リソースのインプレース更新
作成したリソースに対して、小規模で影響の少ない更新を行う必要がある場合があります。
kubectl apply
構成ファイルのセットをソース管理下で管理すること(構成のコード化 を参照)が推奨されています。これにより、構成対象のリソースのコードとともに、構成を保守・バージョン管理することができます。その後、kubectl apply を使用して、構成の変更をクラスターに反映できます。
このコマンドは、適用しようとしている設定のバージョンと、以前のバージョンを比較し、変更を適用します。指定していないプロパティに対する自動的な変更は上書きされません。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
基盤となる仕組みについて詳しく知りたい場合は、server-side apply を参照してください。
kubectl edit
あるいは、kubectl edit を使用してリソースを更新することもできます。
kubectl edit deployment/my-nginx
これは、まずリソースをgetで取得し、テキストエディターで編集した後、更新されたバージョンをapplyで適用するのと同等です。
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# 何らかの編集を行い、ファイルを保存
kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured
rm /tmp/nginx.yaml
これにより、より大きな変更を簡単に行うことができます。なお、EDITORまたはKUBE_EDITOR環境変数を指定することで、使用するエディターを設定できます。
詳しくは、kubectl edit を参照してください。
kubectl patch
kubectl patch を使用すると、APIオブジェクトをインプレースで更新できます。このサブコマンドは、JSONパッチ、JSONマージパッチ、戦略的マージパッチをサポートしています。
詳細については、kubectl patchを使用したAPIオブジェクトのインプレース更新 を参照してください。
破壊的な更新
場合によっては、一度初期化されると更新できないリソースのフィールドを変更する必要があることがあります。また、Deploymentによって作成された異常なPodを修正するなど、即座に再帰的な変更を行いたい場合もあります。そのようなフィールドを変更するには、replace --forceを使用します。このコマンドは、リソースを削除し再作成することで変更を適用します。この場合、元の設定ファイルを修正して適用できます。
kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced
次の項目
5 - ワークロードの自動スケーリング
自動スケーリングによって、何らかのかたちでワークロードを自動的に更新できます。これによりクラスターはリソース要求の変化に対してより弾力的かつ効率的に対応できるようになります。
Kubernetesでは、現在のリソース要求に応じてワークロードをスケールできます。これによりクラスターはリソース要求の変化に対してより弾力的かつ効率的に対応できるようになります。
ワークロードをスケールするとき、ワークロードによって管理されるレプリカ数を増減したり、レプリカで使用可能なリソースをインプレースで調整できます。
ひとつ目のアプローチは 水平スケーリング と呼ばれ、一方でふたつ目のアプローチは 垂直スケーリング と呼ばれます。
ユースケースに応じて、ワークロードをスケールするには手動と自動の方法があります。
ワークロードを手動でスケーリングする
Kubernetesはワークロードの 手動スケーリング をサポートします。水平スケーリングはkubectl CLIを使用して行うことができます。垂直スケーリングの場合、ワークロードのリソース定義を パッチ適用 する必要があります。
両方の戦略の例については以下をご覧ください。
ワークロードを自動でスケーリングする
Kubernetesはワークロードの 自動スケーリング もサポートしており、これがこのページの焦点です。
Kubernetesにおける オートスケーリング の概念は、一連のPodを管理するオブジェクト(例えばDeployment )を自動的に更新する機能を指します。
ワークロードを水平方向にスケーリングする
Kubernetesにおいて、 HorizontalPodAutoscaler (HPA)を使用してワークロードを水平方向に自動的にスケールできます。
これはKubernetes APIリソースおよびコントローラー として実装されており、CPUやメモリ使用率のような観測されたリソース使用率と一致するようにワークロードのレプリカ 数を定期的に調整します。
Deployment用のHorizontalPodAutoscalerを構成するウォークスルーチュートリアル があります。
ワークロードを垂直方向にスケーリングする
FEATURE STATE:
Kubernetes v1.25 [stable]
VerticalPodAutoscaler (VPA)を使用してワークロードを垂直方向に自動的にスケールできます。HPAと異なり、VPAはデフォルトでKubernetesに付属していませんが、GitHubで 見つかる別のプロジェクトです。
インストールすることにより、管理されたレプリカのリソースを どのように いつ スケールするのかを定義するワークロードのCustomResourceDefinitions (CRDs)を作成できるようになります。
現時点では、VPAは4つの異なるモードで動作できます:
VPAの異なるモード
モード
説明
Auto
現在はRecreateです。これは将来インプレースアップデートに変更される可能性があります。
Recreate
VPAはPod作成時にリソースリクエストを割り当てるだけでなく、要求されたリソースが新しい推奨事項と大きく異なる場合にそれらを削除することによって既存のPod上でリソースリクエストを更新します。
Initial
VPAはPod作成時にリソースリクエストを割り当て、後から変更することはありません。
Off
VPAはPodのリソース要件を自動的に変更しません。推奨事項は計算され、VPAオブジェクトで検査できます。
インプレースPodの水平スケーリング
FEATURE STATE:
Kubernetes v1.35 [stable](enabled by default)
Kubernetes 1.35の時点では、VPAはインプレースでのPodのリサイズをサポートしていませんが、この統合は現在作業中です。インプレースでPodの手動リサイズをするには、コンテナリソースをインプレースでリサイズする を参照してください。
クラスターサイズに基づく自動スケーリング
クラスターのサイズに基づいてスケールする必要があるワークロード(例えばcluster-dnsや他のシステムコンポーネント)の場合は、Cluster Proportional Autoscaler を使用できます。VPAと同じように、これはKubernetesのコア部分ではありませんが、独自のGitHubプロジェクトとしてホストされています。
Cluster Proportional Autoscalerはスケジュール可能なノード とコアの数を監視し、それに応じてターゲットワークロードのレプリカ数をスケールします。
レプリカ数を同じままにする必要がある場合、Cluster Proportional Vertical Autoscaler を使用してクラスターサイズに応じてワークロードを垂直方向にスケールできます。このプロジェクトは現在ベータ版 でありGitHubで見つけることができます。
Cluster Proportional Autoscalerがワークロードのレプリカ数をスケールする一方で、Cluster Proportional Vertical Autoscalerはクラスター内のノードおよび/またはコアの数に基づいてワークロード(例えばDeploymentやDaemonSet)のリソース要求を調整します。
イベント駆動型自動スケーリング
例えばKubernetes Event Driven Autoscaler
(KEDA ) を使用して、イベントに基づいてワークロードをスケールすることもできます。
KEDAは例えばキューのメッセージ数などの処理するべきイベント数に基づいてワークロードをスケールするCNCF Graduatedプロジェクトです。様々なイベントソースに合わせて選択できる幅広いアダプターが存在します。
スケジュールに基づく自動スケーリング
ワークロードををスケールするためのもう一つの戦略は、例えばオフピークの時間帯にリソース消費を削減するために、スケーリング操作をスケジュールする ことです。
イベント駆動型オートスケーリングと同様に、そのような動作はKEDAをCronスケーラー と組み合わせて使用することで実現できます。Cronスケーラーによりワークロードをスケールインまたはスケールアウトするためのスケジュール(およびタイムゾーン)を定義できます。
クラスターのインフラストラクチャのスケーリング
ワークロードのスケーリングだけではニーズを満たすのに十分でない場合は、クラスターのインフラストラクチャ自体をスケールすることもできます。
クラスターのインフラストラクチャのスケーリングは通常ノード の追加または削除を意味します。詳しくはNodeの自動スケーリング を読んでください。
次の項目