Kubernetes : アプリケーションのオーケストレーションとデプロイメント管理

この「Get to Know Kubernetes」チュートリアルでは、**Kubernetes**アプリケーションのオーケストレーションと管理におけるデプロイメント管理の様々な側面とコンポーネントについて説明します。

#1）必要性
###背景
ここでは、[Kubernetes](https://www.alibabacloud.com/product/kubernetes?spm=a2c65.11461447.0.0.20865b3aCe8CGh)によるアプリケーションのオーケストレーションとマネジメントの背景について説明します。例えば、クラスター内の全てのPodを直接管理するために、下図のようにアプリケーションA、B、CのPodがクラスター内に点在しています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/1c18b0db-0fbc-48b3-1a94-1fb8b22ec572.png)



では、次の質問に答えて先に進んでください。

- クラスタ内で利用可能なPodの数を確保する方法は？言い換えれば、アプリケーションAの4つのPodでホストに障害が発生したり、ネットワーク障害が発生したりしたときに、利用可能なPodの数を確保する方法は？
- すべてのPodのイメージバージョンを更新する方法は？Podのバージョンを更新する必要がありますか？
- アップデート中にサービスの可用性を確保する方法は？
- アップデート中に問題が発生した場合、Podを以前のバージョンにロールバックする方法は？

###デプロイメントとリリースのためのデプロイメント管理コントローラー
このセクションでは、この記事の重要なトピックを紹介します。デプロイメントです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/2824b946-bd16-06ac-6cfa-a01908763f8a.png)


前述の図のように、アプリケーションA、B、Cはそれぞれ異なるDeploymentに割り当てられています。各Deploymentは同じアプリケーションのPodを管理しており、Podは同じレプリカを持っています。では、Deploymentは何をするのでしょうか。

1）Deploymentは想定されるPodの数を定義します。例えば、アプリケーションAに4つのPodが必要な場合、コントローラは想定通り4つのPodを維持します。Podにネットワーク障害やホスト障害が発生した場合、コントローラは新しいPodをスケールアップして、Podの数が予想される数と同じになるようにします。
2) コントローラは，Podのリリースモードを設定します。したがって、指定されたポリシーに従ってPodを更新します。更新中は、使用できないPodの数量範囲を設定します。
3) アップデート中に障害が発生した場合は、ワンクリックでロールバックを行い、コマンドの実行や行の修正だけで、DeploymentのすべてのPodを以前のバージョンに戻します。

#2) 使用例
###デプロイメントの構文
このセクションでは、簡単なケースを使って Deployment の操作方法を説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/af3e16e5-06c8-ad15-64b0-39ebe3b6ed04.png)


上図は、Deployment のシンプルな YAML ファイルを示しています。

`apiVersion: apps/v1`は、Deploymentがappsグループに属し、バージョンがv1であることを示しています。「metadata」は、これまでの記事で紹介したラベル、セレクタ、Podイメージなど、Deploymentのメタデータを示しています。

KubernetesのリソースであるDeploymentは、独自のメタデータ情報を持っています。ここで定義されているDeployment.nameは`Nginx.Deployment`、`Deployment.spec`には "replicas "というコアフィールドが必要で、予想されるPodの数を3つと定義しています。"selector "はPodのセレクタを示します。すべての新しいPodのラベルは、セレクタの `image.labels（app.nginx）`と一致しなければなりません。

前述のPodテンプレートには、2つの部分が含まれています。

- 1つは、`selector.matchLabels`にマッチするラベルを含む、予想されるPodのメタデータです。
- もう1つは`Pod.spec`です。テンプレートでは、`Pod.spec`はDeploymentがPodを作成する際に使用されます。ここでは、`container.nginx`が定義されており、イメージバージョンはNginx:1.7.9となっています。
以下の新しい概念を理解してください。

- レプリカは、予想されるPodの数、または Deployment での最終的なPodの数を示します。
- テンプレートは、Podに関連するテンプレートを示します。

###デプロイメントの状態を確認
デプロイメントの作成中に `kubectl get deployment` コマンドを実行すると、次の図のようにデプロイメントの全体的なステータスが表示されます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5e4f7cd2-8531-cd53-0481-91f30a62db97.png)


前述の図では、以下の情報が表示されています。

- DESIRED:予想されるPodの数で、3です。
- CURRENT：現在のPodの数。現在のPodの数で，3です。
- UP-TO-DATE：予想される最新バージョンのPodの数。
- AVAILABLE: 実行中のプロセスで利用可能なPodの数。実際には，「AVAILABLE」には，利用可能期間を超えたPodの数も含まれます。
- AGE:作成された Deployment の期間です。前述の図では、デプロイメントが 80 分間実行されています。

###Podの表示
次の図のように、Podを表示します。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/a26935fd-bbb8-456a-b0f2-2c74e79db586.png)


前述の図では、3つのPodが表示されています。

Pod名のうち、`nginx-deployment`はPodが属するDeploymentの名前を示し、`template-hash`は3つのPodが同じテンプレートから作成されているため、3つのPodで同じ内容になっています。

Pod名の最後の部分はランダムな文字列で、`kubectl get pod`コマンドを実行すると同じものが表示されます。PodのコントローラリソースであるownerReferencesは、PodのDeploymentではなくReplicaSetです。ReplicaSetの名前は、後述する`nginx-deployment`と`pod.template-hash`で構成されています。すべてのPodは、Deploymentテンプレートの特定のバージョンに対応するReplicaSetによって作成されます。

###イメージの更新
このセクションでは、指定された Deployment のすべてのPodのイメージバージョンを更新する方法を説明します。`kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1`コマンドを実行します。

- コマンドの中で、「kubectl」の後には必ず「set image」が付いており、このコマンドがイメージを設定するために実行されることを示しています。
- 次の "set image "は `deploy.v1.apps` で、操作対象のリソースの種類を示しています。この部分は固定で、"deployment "はリソース名を、"v1 "はリソースのバージョンを、"apps "はリソースグループを示します。`deployment.v1.apps`の代わりに "deployment "またはdeployment.appsを使用してください。例えば、`deployment.v1.apps`の代わりに "deployment "を使用した場合、デフォルトではv1バージョンのappsが使用されます。
- 3番目の部分は "nginx-deployment "で、更新するイメージを持つデプロイメントの名前を示します。名前の後に続く "nginx" はテンプレートを示しており、これはPodの `container.name` です。Podには複数のコンテナが含まれることがあり、ここで指定した `container.name` のうち Nginx は、更新するイメージのコンテナ名です。
- 最後の部分は nginx:1.9.1 で、コンテナの期待されるイメージのバージョンを示しています。このコマンドを実行すると、Deploymentの`template.spec`が`nginx.1.9.1`に更新されていることがわかります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/e8463ac9-c9cd-707e-6ab7-950e356ea437.png)


###Quick Rollback
リリース中に問題が発生した場合、Quick Rollbackを実行します。`kubectl rollout undo` コマンドを実行して、配置を前のバージョンにロールバックするか、`to-revision` をサフィックスとする `kubectl rollout undo` コマンドを実行して、配置を特定のバージョンにロールバックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/be93f59c-2471-d4e7-f221-b08967b31003.png)


###DeploymentStatus
このセクションでは、DeploymentStatusを紹介します。各リソースには `spec.Status` があります。DeploymentStatusには、下図のようにProcessing、Complete、Failedなどの変換ステータスが記述されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/fce2d9f8-c298-ee1f-59db-05103526fe18.png)


処理中とは、デプロイメントがスケールアップしてリリースされることを示します。処理状態の Deployment では、そのレプリカとPod レプリカがすべて利用可能で最新の状態になると、その Deployment は Complete 状態になることができます。Complete 状態の Deployment は、スケールアップすると Processing 状態になります。

処理中に何らかの問題が発生した場合、例えばイメージの取り出しや準備状況のプローブチェックが失敗した場合、その展開は「Failed」状態になります。Podの準備完了検査が失敗すると、Complete 状態の Deployment は Failed 状態になります。Failed 状態の Deployment は、すべてのレプリカが利用可能で最新の状態になったときにのみ Complete 状態になります。

#3) デモ
###デプロイメントの作成とステータス
Alibaba Cloudのサービスクラスタを接続します。このクラスターには、利用可能なノードが複数あります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/ca596b05-a8ea-01ad-db69-05eca582d3d4.png)


まず、Deploymentを作成します。「DESIRED」「CURRENT」「UP-TO-DATE」「AVAILABLE」の値は、すべて期待通りの値であることに注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/c12199cb-b4b7-dac6-8e8e-0594372098f1.png)


###デプロイメントの構成
図のように、「spec」には3つのレプリカがあり、「selector」と「template」で定義されている「labels」は`app:nginx`、「spec」の「image」は期待値`nginx: 1.7.9`、"status “の`available.replicas`、`readReplicas`、`updatedReplicas`の値がすべて3になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/e61b8017-9055-441a-997e-5d007c8752c6.png)


###Podのステータス
Podのステータスを表示することができます。

Podでは、ownerReferencesがReplicaSet、pod.spec.containerのイメージのバージョンが1.7.9となっています。Podの状態は「Running」で、「conditions.status」は「true」となっており、サービスが利用可能であることを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5c82e435-a2c9-4122-7f61-f940a94b075d.png)


###アップグレード
現在、最新バージョンのReplicaSetのみが利用可能です。ここで、デプロイメントをアップグレードしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/35d2a4eb-0ec9-3607-39b4-8ed37c565bf3.png)


`kubectl set image`コマンドには、「deployment」、`deployment.name`、コンテナ名、予想されるイメージのバージョン番号が続きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/a427051c-80a4-baae-186f-4b8e0eb94d97.png)


次の図に示すように、「Deployment」のテンプレート内のイメージのバージョンが1.9.1にアップグレードされています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/da594a20-2ea6-7305-3b35-7668227564c9.png)


ここで、`kubectl get pod`コマンドを実行して、ステータスを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/f03c129e-26f0-a419-805c-eccb54f7bda5.png)


3つのPodが最新版にアップグレードされ、各Pod名の`pod-template-hash`が更新されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/80bc2c5f-543f-ea86-7c6f-4e8727438a2e.png)


次の図に示すように、旧バージョンのReplicaSetのspec量とpod量はともに0で、新バージョンのpod量は3です。

別のアップデートが実施されたとします。`kubectl get pod`コマンドを実行します。なお、以前のバージョンの2つのPodはRunning状態、以前のバージョンのもう1つのPodはTermining状態、新しいバージョンの2つのPodのうち、1つはRunning状態、もう1つはContainerCreating状態になっています。

この場合、利用可能なPod（終了していないPod）の数は4つで、Deploymentに設定されている値3よりも多くなっています。これは、Deployment に MaxAvailable と MaxSurge の設定があり、リリース時にいくつかのポリシーが制限されているためです。これについては、アーキテクチャ設計のセクションで説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/c28a9411-1ad1-f764-3fb2-ccaf504b74dd.png)


###RevisionHistoryLimit
前述の図に示すように、最新バージョンのReplicaSetには3つのPodが含まれており、以前のバージョンのReplicaSetは2つあります。配置が継続的に更新されると、以前のバージョンのReplicaSetsの数が増え続けるのではないかと思うかもしれません。実は、デプロイメントにはこの問題を防ぐための仕組みが用意されています。配置の仕様では、RevisionHistoryLimit のデフォルト値は 10 で、保持される履歴バージョンの ReplicaSets の数を指定しています。これを 1 に変更できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/ff7ef9d8-3f98-365f-60f1-b9361ed5849f.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/337059b5-a67c-d582-cc55-c3a08109351b.png)


前述の図のように、ReplicaSetsは2つあります。つまり、現在のバージョンのReplicaSetに加えて、以前のバージョンのReplicaSetが1つだけ保持されます。

###ロールバック
ここでは、ロールバックの方法について説明します。`kubectl get replicaset`コマンドを実行します。以前のバージョンのReplicaSetsの数が0から2に増加し、新しいバージョンのReplicaSetsの数が3から1に減少し、ロールバックが開始されたことを示しています。しばらくすると、以前のバージョンのReplicaSetsの数が3になり、ロールバックが成功したことを示します。このとき、新バージョンのReplicaSetsの数は0になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/fec99f6d-7b8f-530d-0e09-20f45d7336c5.png)


`kubectl get pod`コマンドを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/c842d7ce-c7c2-b09e-c520-6879820f632d.png)


3つのPodのテンプレート・ハッシュが、以前のバージョンのハッシュに更新されました。しかし、この3つのPodは、以前のバージョンで作成されたものではなく、新しいPodです。つまり，ロールバック時に，以前の3つのPodを検索するのではなく，以前のバージョンの3つのPodが作成されたのです．

#4）アーキテクチャ設計
###管理モード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/f65ef013-5ccf-908d-6959-b3daa2a369d7.png)


Deploymentでは、異なるバージョンのReplicaSetsを管理し、それによってPodレプリカの数を管理します。各ReplicaSetは、Deploymentテンプレートのバージョンに対応しています。前述のとおり、テンプレートが変更されるたびにReplicaSetが生成されます。同じReplicaSetのPodは、同じバージョンになります。

前述の図に示すように、DeploymentがReplicaSetを作成し、ReplicaSetがPodを作成します。それらのownerReferencesは、コントローラリソースに対応しています。

###Deployment Controller
このセクションでは、コントローラの実装原理について説明します。

すべてのコントローラは、Informerからのイベントに対してハンドラを動作させ、これらのイベントを監視します。受信したDeploymentイベントとReplicaSetイベントは、キューに追加されます。キューからイベントを取得した後、Deploymentコントローラは、新しいリリースが必要かどうかを示す「Paused」をチェックします。Paused "が "true "に設定されている場合、Deploymentコントローラは数量を維持するだけで、新しいリリースはありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/8a1414bf-f9a5-87d1-0dce-7ccd064f4fb9.png)



Paused」が「true」（Yes）に設定されている場合、Deploymentコントローラはレプリカの同期のみを行います。つまり、デプロイメントコントローラはレプリカを対応するReplicaSetに同期させ、デプロイメントステータスを更新します。この場合、コントローラのReplicaSetは終了します。

Paused "が "false "に設定されている場合、Deploymentコントローラはロールアウトを実行する、つまり、作成モードまたはローリングモードでアップデートを実行します。アップデートは、実際にはReplicaSetの作成、更新、または削除によって行われます。

###ReplicaSet Controller

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/25e4132d-e4e5-2c8a-7fff-700f9618f1e0.png)


ReplicaSet が Deployment に割り当てられると、ReplicaSet コントローラは ReplicaSet や pod イベントなど、Informer からの特定のイベントを監視します。ReplicaSetコントローラは、キューからイベントを取得した後、レプリカの数のみを管理します。ReplicaSetコントローラは、レプリカの数がPodの数よりも多いと判断した場合は、Podをスケールアップします。ReplicaSetコントローラは，実際のPodの数が予想される数を超えていると判断した場合には，Podを削除します。

図のように、Deploymentコントローラはバージョンの管理など、より複雑なタスクを実行し、ReplicaSetは各バージョンの数量を維持します。

###スケールアップとスケールダウンのシミュレーション
このセクションでは、スケールアップ操作など、いくつかのシミュレーション操作について説明します。2 つのレプリカを持つ Deployment があり、それに対応する ReplicaSet には Pod1 と Pod2 があるとします。Deploymentのレプリカを変更すると、コントローラはレプリカを現在のバージョンのReplicaSetに同期します。ReplicaSetが2つのPodを見つけ、予想された3つのPodではなかった場合、ReplicaSetは3つ目のPodを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/0214bbac-2bcd-2a88-6b3d-e5cb05abcebf.png)


###リリースシミュレーション
ここでは、少し複雑なリリースのシミュレーション方法について説明します。例えば、現在のバージョンのDeploymentテンプレートをtemplate1とします。template1に対応するReplicaSetには、3つのPodが含まれています。Pod1、Pod2、Pod3です。

テンプレートのコンテナ内のイメージを変更すると、デプロイメントコントローラはtemplate2に対応するReplicaSetを作成します。ReplicaSetが作成されると、コントローラは2つのReplicaSetの数量を変更します。たとえば、ReplicaSet2のレプリカの予想数を徐々に増やし、ReplicaSet1のPodの数を徐々に減らしていきます。

最後に、新しいバージョンのPodをPod4、Pod5、Pod6とし、以前のバージョンのPodを削除する。これでリリース作業は完了です。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/072cd8e6-df66-99ae-84c5-0b9310aecf3c.png)


###ロールバックシミュレーション
ここでは、ロールバックシミュレーションについて説明します。前節のリリースシミュレーションの後、Pod4、Pod5、Pod6がリリースされました。現在のビジネス・バージョンに問題があることがわかったとします。この場合、ロールアウト・コマンドを実行するか、ロールバックを実行してテンプレートをtemplate1にロールバックします。

ロールバック後、DeploymentはReplicaSet1のPodの予想数を3つに変更し、ReplicaSet2のレプリカを徐々に減らして、以前のバージョンのPodが再び作成されるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/97b5e849-c133-2e5a-11bc-d49045a3de2c.png)


ロールバック後，初期バージョンの Pod1，Pod2，Pod3 に対応して，それぞれ Pod7，Pod8，Pod9 が作成される．これは、ロールバックが以前のPodを回収するのではなく、初期バージョンのテンプレートに従った新しいPodを作成することを意味しています。

###Spec フィールド
このセクションでは、デプロイメントのいくつかのフィールドについて説明します。以下に、Deployment の spec フィールドについて説明します。

- MinReadySeconds：Deployment は、Podの準備ができたときに利用可能であると判断します。ただし、MinReadySeconds をたとえば 30 秒に設定すると、Podが準備完了状態になってから 30 秒以上経過したときに、Deployment はPodが利用可能であると判断します。利用可能なPodは、準備ができているPodでなければなりませんが、準備ができているPodは必ずしも利用可能ではありません。ready pod は MinReadySeconds で指定された時間後にのみ利用可能になります。

- RevisionHistoryLimit：保持可能な古いReplicaSetsの数です。デフォルト値は10です。このパラメータを1または2に設定します。ロールバックの可能性が高い場合は、10以上の値を設定してください。
- Paused:デプロイメントが一時停止し、新しいリリースを行わずに数量のみを維持することを示すラベルです。このフィールドは、デバッグシナリオで使用できます。
- ProgressDeadlineSeconds:配置がスケーリングまたはリリースの状態にあるとき、その状態は処理中です。処理状態には、タイムアウト間隔が設定されています。タイムアウト間隔後も状態がProcessingのままの場合、コントローラはPodがFailed状態になったと見なします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/9bea9f88-6c2f-76ab-f093-49b1c9e582f7.png)


###アップグレード ポリシー フィールド
デプロイメントには、RollingUpdate、MaxUnavailable、およびMaxSurgeの2つのポリシーがあります。これらの2つのフィールドについても、次の図で説明します。

- MaxUnavailable:アップデート中に利用できないPodの最大数です。
- MaxSurge:アップデート中に予定されているレプリカの数を超えてスケジュールされるPodの最大数です。

前述のとおり、ReplicaSetsが3つあるDeploymentでは、新しいバージョンのReplicaSetに2つのレプリカ、以前のバージョンのReplicaSetsに2つのレプリカがあり、予想される数である3つを超えてしまうことがあります。これは、MaxUnavailableおよびMaxSurgeのデフォルト値が25％であるためで、リリース中に、元のレプリカの25％までの追加の使用不可のレプリカと、元のレプリカの25％以上の追加の使用可能なレプリカが存在する可能性があることを示しています。最大レプリカ数は、元のレプリカ数の125％です。

実際の要件に基づいて2つのフィールドを設定します。たとえば、十分なリソースがあり、リリース中に高い可用性が必要な場合は、MaxUnavailableを小さい値に設定し、MaxSurgeを大きい値に設定します。ただし、MaxSurgeとMaxUnavailableを同時に0にすることはできません。

これは、MaxSurgeを0に設定した場合、新しいPodを追加する前にPodを削除する必要があるからです。そうしないと、Podの合計数が予定数を超えてしまいます。両方のフィールドが0に設定されている場合、MaxSurgeはPodが作成されないようにする一方で、MaxUnavailableはReplicaSetに利用可能なPodがあることを確認できないため、問題が発生します。したがって、MaxSurgeとMaxUnavailableを同時に0に設定することはできません。実際の要件に基づいて、各フィールドを適切な値に設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/bc28eadd-5159-48bc-afa6-372b91ab2f4d.png)


#まとめ
このセクションでは、記事を締めくくります。

- DeploymentはKubernetesの一般的なワークロードで、複数のバージョンのPodの展開と管理をサポートします。
- Deploymentは、各バージョンのテンプレート用にReplicaSetを作成し、ReplicaSetが一定数のPodのレプリカを管理します。Deploymentは、各バージョンのReplicaSetsに含まれるPodの数を指定するだけで良いです。
- つまり、DeploymentはReplicaSetsの最終的なレプリカの数を調整して、異なるバージョンのPodをアップグレードしたりロールバックしたりします。

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

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