Kubernetes-設計哲学

目次

クラウドインフラストラクチャの2つの鍵

インフラストラクチャはプログラム可能

初期のインフラストラクチャと比較して、クラウドプロバイダーは、API呼び出しによって完全に駆動されるコンピューティング、ストレージ、およびネットワークリソースをゼロから構築する必要があります。標準の安定したAPIの助けを借りて、プロバイダーとユーザーの両方が、サーバーレスコンピューティングなどの高レベルのリソースを構築できます。スケジューラやコントロールプレーンなどの基本的なプリミティブを作成し、プログラム可能なコードを介してこれらのリソースを管理することもできます。

クラウドコンピューティングサービスは、非常に柔軟で、セルフサービスで、API主導で最初から最後まで実行できるように設計されています。このようなモデルでは、ユーザーは手動で介入することなく仮想マシンとデータベースを作成できます。クラウドコンピューティングは、IT資産の仮想化の複雑さをサービスとしてカプセル化し、エンドユーザーは関数呼び出しを行うだけで済みます。

すべてのプログラムと同様に、コアサービスがAPIとして公開されると、機能を再利用してより高いレベルの抽象化を作成することで、それらを活用できます。例:AWS Fargate、Lambda、およびその他の製品は、より高いレベルの抽象化でコンピューティングサービスですが、実際には、最終的にEC2仮想マシンで実行されます。クラウドプラットフォームのユーザーは、同じAPIを使用して独自の抽象化を構築することもできます。例:Netflixは、EC2インスタンスに基づいてコンテナーワークロードをスケジュールおよび実行するためにTitusを確立しました。API経済サポートは、さまざまなサプライヤにさまざまなプロフェッショナル製品を提供します。

言い換えると、APIとしてインフラストラクチャプリミティブによって提供されるイノベーションにより、クラウドプロバイダーはより高いレベルのサービスを構築できます。従来のホスティングは十分な投資なしでは十分な柔軟性を満たすことができないため、このレベルの抽象化により、クラウドプロバイダーは従来の商品ホスティングプロバイダーからすばやく分離されます。

インフラストラクチャは宣言的です

インフラストラクチャを大規模に提供するために、クラウドプロバイダーは内部ワークフローの失敗からユーザーを保護する必要があります。宣言型APIは、基礎となるインフラストラクチャ構成の複雑さをかき消すことができる、正式な結果指向のプログラミング方法です。

大規模なクラウド配信シナリオでは、これまでの従来のITプロセス指向(コマンド)の運用および保守の考え方に頼ることはできません。規模の点では、手動による回復は、ワークフローで発生するすべての障害に対して非現実的で非経済的です。したがって、業界では、ユーザーが内部システムで発生する可能性のある多数の障害にさらされることなく、ソフトウェアインフラストラクチャを定義する方法が必要です。最終的な解決策は、宣言型APIを使用することです。宣言型APIを使用して、ユーザーはクラウドコンピューティングプラットフォームに、実装方法ではなく、見たい結果を伝えます。ユーザーにとって、クラウドプロバイダーと連携するためのより直感的な方法を見つけました。つまり、展開を正確に展開するのではなく、展開の外観を説明することです。

クラウドプロバイダーの場合、管理ソフトウェアと基盤となるハードウェアの複雑さをAPIの背後に沈める必要があります。ユーザーは、ワークフローの特定の手順を完了するために制限される必要はありません。たとえば、必須のAPIに基づいてアプリケーションサービスを構築します。このようにして、クラウドプロバイダーは、技術開発に応じてワークフローのさまざまな部分をすばやく繰り返し実装でき、ユーザーの宣言型APIは常に変更されません。

宣言型APIを使いやすさの点でクラウドプロバイダーにとって魅力的なものにする決定的な要因は、このようにインフラストラクチャを設計することでユーザーとの摩擦を減らすことができることであることがわかります。摩擦が減少するにつれて、クラウドプロバイダーは、コンピューティングスケジューラなどの高レベルのサービスやプリミティブの形で新しい抽象化を提供できるようになりました。

宣言型API

宣言的(宣言的)プログラミングは、エンジニアによって常に必須(命令的)と比較されてきました。前者は「結果指向」であり、後者は「手続き指向」です。

通常、私たちは必須のプログラミングと接触しており、特定の効果または目標を達成するために完了する必要のある命令を説明する必要があります。一般的なプログラミング言語であるGo、Ruby、およびC ++は、実際に開発者に必須のプログラミング方法を提供します。

SQLは、開発者が必要なデータを指定できるようにする一般的な宣言型プログラミング言語です。宣言的プログラミングは、開発者の作業負荷を大幅に削減し、開発、運用、および保守の効率を大幅に向上させることができます。もちろん、宣言的プログラミングは、SQLに対応するRDBMSなど、サポートとして強力なリソース管理システム(リソース管理システム)に基づく必要があることがよくあります。

Kubernetesは、アプリケーションの開発と展開のためのこのようなリソース管理システムであり、etcdを中心に「エンド指向」のオーケストレーションシステムのセットを構築します。ユーザーがAPIオブジェクト(Kubernetesオブジェクト)の説明(Spec)をKubernetesに送信すると、Kubernetesは、クラスター全体の各リソースのステータス(Status)がAPIオブジェクトによって記述された要件と一致することを確認する責任があります。さらに重要なことに、この保証は「無条件」で「期限なし」の約束です。etcdに格納されているすべてのAPIオブジェクトについて、Kubernetesは「コントローラーパターン」を開始します。無限ループ。常にチェックしてから調整し、最後にクラスター全体の状態がこのAPIオブジェクトの説明と一致していることを確認します。

Kubernetesプロジェクトの「コンテナオーケストレーション」の実装の中核は「コントローラモード」と呼ばれるメカニズムにあることがわかります。つまり、etcd(ウォッチ)でAPIオブジェクトの変更を監視することにより、Kubernetesプロジェクトをコントローラと呼ばれるコンポーネントに含めることができます。これらの変更に対応して。Podなどのアプリケーションオブジェクトやiptablesやストレージデバイスなどのサービスオブジェクトに関係なく、APIオブジェクトが変更されると、Kubernetesが次に実行する必要がある応答ロジックは、対応するコントローラーで定義されたオーケストレーションアクションです。

for {
    
    
    实际状态 := 获取集群中对象X的实际状态(Actual State)
    期望状态 := 获取集群中对象X的期望状态(Desired State)

    if 实际状态 == 期望状态{
    
    
      什么都不做
    } else {
    
    
      执行编排动作,将实际状态调整为期望状态。
    }
}

たとえば、YAMLを使用して期待されるサービスのトポロジと状態を記述(定義)する場合、Kubernetesは、既存の状態から期待される最終状態への移行を支援します。

apiVersion: v1
kind: Pod
metadata:
  name: rss-site
  labels:
    app: web
spec:
  containers:
    - name: front-end
      image: nginx
      ports:
        - containerPort: 80
    - name: rss-reader
      image: nickchase/rss-php-nginx:v1
      ports:
        - containerPort: 88

もちろん、ここのコントローラーは、APIオブジェクトの変更の認識を実現するためにetcdのWatchAPIに依存しています。

要するに、Kubernetesの宣言型APIは、クラスターの予想される動作状態を指定することです。予想と矛盾する場合は、指定されたYAMLファイルを介してオンラインクラスターの状態を移行できます。現在のステータスは自動的に適切な操作を行います。

すべてがAPIにあります

Kelsey Hightowerはこの目標についてよく言及し、Daniel Smithは将来の目標のアイデアも提案しました:Kubernetes APIは、仮想化(仮想マシンなど)から物理レベルのすべての要素(ルーターデバイスなど)まで、すべてを管理できます。

Kubernetes APIは最初にリソースをモデル化し、非常に厳しいリソース要件があります。リソースのデータ構造はすべて標準仕様(apiVersion、タイプ、メタデータ、および仕様)に従う必要があり、リソースのアクション(公開、配置、取得、削除など)はAPI動詞(HTTPメソッド)と一致している必要があります。

さまざまなリソースの幅広い標準に基づいて、Kubernetesツールとライブラリは、各リソースをカスタマイズすることなく、すべてのシナリオで一貫して機能します。Kubernetesコミュニティの多くのSIG組織は、機能を他のコンポーネントに転送するのではなく、このAPIシステムを絶えず拡張しています。もちろん、これはKubernetesの複雑さに関する議論のピークでもあります。

Kubernetes APIは標準化されているため、すべてのインフラストラクチャをリソースとしてモデル化できます。リソースデータ構造が標準化されているため、コントローラーはリソース間の違いを無視することもできます。例:リソースラベルの戦略が要件を満たしているかどうかをチェックするコントローラーは、各リソースの役割を知る必要はありません。構造が一貫している限り、コントローラーは同じ場所に移動して各オブジェクトをチェックできます。

コントロールプレーンを定義する

データプレーンをコントロールプレーンから分離するというアイデアはSDNフィールドから来ており、Marc Brookerはこのコンセプトをさらに要約しています:

  1. データプレーンコンポーネントは、リクエストパス上に直接あります。コンポーネントは正常に実行される必要があり、システムからの要求の数に比例して拡張できます。
  2. コントロールプレーンコンポーネントは、データプレーンがその作業を完了するのに役立ちます。これには、リソース管理(リソースの追加と削除)、障害許容度(ハードウェア/ソフトウェア障害の監視と修正)、および展開(時間の経過に伴うシステムの変更)が含まれます。システム要求を満たすために制御プレーンは必要ないため、制御プレーンのコンポーネントは、データプレーンに影響を与えることなく一定期間中断できます。

コントロールプレーンを介してインフラストラクチャを管理するための理論的基礎は、複数の業界にまたがる幅広い分野である「サイバーネティクス」に由来します。

  1. 必要な状態を宣言します。システムは静的ではなく、外部および内部の状態に応答し、変更をフィードバックします。安定したシステムは、所定の状態に移行する必要があります。
  2. 制御ループ:データプレーンコンポーネントを継続的に周期的に監視し、連続制御ループとフィードバックメカニズムにより、目的の状態からの逸脱を継続的に修正できます。

では、Kubernetesはどのようにコントロールプレーンの原則を適用するのでしょうか?Kubernetesは、InformerやWorkqueuesなどのコントローラーのループの構築を制御する責任があります。

Kubernetesアーキテクチャ全体で最も一般的なテーマは、標準化のアイデアです。Kubernetesリソースモデルは、リソース構造の一貫性に大きく依存しており、実行時にデータへのエントリを厳密に制限します。同じプリミティブをさまざまな抽象化で使用できます。これらのプリミティブは、クラウドコンピューティングのコア原則である、より高いレベルの抽象化を作成するためのリソース階層化も実装します(例:デプロイメント抽象ポッド)。

したがって、一般的な制御平面は、コンテナのオーケストレーションではなく、KubernetesAPIの設計に依存します。

非侵襲的

ユーザー(エンジニア)のニーズを可能な限り満たし、エンジニアの作業負荷とタスクを減らし、柔軟性を高めるために、Kubernetesはエンジニアに非侵入型のアクセス方法を提供します。各アプリケーションまたはサービスがコンテナイメージにパッケージ化されると、アプリケーションのコードを変更することなく、Kubernetesでシームレスに使用できます。これは、コンテナ技術の特性によるものです。

ContainerとKubernetesは、アプリケーションにラップされた2つのレイヤーのようなもので、どちらもアプリケーションにコンテナ化とオーケストレーション機能を提供します。これらは、アプリケーション内で変更を加えることなく、ContainerとKubernetesクラスターで実行できます。最大のメリットをもたらすために設計に非侵入的であることを選択するのはKubernetesであり、非侵入的アクセス方法も、現在ほとんどすべてのアプリケーションまたはサービスが考慮しなければならない点です。

移植性

マイクロサービスアーキテクチャでは、ビジネスを処理するすべてのサービスをステートレスサービスにすることがよくあります。以前はメモリに保存されていたデータとセッションキャッシュが、Redisなどのデータベースに保存されるようになりました。マイクロサービスアーキテクチャには、私たちはビジネスを分割し、サービス間の境界を明確にします。そのため、ステートフルなサービスは、アーキテクチャの水平方向の移行に障害をもたらすことがよくあります。

ただし、ステートフルサービスは避けられません。すべての基本サービスまたはビジネスサービスを、コンピューティングのみを担当するプロセスに変えましたが、揮発性キャッシュと永続データの保存を担当するプロセスは他にもあります。 Kubernetesは、このステートフルサービスのサポートも強化しています。

PersistentVolume(永続ストレージ)とPersistentVolumeClaimの概念は、基盤となるストレージの違いを保護するために使用されます。現在、Kubernetesは次のタイプのPersistentVolumeをサポートしています。これらの異なるPersistentVolumeは、開発者によって宣言されたPersistentVolumeClaimによって異なるサービスに割り当てられます。上位層の場合、すべてのサービスがPersistentVolumeに触れる必要はなく、PersistentVolumeClaimによって取得されたボリュームを直接使用するだけです。

ここに写真の説明を挿入

オペレーター

ステートフルアプリケーション(Kafka、TiDBなど)とステートレスアプリケーション(Jave Webサイトなど)の違いは、前者はリモートストレージやネットワークデバイスなどの一部の外部リソースに拘束力のある依存関係があることです。また、ステートフルアプリケーションの複数のインスタンス間にはトポロジ的な関係が存在することがよくあります。

したがって、コンテナの世界では、ステートフルアプリケーションは「異種」になっています。コンテナの本質は、実際には外界(ホスト)を認識しない分離され制限された「サンドボックス」であることがわかっているため、コンテナの「状態」は「揮発性」である必要があります。

分散アプリケーションは、典型的なステートフルアプリケーションです。これらのコンテナインスタンスが分散アプリケーションのようにトポロジ的な関係になり、これらのインスタンス自体が完全に同等でない場合、コンテナ化されたソリューションは再び「醜い」ものになります。立ち上がる:この場合、アプリケーション開発者は、これらのコンテナインスタンスに対して、保守が難しい一連の管理スクリプトを作成する必要があるだけでなく、コンテナの再起動後の状態喪失の問題に対処する方法も見つける必要があります。実際、これらのコンテナの状態を維持するには、コンテナの分離を解除し、コンテナに外界を認識させる必要があります。これにより、コンテナ化とステートフルネスが2つの完全に矛盾する要件になります。

オペレーターの設計は、実際にはコントローラーパターンのアイデアをより徹底的に実装することです。Operatorでは、ユーザーによって送信されたAPIオブジェクトは、単一のアプリケーションの説明ではなく、完全な分散アプリケーションクラスターの説明になります。ここでの違いは、分散アプリケーションクラスター全体の状態と定義が、Kubernetesコントローラーが保証する必要のある「最終状態」になっていることです。例:このアプリケーションにはいくつかのインスタンスがあり、インスタンス間の関係を処理する方法、インスタンスがデータを格納する必要がある場所、インスタンスデータをバックアップおよび復元する方法はすべて、APIオブジェクトの変更に応じてコントローラーが処理する必要のあるロジックです。

演算子は実際にはコードの一部です。このコードは、etcdの分散アプリケーションクラスターを記述するAPIオブジェクトを監視します。次に、このコードはKubernetesコントローラーモードを実装して、クラスターが常にユーザーの定義とまったく同じになるようにします。このプロセスでは、Operatorは、Kubernetesストレージやネットワークプラグインなどの外部リソースを使用して、アプリケーションの状態を維持するためのヘルプを共同で提供することもできます。

したがって、Operator自体の実装は、実際にはKubernetes宣言APIに基づく一種の「マイクロイノベーション」です。Kubernetes APIの機能を合理的に利用してカスタムAPIタイプを追加し、Kubernetesのネイティブ「コントローラーモード」を巧みに使用して、分散アプリケーションの最終状態の調整プロセスを完了します。

使用法に関しては、Operator自体は、ユーザーが多くのコードを作成する必要がある開発者ツールです。しかし、このコード作成プロセスは、多くの人が期待していたように、Operatorプロジェクトをニッチに導くことはできませんでした。代わりに、わずか3年で、Operatorはコンテナ化された分散アプリケーション管理の事実上の標準になりました。今日、オペレータープロジェクトの生態学的状態に疑いの余地はありません。

オペレーターの実現原理

名前が示すように、Operatorプロジェクトの本来の目的は、開発者が運用および保守(Operate)の機能を実現できるようにすることでした。ただし、Operatorの中心的な考え方は、「開発者のために運用および保守作業を行う」ことではなく、「開発者が運用および保守ツールを自分で作成できるようにする」ことです。さらに興味深いのは、この操作および保守ツールの作成標準、またはオペレーターコードを作成するときに参照できるテンプレートが、Kubernetesの「コントローラーパターン」であるということです。

前述のように、Kubernetesの「コントローラーモード」は、ポッドなどのAPIオブジェクトを中心に展開します。コントローラーは、ポッドの追加、削除、および変更に応答することにより、ポッドのオーケストレーションアクションを定義します。

Operatorの設計アイデアは、開発者がKubernetesに新しいAPIオブジェクトを追加して、分散アプリケーションのクラスターを記述できるようにすることです。次に、このAPIオブジェクトのコントローラーで、開発者はこの分散アプリケーションクラスターの操作および保守アクションを定義できます。

たとえば、次のYAMLファイルが3ノードのetcdクラスターの説明を定義しているとします。

"etcd.database.coreos.com/v1beta2"
kind: "EtcdCluster"
metadata:
    name: "example-etcd-cluster"
spec:
    size: 3
    version: "3.2.13"

このようなEtcdClusterオブジェクトを使用して、開発者が次に行う必要があるのは、EtcdClusterコントローラーを作成することです。これにより、ユーザーがこのようなYAMLファイルをKubernetesに送信すると、作成するコントローラーがEtcdClusterの「追加」イベントに応答します。ユーザー用に3ノードのetcdクラスターを作成します。次に、コントローラーで作成したイベント応答ロジックに従って、このクラスターのノードの更新および削除イベントを自動的に処理し、私が定義した他の操作および保守機能を実行します。このようなEtcdClusterコントローラーは、etcdオペレーターのコアコンポーネントです。

ただし、この演算子を完了するための実際の難しさは次のとおりです。Kubernetesは、ポッド、ノード、サービスなどのKubernetes独自のネイティブAPIオブジェクトのみを認識します。開発者が定義したEtcdClusterオブジェクトをどのように認識できますか?

当時、Kubernetesプロジェクトでは、ユーザーがTPR(サードパーティリソース)と呼ばれるAPIオブジェクトのプラグイン機能を追加できました。これは、CRD(カスタムリソース定義、カスタムリソース)と呼ばれるようになりました。

CRDを使用すると、YAMLファイルを送信して、EtcdClusterなどの新しいAPIオブジェクトの名前を定義できます。また、int形式のサイズフィールドや文字列形式のバージョンフィールドなど、このオブジェクトで許可される有効な属性を定義することもできます。 。次に、特定のEtcdClusterオブジェクトの記述ファイルをKubernetesに送信し、対応するコントローラーがそれを処理するのを待つことができます。そして、このコントローラーはオペレーターのバックボーンコードです。

etcdオペレーターは、Kubernetesのコア原則を使用して、etcdクラスターを自動的に管理します。さらに重要なことに、Kubernetesに付属のStatefulSetを使用する必要はありません。

オペレーターが依存するKubernetes機能は、コアの宣言APIとコントローラーモードのみであることがわかります。オペレーターの特定の実装ロジックは、カスタムコントローラーのコードで記述されています。この設計により、開発者は高い自由度を得ることができます。

StatefulSetとOperatorの違い

ただし、Kubernetesプロジェクトは、常にStatefulSetと呼ばれるステートフルなアプリケーション管理機能を構築してきました。また、Kubernetesプロジェクトについて少し理解していれば、OperatorとStatefulSetはアプリケーションの状態の抽象化が異なりますが、それらの設計原則はほぼ完全に同じであることがわかります。つまり、これら2つのメカニズムの本質は次のとおりです。これは、KubernetesAPIオブジェクトの「終了状態」を調整する単なるコントローラーです。

しかし、なぜオープンソースコミュニティには、まったく同じコア原則とほぼ同じ設計目標を持つ2つのステートフルなアプリケーション管理ソリューションがあるのでしょうか。

StatefulSetのコア原則は、実際には分散アプリケーションの2つの状態を維持することです。

  • 分散アプリケーションのトポロジステータス、またはノード間の起動シーケンス。
  • 分散アプリケーションのストレージ状態、または各ノードが依存する永続データ。

ただし、上記の2つの状態の保持メカニズムを実現できるようにするために、StatefulSetの設計は、アプリケーション開発者に追加の制約をもたらします。

たとえば、etcdクラスターのノード間のトポロジ関係は、決定するノード名や役割(マスターやスレーブなど)に依存しませんが、各etcdノードの起動パラメーターに記録されます。これにより、StatefulSetは、「ノードに整然としたDNS名を割り当てる」というトポロジ保守方法を使用しますが、これは実際には役に立ちません。代わりに、開発者は、ノードの起動コマンドに多くのロジックを追加して、正しい起動コマンドを生成する必要があります。とてもエレガントではありません。同様に、ストレージ状態の場合、etcdクラスターのデータバックアップおよびリカバリ方法は、StatefulSetが依存するリモート永続データボリュームスキームとは何の関係もありません。

StatefulSetが、MySQLなどの不完全なアプリケーションノード管理機能を備えたプロジェクトに実際に適していることを確認するのは難しくありません。etcdの場合、Raftの助けを借りて自己管理を実現した分散アプリケーション、StatefulSetの使用、およびそれがもたらすさまざまな制限は、実際には非常に厄介です。

Kubernetesのネイティブ拡張メカニズムで実装されたOperatorは、StatefulSetよりも柔軟性があり、開発者に制御を戻すことができる分散アプリケーション管理ツールです。

Kubernetes API Serverは、ソフトウェアのユニバーサルコントロールプレーンになります

Kubernetes APIエコロジーは急増しています。ほぼ毎週、または毎日でも、Kubernetes開発者エコロジーをめぐる競争が多すぎます。この非常に繁栄しているコミュニティの背後では、未知の方法で開始または終了します。

これらすべての論争の根本的な原因は非常に単純です。Kubernetesプロジェクトは、クラウドコンピューティング時代のアプリケーション開発者にとってのターミナルの入り口として広く認識されています。これが、Google、Microsoft、CoreOSとHeptioのいずれであっても、このエコシステムの大小を問わず、すべてのプレーヤーが、この将来のクラウド時代の開発者ポータルになるために、KubernetesAPIレイヤーで話す権利を擁護する努力を惜しまない理由です。場所を取得します。

過去数年間の激しい競争の中で、Kubernetesの戦略はコンテナオーケストレーションプラットフォームの標準として設定されました。しかし、長期的には、Kubernetesのビジョンはコンテナだけでなく、そのAPIにもあり、より基本的で幅広いレベルのソフトウェア管理プラットフォームになろうとしています。この目標により、Kubernetes APIはソフトウェアの一般的な制御プレーンになり、APIサーバーは管理ソフトウェアの信頼できるインターフェイスになります。

おすすめ

転載: blog.csdn.net/Jmilk/article/details/109909993