Kubernetes展開の解剖
16607 ワード
このポストは、HerokuEngineering Blog .
Kubernetes は、Googleで始まったコンテナのオーケストレーションシステムであり、現在はCloud Native Computing Foundation . このポストでは、私は特にいくつかのKubernetes内部を解剖するつもりです.Deployments そして、どのように徐々に新しいコンテナのロールアウト処理されます.
これは、Kubernetesドキュメントが展開を説明する方法です.
エーPod クラスタ内で開始できる1つ以上のコンテナのグループです.手動で開始されたポッドは、それがクラッシュした場合、自動的に再起動されませんが、しかし、非常に便利になることはありません.エーReplicaSet pod指定が常に設定された複製数で実行されることを保証します.彼らはいくつかのインスタンスを起動することを許可し、それらのいくつかがクラッシュした場合、自動的にそれらを再起動します.展開はレプリカの上に座る.彼らはシームレスにアプリケーションの新しいバージョンをローリングを許可します.
基本的なアプリケーションでのローリング展開の例です.
私たちがこのビデオで見ることができるものは、一度に1本のポッドを巻き出している10のポッド展開です.更新が開始されると、展開は新しいポッドを起動し、そのpodがリクエストに応答するまで待機します.それが起こるとき、それは1つのpodを終えて、新しいものを起動します.すべての古いポッドが停止されるまで、これは続行され、我々は新しい展開を実行している10の新しいものを持っている.
それがカバーの下で扱われる方法を見ましょう.
Kubernetesはトリガーベースの環境です.展開が作成されるか、更新されるとき、それは新しい状態ですetcd . しかし、新しいオブジェクトのいくつかのアクションを実行するコントローラがなければ、何も起こらないでしょう.
クラスタ上の適切な認証アクセスを持つ誰でも、いくつかのトリガーを聞くことができますし、それらのアクションを実行します.次の例を取り上げましょう
展開コントローラに戻ります.それがinitialized , いくつかのinformersを設定します. 展開作成 展開更新 展開削除 レプリカ作成 レプリカの更新 レプリカの削除 ポッド削除 これらのすべてのトリガは徐々にロールアウトの全体処理を可能にします.
前述のトリガーのいずれかについては、展開コントローラはDeployment sync . このメソッドは展開ステータスをチェックし、それに基づいて必要なアクションを実行します.
新しい展開の例を見ましょう.
コントローラは、作成トリガを受け取り、同期を実行する.すべてのチェックを実行した後、それはDeployment strategy とトリガします.私たちのケースでは、私たちは転がりアップデートに興味を持っています.
The
この時点で、少なくとも2つのレプリカがあります.それらのうちの1つは、我々がちょうど作成したものです.もう一つは(私たちがいくつかの同時のロールアウトを持っているならば、より多くのことがありえます).次に、スケールup and down それに応じて複製の両方.
To scale up 新しいレプリカは、どのように多くのレプリカは、展開の期待を見て起動します.我々が十分にスケールしたならば、我々はちょうどそこで止まります.我々がスケーリングを保つ必要があるならば、我々はチェックしますmax surge value そして、それを実行しているポッドの数と比較してください.あまりにも多くの実行している場合、それはスケールアップされませんし、いくつかの古いポッドが終了したまで待機します.さもなければ、新しいポッドの必要な数を起動します.
To scale down , 私たちはどのように多くの合計のポッドを実行しているmaximum available Pods 我々は、その後、完全にブートしたポッドを減算します.それに基づいて、我々はどのように多くのポッドを終了する必要がありますし、ランダムに終了することができます知っている.
この時点でコントローラは現在のトリガを終了した.しかし、展開自体は終わっていません.
新しい展開は新しいポッドを起動するので、新しいトリガーを受け取ります.具体的には、ポッドが上下になると、レプリカは更新トリガを送信します.レプリケートの更新を聞いて、我々はブートまたは終了を終了したポッドを探すことができます.
それが起こるとき、我々は同期の上で同期ダンスをします.そして、構成に基づいて起動するシャットダウンと他のものにポッドを探して、それから新しい最新版を待ちます.
すべての展開が常に正しく実行されていることを確認するための方法として、ReplicSet削除トリガを使用します.レプリカが削除され、展開が予期しない場合は、再度同期を実行する必要があります.
これは、(ダウンタイムを使用して)アプリをすばやく再起動する場合は、配置のレプリカを安全に削除することができます.新しいものはすぐに作成されます.
展開を許可する
しかし、我々は、各クラッシュループ再試行のためのポッド削除の更新のいずれかを受信します.ここで同期することにより、我々は、それが最後の更新以来、どのくらいの期間を確認することができますし、確実にしばらくの間失敗したとして展開をマークします.
展開を考えるならcomplete , 我々clean things
up .
クリーンアップでは、あまりに古いになったすべてのレプリカを削除します.壊れた展開をロールバックすることができるように、古いレプリケート(設定された任意のpodなしで)を設定します.
あなたはrollback a deployment と
Kubernetesは一般的に複雑なツールとして見られますが、彼らがどのように働くかを理解するためにその部分を解剖することは難しくありません.また、それと同じくらい一般的であることは良いです、システムを非常にモジュラーにします.
たとえば、このポストで見たように、展開トリガーを聞いて、自分のロジックを実装するのはとても簡単です.または、完全に自分のコントローラーで再実装する(これはおそらく悪い考えでしょう).各々のコントローラが定期的にそれが所有するオブジェクトの最新版をチェックする必要がないので、このトリガーベースのシステムもものをより簡単にします.それは適切なトリガーを聞いて、適切なアクションを実行する必要があります.
Kubernetes は、Googleで始まったコンテナのオーケストレーションシステムであり、現在はCloud Native Computing Foundation . このポストでは、私は特にいくつかのKubernetes内部を解剖するつもりです.Deployments そして、どのように徐々に新しいコンテナのロールアウト処理されます.
展開とは
これは、Kubernetesドキュメントが展開を説明する方法です.
A Deployment controller provides declarative updates for Pods and ReplicaSets.
エーPod クラスタ内で開始できる1つ以上のコンテナのグループです.手動で開始されたポッドは、それがクラッシュした場合、自動的に再起動されませんが、しかし、非常に便利になることはありません.エーReplicaSet pod指定が常に設定された複製数で実行されることを保証します.彼らはいくつかのインスタンスを起動することを許可し、それらのいくつかがクラッシュした場合、自動的にそれらを再起動します.展開はレプリカの上に座る.彼らはシームレスにアプリケーションの新しいバージョンをローリングを許可します.
基本的なアプリケーションでのローリング展開の例です.
私たちがこのビデオで見ることができるものは、一度に1本のポッドを巻き出している10のポッド展開です.更新が開始されると、展開は新しいポッドを起動し、そのpodがリクエストに応答するまで待機します.それが起こるとき、それは1つのpodを終えて、新しいものを起動します.すべての古いポッドが停止されるまで、これは続行され、我々は新しい展開を実行している10の新しいものを持っている.
それがカバーの下で扱われる方法を見ましょう.
トリガーベースシステム
Kubernetesはトリガーベースの環境です.展開が作成されるか、更新されるとき、それは新しい状態ですetcd . しかし、新しいオブジェクトのいくつかのアクションを実行するコントローラがなければ、何も起こらないでしょう.
クラスタ上の適切な認証アクセスを持つ誰でも、いくつかのトリガーを聞くことができますし、それらのアクションを実行します.次の例を取り上げましょう
package main
import (
"log"
"os"
"path/filepath"
"reflect"
"time"
"k8s.io/api/apps/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// doneCh will be used by the informer to allow a clean shutdown
// If the channel is closed, it communicates the informer that it needs to shutdown
doneCh := make(chan struct{})
// Authenticate against the cluster
client, err := getClient()
if err != nil {
log.Fatal(err)
}
// Setup the informer that will start watching for deployment triggers
informer := cache.NewSharedIndexInformer(&cache.ListWatch{
// This method will be used by the informer to retrieve the existing list of objects
// It is used during initialization to get the current state of things
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return client.AppsV1beta1().Deployments("default").List(options)
},
// This method is used to watch on the triggers we wish to receive
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return client.AppsV1beta1().Deployments("default").Watch(options)
},
}, &v1beta1.Deployment{}, time.Second*30, cache.Indexers{}) // We only want `Deployments`, resynced every 30 seconds with the most basic indexer
// Setup the trigger handlers that will receive triggerss
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
// This method is executed when a new deployment is created
AddFunc: func(deployment interface{}) {
log.Printf("Deployment created: %s", deployment.(*v1beta1.Deployment).ObjectMeta.Name)
},
// This method is executed when an existing deployment is updated
UpdateFunc: func(old, cur interface{}) {
if !reflect.DeepEqual(old, cur) {
log.Printf("Deployment updated: %s", cur.(*v1beta1.Deployment).ObjectMeta.Name)
}
},
})
// Start the informer, until `doneCh` is closed
informer.Run(doneCh)
}
// Create a client so we're allowed to perform requests
// Because of the use of `os.Getenv("HOME")`, this only works on unix environments
func getClient() (*kubernetes.Clientset, error) {
config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config"))
if err != nil {
return nil, err
}
return kubernetes.NewForConfig(config)
}
このコードサンプルでコメントに従った場合は、作成して配備トリガーを更新し、それらをログオンしますstdout
.展開コントローラに戻ります.それがinitialized , いくつかのinformersを設定します.
圧延
前述のトリガーのいずれかについては、展開コントローラはDeployment sync . このメソッドは展開ステータスをチェックし、それに基づいて必要なアクションを実行します.
新しい展開の例を見ましょう.
展開が作成される
コントローラは、作成トリガを受け取り、同期を実行する.すべてのチェックを実行した後、それはDeployment strategy とトリガします.私たちのケースでは、私たちは転がりアップデートに興味を持っています.
The
rolloutRolling
メソッドは新しいレプリケートを作成します.我々は、一度にポッドを更新することができるように、すべてのロールアウトのための新しいレプリカを必要とする.展開が同じレプリカを保って、ちょうどそれを更新したならば、すべてのポッドは再開されます、そして、我々が要求を処理することができない数分があります.この時点で、少なくとも2つのレプリカがあります.それらのうちの1つは、我々がちょうど作成したものです.もう一つは(私たちがいくつかの同時のロールアウトを持っているならば、より多くのことがありえます).次に、スケールup and down それに応じて複製の両方.
To scale up 新しいレプリカは、どのように多くのレプリカは、展開の期待を見て起動します.我々が十分にスケールしたならば、我々はちょうどそこで止まります.我々がスケーリングを保つ必要があるならば、我々はチェックしますmax surge value そして、それを実行しているポッドの数と比較してください.あまりにも多くの実行している場合、それはスケールアップされませんし、いくつかの古いポッドが終了したまで待機します.さもなければ、新しいポッドの必要な数を起動します.
To scale down , 私たちはどのように多くの合計のポッドを実行しているmaximum available Pods 我々は、その後、完全にブートしたポッドを減算します.それに基づいて、我々はどのように多くのポッドを終了する必要がありますし、ランダムに終了することができます知っている.
この時点でコントローラは現在のトリガを終了した.しかし、展開自体は終わっていません.
レプリカを更新する
新しい展開は新しいポッドを起動するので、新しいトリガーを受け取ります.具体的には、ポッドが上下になると、レプリカは更新トリガを送信します.レプリケートの更新を聞いて、我々はブートまたは終了を終了したポッドを探すことができます.
それが起こるとき、我々は同期の上で同期ダンスをします.そして、構成に基づいて起動するシャットダウンと他のものにポッドを探して、それから新しい最新版を待ちます.
レプリカを削除する
すべての展開が常に正しく実行されていることを確認するための方法として、ReplicSet削除トリガを使用します.レプリカが削除され、展開が予期しない場合は、再度同期を実行する必要があります.
これは、(ダウンタイムを使用して)アプリをすばやく再起動する場合は、配置のレプリカを安全に削除することができます.新しいものはすぐに作成されます.
ポッドを削除
展開を許可する
ProgressDeadlineSeconds
オプション.設定が秒単位で経過していない(任意のポッドブートまたは停止)場合は、失敗したとしてマークされます.PODがクラッシュループに入るとき、これは典型的に起こります.それが起こるとき、podが決してオンラインにならないので、我々はReplicaset最新版を決して受けません.しかし、我々は、各クラッシュループ再試行のためのポッド削除の更新のいずれかを受信します.ここで同期することにより、我々は、それが最後の更新以来、どのくらいの期間を確認することができますし、確実にしばらくの間失敗したとして展開をマークします.
展開終了
展開を考えるならcomplete , 我々clean things
up .
クリーンアップでは、あまりに古いになったすべてのレプリカを削除します.壊れた展開をロールバックすることができるように、古いレプリケート(設定された任意のpodなしで)を設定します.
Note: ReplicaSets only hold a Pod template. So if you are always using the
:latest
tag for your Pod (or using the default one), you won't be rolling back anything. In order to have proper rollback here, you will need to change the container tag every time it is rebuilt. For example, you could tag the containers with thegit
commit SHA they were built against.
あなたはrollback a deployment と
kubectl rollout undo
コマンド.無限に
Kubernetesは一般的に複雑なツールとして見られますが、彼らがどのように働くかを理解するためにその部分を解剖することは難しくありません.また、それと同じくらい一般的であることは良いです、システムを非常にモジュラーにします.
たとえば、このポストで見たように、展開トリガーを聞いて、自分のロジックを実装するのはとても簡単です.または、完全に自分のコントローラーで再実装する(これはおそらく悪い考えでしょう).各々のコントローラが定期的にそれが所有するオブジェクトの最新版をチェックする必要がないので、このトリガーベースのシステムもものをより簡単にします.それは適切なトリガーを聞いて、適切なアクションを実行する必要があります.
Reference
この問題について(Kubernetes展開の解剖), 我々は、より多くの情報をここで見つけました https://dev.to/heroku/dissecting-kubernetes-deployments--16ejテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol