Kubernetesアプリケーションのオーケストレーションと管理：ジョブとデーモンセット

この記事では、アプリケーションのオーケストレーションと管理におけるジョブとデーモンセットの概念と基本操作について説明します。

#1) ジョブ内容
###条件
**ジョブの背景**
まず、なぜジョブが必要なのかを説明します。ポッドとは、[Kubernetes](https://www.alibabacloud.com/product/kubernetes?spm=a2c65.11461447.0.0.50275607Z68WEe)における最小のスケジューリング単位です。ポッドを使って任意のタスクを実行することができます。この場合、以下のような疑問があるのではないでしょうか。

- ポッド内のプロセスが正しく終了するようにするには？
- プロセスの実行に失敗した後、リトライが確実に行われるようにするには？
- 相互依存性のある複数のタスクを管理するには？
- タスクを並行して実行し、タスクのキューサイズを管理するには？

#ジョブ - タスク管理のためのコントローラ
Kubernetesのジョブには以下のような機能があります。

- ジョブを使用して、1つまたは複数のポッドを作成し、その実行または終了を監視する。
- ポッドの状態に基づいて、ジョブのリセット方法とリトライ回数を設定する。
- ジョブを使用して、タスクの依存関係に基づいて、前のタスクが終了した後にのみタスクが実行されるようにする。
- また、ジョブを使用してタスクの並列性を制御し、並列性に基づいて並列操作の数と操作中に完了するポッドの総数を制御する。

#例
次の例は、ジョブの動作を示しています。

###ジョブの構文

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/f7309c7b-71fe-da57-0588-fc317904f506.png)


前述の図は、YAML形式の最も単純なジョブを示しています。このジョブは、実際にはジョブコントローラの一種です。メタデータのnameフィールドはジョブ名を指定し、spec.templateフィールドはポッドの仕様を示しています。

ここでの内容は、さらに2つの項目がある以外は同じです。

- 最初の項目はrestartPolicy：ジョブでは、Never、OnFailure、Alwaysのリトライポリシーを設定します。Neverポリシーは必要に応じてジョブを再実行するために、OnFailureポリシーは失敗時にジョブを再実行するために、Alwaysポリシーはどんな条件でもジョブを再実行するために使用します。
- また、ジョブの再試行回数を制御するためには、backoffLimitパラメータが必要です。
そのため、ジョブのrestartPolicyとbackoffLimitパラメータに注目してください。

###ジョブの状態


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/b3bef981-043e-a9bc-770b-f7b97a3f063c.png)


ジョブを作成したら、`kubectl get jobs`コマンドを実行して、ジョブの状態を確認します。コマンドの出力には、NAME（ジョブ名）、COMPLETIONS（完了したポッド）、DURATION（実行期間）、AGEが含まれています。

- AGEは、現在の時刻からポッドの作成時刻を差し引いて得られます。このパラメータは、ポッドが作成されてからの経過時間を指定します。
- DURATIONは、ジョブのビジネスが実行されている時間を示します。このパラメータは、パフォーマンスの最適化に役立ちます。
- COMPLETIONSは、ジョブ内のポッドの総数と、完了したポッドの数を示します。

#ポッドの表示
ポッドに基づいてジョブが実行されます。先ほど開始したジョブでは、piという名前のポッドを作成し、円周率を計算しています。ポッドの名前は、`${job-name}-${random-suffix}`という形式で付けられています。次の図は，YAML形式のポッドを示しています．


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5368bdb4-89d9-0f0b-6445-cef5e2f92932.png)


一般的なポッドとは異なり、このポッドには、ポッドを管理する上位層のコントローラを宣言するownerReferencesが含まれています。図のように、ownerReferencesパラメータは、ポッドが前のジョブであるbatch/v1によって管理されていることを示しています。 次に、ポッドのコントローラだけでなく、ジョブに属するポッドも確認します。

#ジョブでの並列実行
ジョブを素早く実行するために、n個のポッドを並行して実行したい場合があります。一方で、ノードが限られているため、あまり多くのポッドを並列実行したくない場合もあります。パイプラインの概念を念頭に置いて、ジョブは最大の並列性をコントロールするのに役立ちます。

これは、completionsパラメータとparallelismパラメータに基づいて実装されます。

- completionsパラメータでは、ポッドキューの実行回数を指定します。これは、ジョブの実行可能な総回数と考えてください。たとえば，このパラメータが8に設定されている場合，ジョブを8回実行することができます．
- parallelismパラメータでは，並列するポッドの数を指定します。並列するポッドの数は、パイプラインやバッファのバッファキューのサイズを示します。このパラメータが2に設定されていると仮定すると、ジョブを8回実行しなければならず、毎回2つのポッドを並列に配置すると、合計4つの実行バッチが発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/502b1cc0-c80b-4d07-43e3-3134f9bb0036.png)


前述の図は、ジョブを実行したときの効果を示しています。この図では、ジョブ名、作成された8つのポッド、ジョブ内のビジネスの実行時間（2分23秒）が表示されています。

さらに、8つのポッドが、それぞれのAGE値でCompleted状態になっているのがわかります。AGE値は、下から順に、73s、40s、110s、2m26sです。各グループには，同じ継続時間のポッドが2つあります。持続時間が40秒のポッドは，最後に作成され，持続時間が2m26秒のポッドは，最初に作成されたものです。つまり，2つのポッドが同時に作成され，並行して実行され，完了したことになります。

例えば，parallelismパラメータを使用して，ジョブ内で並行して実行されるポッドの数を制御し，そこからパイプラインやバッファのバッファキューサイズの関数を見ることができます。



#CronJob 構文

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/33f4accd-482f-2fce-ffa0-ac1d4c4c34a0.png)


このセクションでは、CronJobまたはスケジュールされたジョブと呼ばれる別のタイプのジョブを紹介します。CronJobは、スケジューリングをサポートすることを除いて、一般的なジョブと非常によく似ています。例えば、CronJobは指定した時間に実行されるかもしれません。CronJobはn分または1時間ごとに実行されるので、スケジュールジョブとも呼ばれます。

一般的なジョブと比較して、CronJobはより多くのフィールドを持っています。

- schedule: 時間形式を指定します。これはLinuxのcrontimeと同じです。例えば、*/1は1分ごとに実行されることを示し、ジョブは大まかな時間を表示した後、"Hello from the kubernetes cluster. "という文章を出力する必要があります。
- startingDeadlineSeconds：ジョブが開始されるまでの待ち時間を指定します。長時間実行しているにもかかわらず、ジョブが開始されないことがあります。このような場合、CronJobはジョブを停止します。

- concurrencyPolicy：並列実行を許可するかどうかを示します。たとえば、1分ごとにジョブを実行したいが、ジョブが正常に完了するには2分かかるとします。この場合、次のジョブを実行する時間になってもジョブが完了しません。concurrencyPolicy が true に設定されている場合、最後のジョブが完了したかどうかに関わらず、ジョブが実行されます。

- concurrencyPolicyがfalseに設定されている場合、最後のジョブが完了するまでジョブは実行されません。

- JobsHistoryLimit: CronJobの各実行後に保持される、実行履歴や視聴時間などの最後のジョブの履歴記録を指定します。一般的には、クラスターの数に応じて、デフォルト値を10または100に設定します。

#デモ
###ジョブオーケストレーションファイル
このセクションでは、ジョブの使用方法について説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/ba9de159-6b68-7bdc-5a93-153f62eb40df.png)


###ジョブの作成と実行検証
`job.yaml`ジョブは、円周率を計算するだけの簡単なジョブです。`kubectl creat-f job.yaml`コマンドを実行して、ジョブを投入します。`kubectl get jobs`コマンドを実行することで、ジョブが実行されていることが確認できます。`kubectl get pods`コマンドを実行すると、podの実行が完了していることがわかります。続いて、ジョブとポッドのログを確認します。次の図は、piを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/f25159b8-3c97-36df-d9d2-0e685eaa0944.png)


###並列ジョブのオーケストレーションファイル
次の図は、別の例を示しています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/115aa9c8-20ee-9c3b-2edb-5e4c1949293a.png)

###並列ジョブの作成と検証の実行
前のステップでパラレル・ジョブを作成した後、別のパラレル・ジョブを見ていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/ae64a3f2-3bc9-c2c4-f98b-d81dad54c5c1.png)


2つのポッドが約30秒間稼働しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5b6375c6-e7e9-998d-c27f-47e74751772f.png)

30秒後、別の2つのポッドが動き出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/a3c66cd1-3a78-8613-730c-99194fc1c35a.png)

最初の2つのポッドの実行が完了し，残りの2つのポッドが実行されます。つまり，約40秒の間隔で2つのポッドが並行して実行され，合計4バッチの実行が行われ，合計8つのポッドが実行されることになります。すべてのポッドの実行が終了すると，並列実行のためのバッファキュー機能が実装されます。

一定時間が経過すると，2つ目のバッチが完了し，3つ目のバッチが開始されることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/84bd2234-89ff-fcb4-3f95-6ed7bcec0bd7.png)

###CronJobオーケストレーションファイル
3つ目の例は、CronJobの実行についてです。CronJobは1分ごとにジョブを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/429ca86e-2fed-e535-8147-d31e643d2312.png)

###CronJobの作成と実行検証
`kubectl get cronjobs`コマンドを実行すると、CronJobが利用できることがわかります。CronJobは1分ごとにジョブを実行するので、少し待ってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/ef071dfe-0592-4feb-3b4b-20f2463887b2.png)


また、最後のジョブの実行時間は2分12秒で、完了の進捗状況は7/8または6/8であることにも注意してください。完成度が7/8または8/8に近づくと、最新のジョブが完了します。この場合、2つのジョブが同時に実行されていることになります。2つのジョブを並行して実行することで、特定の大規模なワークフローやワークタスクの実行が容易になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/6b886585-351e-42b0-91e1-854a6d845060.png)


前述の図では、CronJobであるhello-1559206860のジョブをご覧ください。1分後に、ジョブが自動的に作成されます。もしCronJobが終了しなければ、1分ごとにそのようなジョブを作成します。

CronJobは、特定のクリーンアップタスクやスケジュールされたタスクを実行するために使用されます。例えば、CronJobはJenkinsの作成のようなタスクを効果的に実行します。

#アーキテクチャ
###ジョブ管理モード


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/d95e3f09-3c3b-8fe9-a029-483e2c207ce7.png)

ここでは、ジョブアーキテクチャの設計について説明します。ジョブコントローラは、関連するポッドを作成し、ジョブのステータスを追跡し、更新された構成に従ってポッドの作成を再試行または継続します。各ポッドには独自のラベルがあります。ジョブコントローラは、対応するポッドを追跡するためにラベルを追加し、ポッドを並列または連続して作成します。

###ジョブコントローラ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/8938069f-73bc-824e-3554-fd29888da01f.png)

前述の図は、ジョブコントローラのワークフローを示しています。すべてのジョブは、APIサーバーを監視するコントローラを構成します。ジョブのYAMLファイルを送信するたびに、ジョブコントローラーはAPIサーバーを介してファイルをetcdに転送します。次に、ジョブコントローラは、いくつかのハンドラを登録します。ハンドラは、追加、更新、削除などの操作のリクエストを、メモリレベルのメッセージキューを介してジョブコントローラに送信します。

ジョブコントローラは，ポッドが動作しているかどうかをチェックします。もし動作していなければ，ポッドを作成するためにスケールアップします。「はい」または実行中のポッドの数がしきい値を超えた場合，ジョブコントローラはスケールダウンしてポッドを削減します。ポッドが変更されると、ジョブコントローラはそのステータスを適時に更新します。

また，ジョブコントローラは，ジョブが並列か直列かをチェックし，指定された並列性または直列性に基づいてポッドの数を決定します。最後に、ジョブコントローラーは、ジョブの全体的なステータスをAPIサーバーに更新します。そして、ワークフロー全体の最終的な効果を確認することができます。



#2) デーモンセット
###条件
**デーモンセットの背景**
ここでは、もう一つのコントローラであるデーモンセットを紹介します。デーモンセットが利用できない場合は、次のような疑問があるかもしれません。

- クラスタ内のすべてのノードに同じポッドを実行させたい場合はどうすればよいか？
- クラスタに追加されたノードをすぐに感知して、何かを初期化するためにポッドをデプロイしたい場合はどうすればいいのか？
- ノードがクラスタから退出したときに、対応するポッドを削除したい場合はどうすればいいか？
- ポッドが異常に動作しているノードを監視して報告するには、どのコントローラを使用する必要があるか？


**デーモンセット - デーモンプロセスコントローラ**
デーモンセットは、Kubernetesが提供するデフォルトのコントローラで、次のような目的を果たすことができるデーモンプロセスコントローラです。

- クラスタ内のすべてのノードが同じポッドのセットを実行するようにする。
- 新しいノードが、ノードのステータスに基づいてポッドを自動的に作成するようにする。
- ノードがクラスタから削除されたときに、対応するポッドを削除する。
- 各ポッドの状態を追跡し、異常またはクラッシュしたポッドを回復する。

#例
###デーモンセット 構文
次の図は、デーモンセットの構文例です。`DaemonSet.yaml`ファイルには、`job.yaml`ファイルよりも多くの項目が含まれています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/0c2278e7-21a8-5cd5-0abb-12809591c3fb.png)

まず、デーモンセットという種類が紹介されています。このYAMLファイルは、デプロイメントコントローラーについての知識があれば、簡単に理解できます。たとえば、この場合、対応するポッドを管理するためにmatchLabelsが使用されます。デーモンセットコントローラは、ポッドのラベルがデーモンセットコントローラのラベルと一致する場合にのみ、ラベルセレクタに基づいて特定のポッドを見つけます。spec.containerフィールドの内容は、`job.yaml`ファイルの内容と同じです。

ここでは、fluentdを例にしています。デーモンセットは以下のようなシーンでよく使われます。

- GlusterFSやCephでストレージを実装する場合：GlusterFSやCephにストレージを実装するためには、各ノードでエージェントのようなプロセスを実行する必要がありますが、これをデーモンセットで実装します。
- logstashやfluentdにログを集めるため：各ノードがエージェントを実行することで、ノードの状態を容易に取得し、各ノードの情報をタイムリーに報告する必要があります。
- デーモンセットは、各ノードがデータを監視し、Prometheusなどの同じプロセスを実行できるようにします。

**DaemonSetのステータスを見る**


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/b1b851fa-4446-3f3c-a39f-8fcbd8a01b21.png)


デーモンセットを作成した後、`kubectl get ds`コマンドを実行します。dsはデーモンセットの略です。コマンド出力の値は、DESIRED、CURRENT、READYなど、デプロイ時の値とよく似ています。この場合、READYの状態にあるのはポッドだけです。したがって、ポッドのみが作成されます。

関係するパラメータには、「DESIRED」、「CURRENT」、「READY」、「UP-TO-DATE」、「AVAILABLE」、「NODE SELECTOR」があります。このうち、NODE SELECTORはデーモンセットで非常に便利です。一部のノードだけにポッドを実行させたい場合は、これらのノードにラベルを追加して、これらのノードでのみデーモンセットが実行されるようにします。たとえば、マスターノードやワーカーノードにのみ一部のポッドを実行させたい場合は、NODE SELECTORを使ってノードにラベルを追加します。

**デーモンセットの更新**


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/6a5243e8-a7f7-faf1-9bc5-e824799daf33.png)

デーモンセットは、デプロイメントと同様に、RollingUpdateとOnDeleteという2つのアップデートポリシーを持っています。

- RollingUpdateは、1つずつ更新することを意味します。このポリシーを実行すると、最初のポッドが更新され、古いポッドが削除されます。ヘルスチェックが完了すると、2つ目のポッドが更新される。これにより、業務を中断することなくスムーズなアップデートが可能になります。
- OnDeleteも便利なアップデートポリシーです。ただし、これを使用している間は、テンプレートが更新された後にポッドを手動で更新します。ポッドは、ノードから削除されるまで再作成されません。これは、手動制御の要件をよりよく満たしています。

#デモ
###デーモンセットのオーケストレーション
例えば、デーモンセットのいくつかのイメージを変更した場合、デーモンセットのステータスに応じて1つずつ更新されます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/8cf4384d-a446-8e0f-efe9-cd0e7b531255.png)

上図はデーモンセットのYAMLファイルですが、先ほどの例のファイルよりも項目数が多くなっています。

#デーモンセットの作成と動作確認
デーモンセットを作成し、その状態を確認します。次の図は、デーモンセットが準備状態にあることを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/66a5e2ee-b65d-e1e4-c402-0c0e3e54ba6a.png)

図に示すように、4つのノードが存在し、それぞれがポッドを実行しているため、4つのポッドが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/6faa2727-785e-731e-17c1-1c89024598d9.png)

#デーモンセットのアップデート
`kubectl apply -f`コマンドを実行してデーモンセットをアップデートします。デーモンセットがアップデートされたら、その状態を確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/365fdc6a-1ffa-6530-2c07-ea6b418323fd.png)

前述の図のように、デーモンセットはデフォルトでRollingUpdateモードを使用しています。アップデートが始まる前は「0 out of 4 new pods have been updated」と表示されています。現在は，「4つの新しいポッドのうち1つが更新されました」と表示されます。最初のポッドが更新された後、2番目のポッドが続き、3番目、4番目と、まさにRollingUpdateモードの実装となっています。RollingUpdateモードでは、自動更新が実装されています。これにより、現場でのリリース作業などが容易になります。

なお、RollingUpdateモードでのデーモンセットの更新が成功したことを示すのは、前出の図のように末尾の情報です。

#アーキテクチャ
###デーモンセット管理モード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/7a731312-b730-eefe-4909-dd9687ec612a.png)


ここでは、デーモンセットのアーキテクチャ設計について説明します。デーモンセットは、ポッドを持つコントローラでもあります。ジョブコントローラと同様に、デーモンセットコントローラは、APIサーバのステータスを監視し、タイムリーにポッドを追加します。両者の唯一の違いは、デーモンセットコントローラがノードの状態を監視し、新しいノードにポッドを作成し、設定されたアフィニティまたはラベルに基づいて対応するノードを選択することです。

###デーモンセットコントローラ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/d4df9cbb-05a9-54fc-686e-da53d476d551.png)


ここでは、デーモンセットコントローラについて詳しく説明します。ジョブコントローラと同様に、デーモンセットコントローラはAPIサーバのステータスを監視します。両者の唯一の違いは、デーモンセットコントローラが、APIサーバを通じてetcdに転送されるノードステータスを監視する必要があることです。

ノードの状態が変化すると、メモリレベルのメッセージキューを通じてデーモンセットコントローラにメッセージが送られ、デーモンセットコントローラは各ノードにポッドが含まれているかどうかをチェックします。Yesの場合、デーモンセットコントローラはバージョンを比較し、RollingUpdateモードでポッドをアップデートするかどうかを決定します。いいえの場合、デーモンセットコントローラはポッドを再作成します。OnDeleteモードでは、デーモンセットコントローラはポッドもチェックし、対応するポッドをアップデートするか作成するかを決定します。

更新が完了すると、デーモンセットのステータスがAPIサーバーに更新されます。

#概要
この記事では、ジョブとCronJobの概念を説明し、2つの例を使ってジョブとCronJobの使用方法を紹介し、ジョブとCronJobのすべての機能ラベルを実演します。さらに、デプロイメントコントローラとの比較を通じて、デーモンセットコントローラのワークフローと関連する操作についても説明しています。また、デーモンセットのRollingUpdateモードについても紹介しています。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/getting-started-with-kubernetes-%7C-application-orchestration-and-management-jobs-and-daemonset_596062)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*