Kubernetes Deployments: The Ultimate GuideーPart3

Kubernetesのデプロイメント :究極のガイド パート3

gavin.zhou
11 min readOct 31, 2019

今回の記事はKubernetesのデプロイメントに関しての記事です。少し長いので4つに分けて投稿します。第3回目はreadiness probesなどについてです。

Broken deployments and readiness probes

壊れたデプロイとreadiness probesについてです。

壊れたバージョンをロールアウトするとアプリケーション全体がダウン(一つのポッドが一回に)することもあります。Kubernetesは、古いポッドを1つずつ新しい(壊れた)バージョンに着実に置き換えていきます。

readiness probesを使用しない限り。

readiness probe は、コンテナの仕様に追加するテストです。 これはバイナリテストであり、「IT WORKS(機能する)」または「IT DOES N’T(機能しない)」とのみ表示され、定期的に実行されます。 (デフォルトでは、10秒ごと。)

Kubernetesではreadiness probesを実行する3つの方法を提供してくれています。

  1. コンテナの中でコマンドを実行する
  2. コンテナに対してHTTP(S)リクエストをする、もしくは
  3. コンテナに対してTCP ソケットを開ける

Kubernetesは、そのテストの結果を利用して、コンテナとそれが属するポッドがトラフィックを受信する準備ができているかどうかを確認します。 新しいバージョンをロールアウトすると、Kubernetesは新しいポッドが「準備完了」とマークするのを待ってから次のポッドに進みます。

readiness probesが失敗し続けるためにポッドが準備完了状態にならない場合、Kubernetesは次へうつりません。 デプロイメントがストップし、問題に対処するまで、アプリケーションは古いバージョンで実行され続けます。

readiness probesがない場合、コンテナは開始できる限り、準備完了と見なされます。 そのため、その機能を利用する場合は、readiness probesを必ず設定するようにしてください。

Rollbacks for quick recovery from bad deploys

いつでも、アップデートのローリングの間もしくは、そのあと、Kubernetesにこう言うことができます「ねえ、気が変わったんだけど。そのデプロイメントよりも前のバージョンに戻ってほしんだけど」 するとKubernetesはすぐに「古い」ものと「新しい」もののレプリカセットの役割を交換します。その観点から見れば、古いレプリカセットのサイズが増え(デプロイメントの基準的なサイズまで増加)し、もう一方のもののサイズは小さくなります。

一般的な話をすると、これは二つの「古い」レプリカセットと「新しい」レプリカセットに限られたものではありません。より詳しく見てみると、「最新」とみなされている1つのレプリカセットがあります。そして、それは自分たちが「ターゲット」としているレプリカセットです。それが、私たちが移ろうとしているものです。 Kubernetesが徐々にスケールアップするものです。 同時に、古いバージョンに対応する他のレプリカセットがいくつあってもかまいません。

例として、10のレプリカを超えるアプリケーションのバージョン1を走らせます。それからバージョン2をロールアウトします。いくつかの点において、バージョン1を走らせる7つのポッドとバージョン2を走らせる3つのポッドを持つことになります。バージョン2が完全にデプロイされるのを待つことなく、バージョン3をリリースすることに決め巻いた。(その理由は、最初の方に気づかなかった問題点を修正するからです)そして、バージョン3がデプロイされている間、結局バージョン1に戻ることに決めました。Kubernetesはそれに応じて、ほぼレプリカセット(アプリケーションのバージョン1,2,3に対応するもの)のサイズを調整することはありません。

MaxSurge and MaxUnavailable

Kubernetesは一度に1つのポッドを正確に更新しません。最初にお話ししたようにデプロイメントは「数個の余分なパラメーター」を持っています。そのパラメーターは MaxSurgeMaxUnavailableを含んでいます。それらはアップデートが実施されるペースを表示しています。

新しいバージョンをロールアウトする場合2つのストラテジーが思いつくと思います。アプリケーションの高可用性に対してすごく保守的になることもあるし、古いポッドをシャットダウンする前に新しいポッドをスタートすることにすることもあります。新しいポッドがアップされ、実装され、準備された後にのみ、古いポッドを停止することができます。

これはつまり、クラスター上で余分な利用可能なキャパシティーがあるということ示唆しているのです。しかし、クラスターがいっぱいになっているため、追加のポッドを実行する余裕がない場合や、新しいポッドを開始する前に古いポッドをシャットダウンする場合があります。

MaxSurgeはローリングアップデート中にどれだけ余分なポッドを走らせたいと思っているのかを表します。一方MaxUnavailableはローリングアップデート中にいくつのポッドを失うかを表しています。両方のパラメーターはデプロイメントにとっては明確なものです。(言い換えれば、それぞれのデプロイメントはそれぞれに異なるパラメーターを持つということです)両方のパラメーターはポッドの絶対値、またはデプロイメントのサイズのパーセンテージとして表示されます。 また、両方のパラメーターをゼロにすることもできます(同時にはできません)。

それでは、MaxSurge とMaxUnavailableの典型的な値をいくつか見ていきましょう。そしてそれが何を意味するか確認していきます。

MaxUnavailableを0に設定すると「新しいポッドが立ち上がってトラフィックを処理する準備ができるまで、古いポッドをシャットダウンしないでください」という意味になります。

MaxSurgeを100%に設定すると「すべての新しいポッドを今すぐスタートする」という意味で、クラスター上により多くのキャパシティーがあるということを表していて、できるだけ早くこうしたいと私たちは願っています。

両方のパラメーターのデフォルト値は25%です。つまり、サイズ100のデプロイメントをアップデートすると、25個の新しいポッドがすぐに作成され、25個の古いポッドがシャットダウンされます。 新しいポッドが起動するたびに(準備完了のマークが付けられるたびに)、別の古いポッドをシャットダウンできます。 古いポッドがシャットダウンを完了する(およびそのリソースが解放される)たびに、別の新しいポッドを作成できます。

Demo time!

それではデモの時間です。

実際にそれらのパラメーターが動いているのを見るのは簡単です。カスタムのYAMLを書いたり、readiness probesを設定したりのようなことをする必要はありません。

私たちは、デプロイメントに無効のイメージを使うように言うだけでいいのです。無効なイメージというのは例えば存在しないイメージなどのことを指します。コンテナは出てくることはありませんし、Kubernetesは無効なイメージを「準備」とマークすることは決してありません。

もしKubernetesクラスターを持っているのであれば( minikubeDocker Desktop のようなワンノードのクラスタ―でかまいません)異なるターミナルで何が起きているか確認するために、以下のようなコマンドを走らせることができます。

  • kubectl get pods -w
  • kubectl get replicasets -w
  • kubectl get deployments -w
  • kubectl get events -w

それから、以下のコマンドでデプロイメントを生成、スケール、アップデートします。

kubectl run deployment web --image=nginxkubectl scale deployment web --replicas=10kubectl set image deployment web nginx=that-image-does-not-exist

デプロイメントが停止しているのが分かります。しかし80%のアプリケーション容量が利用可能なのです。

kubectl rollout undo deployment webを走らせるとKubernetesは最初のバージョンに戻ります( nginxを走らせるバージョンです。

Understanding selectors and labels

先述の通り、「レプリカセットの役割は正しい仕様にあったNポッドが必ずあるということを確認すること」です。それはまさに起こっていることではありません。実際レプリカセットはポッドの仕様を参照することがありませんが、ラベルだけは確認します。

言い換えると、ポッドがnginx やredisなどを走らせているかどうかということは問題ではありません。問題なのは、正しいラベルをもっているかどうかです。(上の例でいえば、ラベルは run=web と pod-template-hash=xxxyyyzzzのように見えます)

レプリカセットのコンテナはセレクターです。セレクターというのは多くのポッドを「セレクトする(選択する:SQLにおける SELECTクエリと同じです)」の論理的な表現です。レプリカセットはポッドの数が正しいことを確認し、必要に応じてポッドを生成するか削除します。しかし、既存のポッドを変更することはありません。

あなたが考えているような場合においてですが、その答えは「はい」です。ラベルを伴ったポッドを手動で生成することは可能です。しかし、異なるイメージ(もしくは異なるセッティング)を走らせ、レプリカセットを誤魔化します。

最初、これは大きな潜在的な問題のように見えますが、実際には、たまたま「正しい」ラベル(もしくは味方によっては「悪い」ラベル。)を選ぶこともあります。ポッドの仕様にランダム関数以外のハッシュ関数が含まれていることが理由となっています。

Services as load balancers

ロードバランサーとしてのサービスについてです。

セレクターはまた「サービス」によって使用されます。これは、Kubernetesの内外のトラフィックのためのロードバランサーとして機能します。以下のコマンドを伴った web のデプロイメントのためのサービスを生成することが可能です。

kubectl expose deployment web --port=80

そのサービスはそれ自身のインターナルの(内部の)IPアドレス(ネームClusterIPを意味します)を持っていて、ポート80上のこのIPアドレスへの接続はこのデプロイメントのすべてのポッド全体を通してロードバランスされることになります。

実際、それらの接続はサービスのセレクターにマッチングするすべてのポッド全体を通してロードバランスされます。その場合、そのセレクターは run=webとなります。

デプロイメントを編集し、ローリングアップデートを呼び出すとき、新しいレプリカセットが生成されます。このレプリカセットがポットを生成し、そのポッドのラベルはrun=webを含んでいます。このようにそれらのポッドは自動的にコネクションを受け取ります。

これはロールアウトの間ずっとデプロイメントが再コンフィギュアしない、もしくはポッドをスタートさせるかストップさせるロードバランサーに知らせるこtもないということを意味します。ロードバランサーに関係するサービスのセレクターを通して自動的に起こります。

(probesとヘルスチェックがこれにどのように作用するのか疑問に思われた方方:ポッドは全てのコンテナがreadinessチェックに合格した場合にのみサービスの有効なエンドポイントとして追加されます。つまりポッドは実際に準備ができて初めてトラフィックの受信を開始します。

Orangesys.ioでは、kuberneteの運用、DevOps、監視のお手伝いをさせていただいています。ぜひ私たちにおまかせください。

--

--

No responses yet