Kubernetesを知る ~2.各種リソース~
概要
今回はkubernetesリソースの役割を記載していきます。
QUESTION
以下の質問や語句がわからない方向けの記事になります。
- kubernetesって?
- Dockerとの関係は?
- podとかnodeとか言われてもわからないです
Kubernetesとは
kubernetesはDockerなどのソフトウェア(コンテナランタイムと言う)で作成されたコンテナをデプロイ・オーケストレーションするプラットフォームです。
長いのでk8sとか言われたりもします。kとsの間が8文字だからk8sです[1]。以後文章内ではk8sと言います。
k8sはコンテナランタイムに対し、色々な命令(コンテナを作って、コンテナを削除して、など)を出します。
前回の図とほぼ同じですが高レベルコンテナランタイムを呼び出しているのが、Kubernetesに代わっています。
つまりk8sはコンテナランタイムとのやりとりをしてくれるものになります。
そもそもとして、Dockerはあくまでコンテナを作成する機能しか備えておらず、各コンテナ間の連携や全コンテナの管理などはできません。
単一のコンテナ(プロセス)で完結し変更がなければいいですが、そうでない場合はデプロイ・オーケストレーションができるk8sを使う必要が出てくるわけです。
k8sを使いたくない場合は頑張ってオーケストレーションができる仕組みを何かしらで構築する必要があります。
kubernetesのリソースなど
k8sは様々なリソースとコンポーネントで構成されています。
kubectlで(個人的に)よく操作するリソースをピックアップしまとめていきます。
Pod
podはイメージをもとに作成されたコンテナを実行する環境を提供します。
k8sのリソースの最小単位でコンテナの実態になります。
つまり、k8sでPodを作成することはDockerでコンテナを作成することという理解になります。
podは1podに1コンテナ、もしくはメインコンテナとサブコンテナからなる2コンテナで構成されます。
podはpod間の通信やストレージを介したデータ共有もできるため、podのデータを永続的に保持できます。
podは自身で作成することもできますが、メインはワークロードリソースというpodを作成・管理するオブジェクトから作成します。
Node
マスターノードとワーカーノードの2種類のNodeがあり、
Podの実行環境を提供するリソースをNodeと言います。実態はVMもしくは物理マシンで、ベアメタル、クラウドなどk8sの実行環境によります。
Nodeは利用可能なリソース(ここではcpuやmemoryなど)を保持しており、それを超えてのPodのスケジュールは行われません。
上記はNodeの情報のcapacityとallocatableから確認できます。
- capacity: Nodeが持っている利用可能なリソース
- allocatable: 配置されているPodが純粋に使用しているリソースの合計
Service
Podの外部通信、Pod間通信を補うための機能です。
Podが持つIPによって通信ができますが、後述するワークロードリソースによってPodの作成と削除が行われたとき削除前のIPアドレスと異なる場合があります。
IPアドレスが可変となるとクライアントから通信だったりDNSに登録したい場合などはIPアドレスが変わるたび修正しなくてはならないので不便です。
そのようなときに使用するのがServiceになります。
Serviceは固定のIPを持ち、Serviceの以下定義によって宛先となるPodにトラフィックを流します。
-
spec.ports
のポート情報と一致するPod -
spec.selector.app
と一致するラベルを持つPod
ただし必ずしもPodを宛先とする必要はなく、ServiceからServiceなどエンドポイントを変更することができます。spec.selector.app
を定義せずspec.ports
に対応するEndpoints
というリソースを作成することで実現できます。
ワークロードリソース
k8sで使えるアプリケーションで、簡単に言うとPodの管理を行う機能のことをワークロードリソースと言います。
Podの説明に記載しましたが、Podは直接作成するのではなくワークロードを通し作成することでk8sの真価を発揮します。
ReplicaSet
稼働しているpodの数を調整しリソース過多・不足を補うワークロードリソースです。
ReplicaSetは、以下の定義から構成されます。
- 稼働状態にするpod数(replica数)
- podのスケジュール時に使用されるpodテンプレート
調整対象のPodは以下の要素で判断されます。
- ReplicaSetの
spec.selectort
で定義したラベルを持つpod - Podが持つownerReferencesプロパティが自身のreplicasetを指しているpod
ReplicaSetがpodの作成を行った場合、そのPodはownerReferencesというプロパティを保持するので調整対象となり、それ以外の場合はPodが持つラベルがspec.selectort
と一致した場合に調整対象となります。
調整対象のpodがreplica数に満たない、もしくは多すぎる場合、ReplicaSetによりpodがreplica数に合うようスケジュール(podの作成or削除)を行います。
こちらも自身で作成できますがメインはReplicaSetを管理するDeploymentによって作成します。
Deployment
ReplicaSetを管理するワークロードリソースで、Depolyment→ReplicaSet→Podという親子関係になっています。
k8sではpodの調整が不要でもDeploymentを使いReplicaSetを通しpodを作成することが推奨されています。
Deploymentを更新しても古いReplicaSetは削除されず、同じPodTemplateSpecが適用された場合に再使用されます。
なお、Deploymentは更新されたが.spec.template
配下に変更がないという場合は、ReplicaSetおよびPodのスケジュールは行われません。
例えばreplica数の変更の場合はPodの増減はあるかもしれませんが、展開されているPodの更新は行われません。replica数の定義は.spec.replica
であるためです。Podのimageなどが変わる場合などにPodの再スケジュール(削除→作成)が発生します。
ロールアウトについて
DeploymentのPodTemplateSpecを更新することで新しいReplicaSetが作成されますが、このとき更新前のReplicaSetはreplica数が0という情報がDeploymentのロールアウト履歴として残ります。そしてその履歴をもとにロールバックすることができます。
履歴からのロールバックではなく、更新前のDeploymentのマニフェストファイルを再適用した場合も、ロールアウト履歴と一致するReplicaSetが使用されます。
ロールアウト履歴の上限は.spec.revisionHistoryLimit
で指定でき、0を指定するとすべての履歴が削除されます。
StatefulSet
名前の通りステートフルとなるようpodの作成・管理を行います。
これに対しDeploymentやReplicaSetはステートレスです。
StatefulSetによって作成されるPod名には以下の特徴があります。
- スケジュールされてもPod名は変わらない
- Pod名(ホスト名)は「StatefulSet名-連番」と命名され、例えば「statefulpod-1, statefulpod-2 ...」のようになる
ReplicaSetなどと違い以下のような特徴があります。
- StatefulSetを削除してもStatefulSetによって作成されたPodは削除されない
- スケジュールの際、増加の場合はPodの作成→Running待機→作成 ...と順番に1個ずつ行われる
- スケジュールの際、削除の場合は最新のPod(一番大きい数字)から削除される
StatefulSetで作成したPodにはk8sのストレージという機能の、PersistentVolumeという永続的なデータを保持する領域が設定されます。
マニフェスト内のvolumeClaimTemplates
で使用したいPersistentVolumeを定義することもできます。
Podが削除されたり停止した場合でも、StatefulSetの定義により再スケジュールされたときに定義されたストレージがマウントされるためデータの損失は起きません。
この特性からStatefulSetを削除した場合でも、このPersistentVolumeは削除されずクリーンアップしたい場合は手動で削除する必要があります。
DeamonSet
特定の単一のPodを全てのNodeに作成します[2]。ReplicaSetと似た機能を提供しますが、ReplicaSetの場合は全てのNodeにではなくリソースに空きがあるNodeに適当に作成します[3]。
また、replica数の指定はできないので単一のPodしか作成できません
全てのNodeに配置したい以下のようなユースケースで使用します。
- Podの状態をモニタリングする
- ログの集計を行う
Job
以下の一連の流れを行う機能です。
- Jobのマニフェストファイルに従ってPodを作成
- 作成したPodの状態を確認する
- Podが障害などで削除や停止した場合、Podを再作成する
- 作成したPodの状態が全て完了になるまで繰り返し
上記処理を以下のようにカスタマイズすることもできます。
- 並列実行(
.spec.parallelism
で定義。デフォルトは1で単一。) - 全てではなく任意の個数が完了した場合終了とする(
.spec.completions
で定義。デフォルトは、.spec.parallelism
と同じ定義になるので、全ての完了を待つ) - 失敗した場合のリトライ回数の定義(
.spec.backoffLimit
で定義。デフォルトは6)
このことから、ReplicaSetなどと違いJobによって作成されるPodは使い捨て前提のPodとなるため、バッチ処理などに適しているといえます。
Jobが完了しても、JobやJobによって作成されたPodは残り続けるため削除する場合は手動で削除するか、TTL Controllerを使用する必要があります。
完了したJobなどこれらの不要なリソースがある場合、パフォーマンスに影響がでるためTTL Controllerを使用し自動削除を設定することが推奨されています。
TTL Controller
Jobの.spec.ttlSecondsAfterFinished
で定義が行われ、TTL(Time To Liveの略でデータが破棄されまでの時間)の名の通り、Jobによって作成されたリソースの自動削除までの時間を設定できます。
TTL Contorollerを時刻のずれなく正しく実行するためにNodeにNTPが稼働している必要があります。
kuberntes v1.23ではJobでのみ使用できる機能で今後拡張されていくようです。
CronJob
名前の通りJobをクーロンするという、CronJob→Job→Podという親子関係になっています。
Kubernetes MasterというコントローラがCronJobを実行するため、これが障害などで作動していないとCronJobは実行されません。
Cronのスケジュール書式
cronの話ですが、定期実行する時間は次の通り指定します。
基本の書式は* * * * *
で記載し、アスタリスクの左から順に以下の意味を持ちます。
アスタリスクのままにしておくとその箇所の定義は全ての場合となります。
その他、カンマ区切りで複数指定、ハイフン区切りで範囲指定などがあります。
まとめ
色々な機能がありますが、根本はk8sはDockerコンテナを作成するためのプラットフォームということを押さえておけば、「色々な機能があるけどk8sでやりたいことって結局コンテナ(Pod)を作ることなんだな」というシンプルな理解ができます。
その機能をワークロードリソースといい、DeploymentやJobなどによってオーケストレーションを実現していることがわかりました。
参考
Discussion