Kubernetes(k8s)は短時間で大きく躍進している。ほんの 2 年前、CoreOS の Fleet、Docker Swarm、Cloud Foundry Diego、HashCorpのNomad、Kontena、Rancher's Cattle、Apache Mesos、Amazon ECS 等と競合し、同製品が優れていることが完全に証明された。それら各プロジェクトの一部は公に中止を宣言し Kubernetes への協力に賛成し、その他は部分的なサポートまたは Kubernetes との完全な統合を発表したが、これはそれらのコンテナオーケストレーターの緩やかな死を意味している。どちらにしても k8s は最後まで残り続けたプラットフォームだ。単なるユーザーやプラチナスポンサーとしてだけでなく、同社のコンテナ事業を Kubernetes の成功に賭けて Kubernetes エコシステムに参加するビッグネームが増え続けている。Google の Kubernetes Engine、Red Hat の OpenShift、Microsoft の Azure Container Service、IBM の Cloud Container Service、Oracle の Container Engine 等がここで最初に思い浮かぶ。
しかしこれはどういう意味か?一つ目として、コンテナに関する雇用市場の 90% にかかわるため、開発者は単一のコンテナオーケストレーションプラットフォームのみ習得する必要があるということだ。k8s を効率よく学習するために時間を投資する良い理由であり、我々が k8s に深く染まっていることも意味している。Kubernetes は Amazon の様だがコンテナであり、ロックインを望まない場合は Kubernetes に対するロックインとなる。Kubernetes でアプリケーションを設計、実装、運用することで、異なるクラウドプロバイダ、Kubernetes ディストリビューション、サービスプロバイダ等の間でアプリケーションを自由に移動できる。これにより、Kubernetes 認定された開発者がプロジェクトを開始し、支援後に引き続き実行する機会が与えられる。それは VM でなく、JVM でなく、新たなアプリケーション移植性レイヤーである Kubernetes であり、どれにも誰にでも共有可能となる。
Knee Deep in Kubernetes
以下は Kubernetes にどの程度依存しているかを示すコンテナ化されたサービス図だ。
[画像を大きくするにはクリック]
Figure 1 - Kubernetes でのアプリケーション依存
Kubernetes はアプリケーションに対する移植性 API でなく、移植性レイヤーと記載したことに注意してほしい。この図では、k8s APIを呼び出し可能な明示的に作成する必要のある K8s オブジェクトのみを示している。しかし現実にはもっとプラットフォームと結びついている。K8s は要件に応じアプリケーション設計を推進する分散プリミティブ(Pod、サービス、コントローラ等)全てを提供している。 これら新しいプリミティブとプラットフォーム機能により、将来の全サービス実装に使用するデザイン原則とデザインパターンを決定される。 これらは日々の課題に取り組むためにどのようなテクニックを使用するかという「ベストプラクティス」と呼ばれるものにも影響を及ぼす。従って Kubernetes に注目する道筋として、単なる相互作用 API としてではなく複数の観点からを包含する主要なパラダイムとしてみるべきだ。
Kubernetes 効果
コンテナとオーケストレータ機能は新たな概念とプリミティブを提供する。新しいプリミティブの最高の価値を引き出しその力をバランスさせるためには、我々を導く新しい設計原則が必要になる。新しいプリミティブを使用すればする程、繰り返される問題を車輪の再発明で解決することになる。これがパターンの必要となるケースだ。デザインパターンが新しいプリミティブをどのように構築するかの処方箋を提供し、繰り返される問題をより迅速に解決できる。設計原則は抽象的で基礎的であり、頻繁に変更されることはないが、パターンは原始的な振る舞いの変更によって影響を受ける可能性がある。プラットフォームの新機能はパターンをアンチパターンや関連性の低いパターンにする場合がある。次に、日々利用する実践方法や技術もある。技術とは、タスクを効率的に実行する細かな小手先のものから広範な作業と実践方法にまで及ぶ。より簡単かつ迅速に行える方法を見つければ即座に技術と実践方法を変更する。これが我々とプラットフォームが進化する方法だが、一方でなぜ我々がそのすべてを行っているのか?それこそ、この新プラットフォームを利用して利益と価値を得てニーズを満たすところだからだ。ある意味で「Kubernetes 効果」は自己強制的かつ多面的だ。
Figure 2 - ソフトウェア開発ライフサイクルにおける Kubernetes 効果
本記事の残りの部分で各カテゴリの例を詳しく掘り下げる。
分散概念とプリミティブ
新しい抽象概念とプリミティブが何を意味するのかを説明するため、よく知られたオブジェクト指向の世界である Java を用いて具体的に比較する。OOP 領域には、クラス、オブジェクト、パッケージ、継承、カプセル化、ポリモーフィズム等の概念がある。Java ランタイムはオブジェクトとアプリケーション全体のライフサイクルを管理するために一定の機能と保証を提供する。Java 言語と JVM ランタイムはアプリケーション作成におけるローカルインプロセスでのビルディングブロックを提供する。複数のプロセスやノードにまたがる分散システムを作成に向けた新たな分散プリミティブとランタイムセットを提供することで、Kubernetes はよく知られたこの考え方に全く新しい次元を追加する。 Kubernetes による近い将来、そうしたアプリケーション全体の動作を実装するために Java プリミティブのみに依存しない。依然としてオブジェクト指向のビルディングブロックを使用して分散アプリケーションのコンポーネントを作成する必要はあるが、アプリケーション動作に Kubernetes プリミティブも利用できる。 Kubernetes の分散概念とプリミティブの例をいくつか挙げる。
- Pod - 関連するコンテナの展開単位
- Service - サービスとロードバランサのプリミティブ
- Job - 非同期にスケジュールされたアトミックな作業単位
- CronJob - 未来や定期的な特定の時間に予定されるアトミックな作業単位
- ConfigMap - サービスインスタンスを跨いだデータ設定を分散させるためのメカニズム
- Secret - 機密性の高いデータ設定を管理するためのメカニズム
- Deployment - 宣言的なアプリケーションのリリースメカニズム
- Namespace - リソースプールを隔離するためのコントロールユニット
アプリケーションの信頼性に対する例として、Kubernetes のヘルスチェック( Readiness と Liveness プローブ等)にのみ頼ることが可能だ。アプリケーション内からクライアント側のサービス発見を行うのではなく、サービス発見に Kubernetes サービスを利用できる。Kubernetes Jobs を利用して非同期のアトミックな作業単位をスケジュールすることができる。 構成管理に ConfigMap を利用し、Java ベースの Quartz ライブラリや ExecutorService インターフェイスの実装を利用することなく Kubernetes CronJob を定期的なタスクスケジューリングに使用できる。
Figure 3 - 分散システムの一部としてのローカル・分散プリミティブ
インプロセスプリミティブと分散プリミティブは共通点を持つが、直接的な比較や置き換えはできない。それらは異なる抽象化レベルで動作し、異なる前提条件と保証がある。プリミティブのいくつかは一緒に利用される。例として、クラスを使用してオブジェクトを作成しコンテナイメージに配置する必要がある。しかし、Kubernetes CronJob の様なプリミティブは Java の ExecutorService 動作を完全に置き換えることができる。ここで JVM と Kubernetes 間で共通点のある概念は殆どないが、遠すぎるものではない。
Figure 4 - ローカル・分散プリミティブのカテゴライズ
過去、こちらに分散概念とプリミティブについてブログを記載してきた。ここでのポイントは、開発者が豊富なローカル・グローバル両方のプリミティブを利用して分散ソリューションを設計・実装できることだ。時間とともに新しいプリミティブは問題解決の新しい手段を生み出し、反復的に利用されるソリューションはパターンになる。
コンテナ設計の原則
設計原則は品質の高いソフトウェアを書くための抽象的なガイドラインと基本的なルールだ。この原則は具体的なルールを指定するものではないが、開発者の多くが理解し定期的に参照する言葉と共通の知恵を示している。 より良いオブジェクト指向ソフトウェア作成のガイドラインを示した Robert C. Martin 氏によって紹介されたSOLID 原則と同様、コンテナ化されたアプリケーション作成の設計原則も存在する。SOLID 原則はオブジェクト指向設計の推論のためにクラス、インタフェース、継承などのオブジェクト指向のプリミティブと概念を利用する。同様に、コンテナ化されたアプリケーション作成向けの以下に列挙する原則はコンテナイメージを基礎的なプリミティブとして用い、コンテナオーケストレーションプラットフォームをコンテナ実行時環境として利用する。コンテナベースのアプリケーションの設計原則は以下の通りだ。
- ビルド時
- 単一関心の原則 - コンテナは一つの概念を扱い、処理する必要がある
- 自己充足の原則 - コンテナは Linux カーネル にのみ依存し、コンテナのビルド時に必要なライブラリ等を追加する必要がある
- イメージのイミュータブルの原則- コンテナ化されたアプリケーションはイミュータブルであり、一度ビルドされたイメージは環境毎に異なることは期待されない
- ランタイム
- 高監視性の原則 - プラットフォームが最良の方法でアプリケーションを監視・管理するため、必要な API 全てをコンテナは実装する必要がある
- ライフサイクル適合の原則 - コンテナはプラットフォームからのイベントを読み込み、イベントに反応して適合させる手段が必要がある
- プロセス廃棄性の原則 - コンテナ化されたアプリケーションは可能な限り短期間で常に別コンテナインスタンスに置き換え可能である必要がある
- 実行時制限の原則 - コンテナはリソース要件を宣言する必要があり、アプリケーションが指定されたリソース要件に制限された状態を維持することも重要だ
これらの原則に従い Kubernetes 等のクラウドネイティブプラットフォームに適したコンテナ化アプリケーションを作成する可能性が高くなる。
[画像の拡大にはクリック]
Figure 5 - コンテナ設計原則
これらの原則は十分にドキュメント化されており、ここからホワイトペーパーとして自由にダウンロードすることができる。 原則のスニークプレビューは上記の通りだ。設計原則のスニーク・プレビューは上記となる。
コンテナデザインパターン
新しいプリミティブにはプリミティブ間の能力を説明する新しい原則が必要だ。プリミティブを使用すればするほど反復的な問題が解決され、パターンと呼ばれる反復的なソリューションと認識される。コンテナデザインパターンは手元の課題を解決するため最善の方法として、コンテナや他の分散プリミティブを構造化することに重点を置いている。コンテナに関するデザインパターンの短い一覧は以下の通りだ。
- サイドカー・パターン - サイドカー・コンテナは既存コンテナの機能を変更なしに拡張、強化する
- アンバサダー・パターン - このパターンは複雑さを隠して統一されたビューをコンテナに提供する
- アダプタ・パターン - アダプタはリバースアンバサダーのようなもので、外部からの Pod への統一インタフェースを提供する
- イニシャライザ・パターン - 初期化コンテナは初期化関連タスクをメイン・アプリケーション・ロジックから分離することができる
- ワーク・キュー・パターン - コンテナに基づく一般的なワーク・キュー・パターンは任意の処理コードをコンテナとしてパッケージ化し、任意のデータを取り込み、完全なワーク・キュー・システム構築を可能にする
- カスタムコントローラー・パターン - 本パターンではコントローラーがオブジェクトの変更を監視し、変更に基づいてクラスターを望む状態に変更する。この調整パターンを利用してカスタムロジックを実装することでプラットフォームの機能を拡張できる
- セルフアウェアネス・パターン - アプリケーションが必要な自己監視を行い、自身や実行環境に関するメタデータを取得する状況を記述する
この分野の基礎研究は Brendan Burns 氏と David Oppenheimer 氏によるコンテナデザインパターンの論文で行われている。 これにより Brendan 氏は書籍を執筆し、同書では分散システムにおけるデザインパターンと関連するトピックについて述べている。 Roland Huß 氏と私も Kubernetes Patterns というタイトルで、これらすべてのデザインパターンとコンテナベースのアプリケーションの使用例を記載した書籍を執筆した。以下はこれらのパターンを可視化したものだ。
[画像の拡大にはクリック]
Figure 6 - コンテナデザインパターン
プリミティブには原則と作成のためのパターンが必要となる。 Kubernetes を使用する場合のベストプラクティスと全体的な利点を見てみよう。
実践とテクニック
原則とパターンに加え、優れたコンテナ化アプリケーションを作成するには他のコンテナ関連のベストプラクティスとテクニックにも精通している必要がある。原則とパターンは頻繁には変更されない抽象的で基礎的な考え方だ。ベストプラクティスと関連するテクニックは具体的であり、頻繁に変更される可能性がある。 一般的なコンテナ関連のベストプラクティスを次に示す。
- 小さいイメージを目指す - これによりコンテナイメージをコピーする際のコンテナサイズ、ビルド時間、ネットワーキング時間が短縮される
- 任意ユーザーのサポート - sudo コマンドの利用やコンテナ実行に特定ユーザーを要求することは避けること
- 重要ポートのマーキング - EXPOSE コマンドを利用してポートを指定することで、人間とソフトウェア両方でイメージを簡単に利用できる
- 永続データには Volume を利用 - コンテナ破棄後に保存する必要のあるデータは Volume に書き込む必要がある
- イメージにメタデータを付与 - タグ、ラベル、アノテーション形式のイメージメタデータはコンテナイメージを見つけやすくする
- ホストとイメージの同期- コンテナ化されたアプリケーションには時刻やマシン ID 等、特定の属性でコンテナとホストを同期させる必要があるものがある
- STDOUT と STDERR へのログ - ファイルではなくシステム・ストリームへのロギングによりコンテナログが適切に収集され集約される
以下はコンテナに関するベストプラクティスを持つリソースへリンクだ。
- Best practices for writing Dockerfiles
- OpenShift Guidelines
- Kubernetes Production Patterns
- Kubernetes By Example
Kubernetes の利点
本記事から分かるように Kubernetes は基礎的な方法で分散システムの設計、開発、Day-2 Operation を指示している。学習曲線は短くなく Kubernetes 谷を渡るには時間と忍耐が必要となる。そのため、ここで Kubernetes が開発者にもたらす利点の一覧を完成させたいと思う。Kubernetes 舟に飛び込む理由を判断するのに役立ち、それを用いて IT 戦略を進めることが望ましい。
- セルフサービス環境 - チームやチームメンバーは CI/CD や実験目的でクラスタから隔離された環境を即座に取り出すことができる
- アプリケーションの動的配置 - アプリケーションの需要、利用可能なリソース、指針をもとに予測可能な方法でアプリケーションをクラスタに配置できる
- 宣言型サービスデプロイメント - 本抽象化によりコンテナグループのアップグレードとロールバック・プロセスをカプセル化し、繰り返し実行可能な自動化可能なアクティビティとする
Figure 7 - Kubernetes を用いたデプロイメントとリリースの戦略例
- アプリケーション・レジリエンス - コンテナと管理プラットフォームはアプリケーションのレジリエンスを以下の様な様々な方法で向上させる。
- 無限ループ: CPU 共有とクォータ
- メモリリーク: 自己 OOM
- Disk Hogs: クォータ
- Fork Bomb: プロセス制限
- サーキットブレーカー、タイムアウト、サイドカーとしてのリトライ
- サイドカーとしてのフェイルオーバーとサービス検出
- コンテナによるプロセス分離
- スケジューラを介したハードウェア分離
- オートスケーリングと自己修復
- サービスディスカバリ&ロードバランシング&サーキットブレーカー - プラットフォームではアプリケーションエージェントを使用せずサービスを検出し、他サービスを利用することができる。さらにサイドカーコンテナや Istio フレームワーク等のツールを利用して、アプリケーション以外のネットワーク関連の責任をプラットフォームレベルに完全移行することができる。
- 宣言的アプリケーショントポロジ - Kubernetes API オブジェクトを利用して、サービス展開方法、他サービスやリソース前提条件の依存性を記述することができる。 すべての情報を実行可能形式にすることで開発初期段階でアプリケーションのデプロイメント観点のテストを可能とし、プログラマブルアプリケーションインフラストラクチャとして扱うことができる。
[画像の拡大にはクリック]
Figure 8 - Kubernetes リソースディスクリプタファイルを用いた宣言的アプリケーショントポロジ
IT コミュニティが Kubernetes で盛り上がっているのにはまだまだ理由がある。上に挙げたものは開発者バックグラウンドの人間に非常に役立つものを記載した。
リソース
Kubernetes が開発者の日々の生活にどのように影響しているかをあなたに説明することができたら幸いだ。 本トピック、すなわち開発者観点から Kubernetes について詳しく知りたい場合、こちらの書籍をチェックアウトして Twitter で @bibryam をフォローして欲しい。
以下は開発者の視点から Kubernetes に焦点をあてたリソースへのリンクだ。
- Design patterns for container-based distributed systems (white paper)
- Principles of container-based application design (white paper)
- Designing Distributed Systems (ebook)
- Kubernetes Patterns (ebook)
- Kubernetes in Action (ebook)
著者について
Bilgin Ibryam(@bibryam)は ASF のコミッタとメンバーでもある Red Hat の Principal Architect だ。彼はオープンソースのエバンジェリスト、ブロガー、Camel Design Patterns と Kubernetes Patterns の著者だ。 彼の通常業務で Bilgin 氏はメンター、コーディング、主要開発者がクラウドネイティブソリューション構築を成功することに楽しんでいる。現在アプリケーション統合、分散システム、メッセージング、マイクロサービス、DevOps、クラウドネイティブの課題に焦点を当てている。 Twitter、Linkedin、ブログで見かけることができる。