Kubernetes 採用のメリット

最近、ようやく「入門 Kubernetes」を腰を据えて読み始めました.

控えめに言って最高です.
自信をもっておすすめできる一冊です.

 

今回は、「入門 Kubernetes」の第一章に書かれている Kubernetes 採用のメリットを、自分の理解のためにまとめたい(という名の写経をしたい)と思います.

ベロシティ

昨今の Web ベースのサービスは数時間ごとに機能改善されることが珍しくなく、新しいコンポーネントや機能を開発しデプロイできるスピードが、競争相手と差をつける要素になるケースが多くなっています.

ただし、ここでいう速さとは単なるスピードではありません.
ユーザーは反復的改善を求める一方で、信頼性の高いサービスにも関心があります.
ソフトウェアは継続的に変化していても、システムは常に動いていることが求められています.

その結果、単にたくさんの機能を世に出せばいいのではなく、可用性の高いサービスを動かし続けながら世に出せたものの数で、速さを測ることになります.

この点において、可用性を保ちながらもすばやく進化していくのに必要なツールを、コンテナと Kubernetes は提供できます.

 

イミュータブルであることの価値

コンテナと Kubernetes は、イミュータブルなインフラの原則を守って分散システムを構築するように、開発者を後押しします.

伝統的には、コンピュータとソフトウェアシステムはミュータブルなインフラとして扱われてきました.
ミュータブルなシステムでは、インフラの現在の状態はある1つの成果物によって表現されるのではなく、追加されてきた更新や変更の積み重ねとして表現されます.

その一方でイミュータブルなシステムでは、積み重ねられてきた一連の更新や変更の代わりに、全く新しいイメージが作られ、1回のオペレーションでイメージ全体をその新しいイメージで置き換えてしまいます.変更が積み重ねられていくことはありません.

ミュータブルなシステムは作成した方法の記録を持たないのに対し、イミュータブルなシステムは作成した方法を明示的に(具体的には Dockerfile として)保持します.
これによって新しいバージョンでの違いが簡単に分かるようになり、問題が起きたときにも、何が変更され、どのように修正すべきなのかを突き止めやすくなります.

さらに、既存のイメージを変更せずに新しいイメージを構築すると、古いイメージを残しておけます.するとエラーが起きたときのロールバックのためにこのイメージをすぐに使用できます.
一方、既存のバイナリに新しいバイナリを上書きしてしまうと、ロールバックはほとんど不可能になります.

 

宣言的設定

イミュータブルであることは、クラスタ上でコンテナを動かすだけでなく、Kubernetes に対してアプリケーションを記述する方法にも当てはまります.Kubernetes 上ではあらゆるものが、システムの望ましい状態を表現する宣言的設定のオブジェクトです.

ミュータブルなインフラとイミュータブルなインフラの関係のように、宣言的設定と命令的設定は考え方が対照的です.命令的設定では、望ましい状態を宣言するのではなく、一連の命令の実行によって状態が定義されます.命令的なコマンドがアクションを定義する一方で、宣言的設定は状態を定義します.

以下はレプリカを3つ生成するタスクの例です.
命令的なアプローチでは「Aを起動、Bを起動、Cを起動」のように逐次処理的な命令なのに対し、宣言的な設定では「レプリカ数は3に等しい」のように状態を定義します.

宣言的設定では、ソフトウェア開発の伝統的なツールであるソース管理、コードレビュー、ユニットテストなどの仕組みを、命令的設定ではうまく適用しにくかった方法で使用できます.

バージョン管理システムに保存された宣言的状態と、望ましい状態とを最終的に一致させる Kubernetes の能力によって、変更のロールバックが簡単になります.要するに、システムの以前の宣言的状態を、もう一度適用すればいいだけです.命令的設定はA点からB点へ遷移する方法を記述するものであって、元に戻す方法まで含めることはめったにないので、命令的設定を使っているシステムでは通常はこのようなロールバックは不可能です.

 

自己回復するシステム

Kubernetes はオンラインで自己回復するシステムです.
Kubernetes は、現在の状態が望ましい状態に一致するように動き続けます.つまり、システムを初期化するだけでなく、その後もシステムを不安定にしたり、信頼性に影響を及ぼしかねない障害や揺らぎからシステムを保護します.

オペレータによる従来型の復旧作業は、手動の復旧策の実行やアラートに対する人間による介入という形で行われます.
このような命令的な復旧作業は、以下のような欠点があります.

  • オンコールのオペレータを用意する必要があり、お金が掛かる
  • 作業のために人間が反応してログインする必要があるため、一般的に対応は遅くなる
  • 命令的設定の管理の問題の影響を受けるので、信頼性が引いものとなる

Kubernetes のような自己回復するシステムは、オペレータの責任を軽減すると共に、信頼性の高い復旧策をより早く実行することによって、システム全体の信頼性を改善することもできます.

 

サービスとチームのスケール

プロダクトが成長するにつれて、ソフトウェアと、ソフトウェアを開発するチームの両方にスケールが必要になってきます.Kubernetes は、この両方を達成するのに役立ちます.Kubernetes は、分離アーキテクチャを重視することで、スケーラビリティを実現しています.

分離

分離アーキテクチャでの各コンポーネントは、定義済みの API とサービスロードバランサによって他のコンポーネントから分けられています.

コンポーネントをロードバランサで分離すると、サービスの他の層を調整したり設定し直したりせずにプログラムのサイズ(ひいてはキャパシティ)を大きくできるので、サービスを構成するプログラムをスケールするのが簡単になります.

サーバを API で分離すると、API の開発を担当する各チームは、外部との接続部分が明確な小さなマイクロサービスに集中できるので、開発チームのスケールも簡単になります.マイクロサービス間が簡潔な API で接続されると、ソフトウェアのビルドやデプロイに必要なコミュニケーションオーバヘッドも小さく保てます.

アプリケーションとクラスタの簡単なスケール

Kubernetes のイミュータブルで宣言的な性質は、サービスのスケールを簡単にします.サービスを拡大していくことは、設定ファイル内の数字を変更して、その宣言の状態を Kubernetes に通知し、あとは Kubernetes に任せるだけです.

もちろん、こういったスケールをするには、使用できるリソースがクラスタ内にある必要があります.クラスタ自体のスケールアップが必要な場合もあるでしょう.ここでも Kubernetes のおかげで作業が簡単になります.クラスタ内の各マシンは他のマシンと完全に同じものとして扱えて、しかもそれぞれのアプリケーションはマシンの細かい部分とはコンテナによって分離されています.そのため、クラスタにリソースを追加することは、新しいマシンのイメージを作ってそれをクラスタに追加するだけで良いのです.

また、マシンリソースをスケールする際の問題の1つに、使用状況の予測があります.この問題に対し、Kubernetes は、将来のコスト予測をシンプルにします.
もし、あるサービスに割り当てたマシンを他のサービスが使用できないなら、各サービスの成長予測の最大値をもとに予測を行うしかありません(Legacy System).

ここで、個別のサービスから使用するマシンを切り離し、まとめて管理するのに Kubernetes を使うと、複数のサービスの全体の成長予測を合計したものを元にリソース使用の予測を立てられるようになります.
複数の変数の成長率を1つの値にまとめることで、統計的なノイズを減らし、より信頼のあるリソース使用の成長率の予測が立てられます.さらに、サービスからマシンを独立させると、各サービスがマシンの余剰リソースを共有できるので、計算リソースの成長予測に関するオーバーヘッドをかなり減らせます.

 

マイクロサービスによる開発チームのスケール

多くの研究で指摘されているように、理想的なチームのサイズは「ピザ2枚分のチーム」、つまり大体6人から8人とされています.しかし、多くのプロジェクトでは、成功や目標達成のためにもっと大きなリソースが必要になります.その結果、機敏さのために理想的なチームの大きさと、プロダクトの最終ゴール到達のために必要なチームの大きさの間で、せめぎ合いがあります.

このせめぎ合いを解消するよくある方法として、それぞれ独立したサービス指向の各チームがマイクロサービス1つずつの開発を担当するという開発方法が取られてきました.
Kubernetes は、このような分離されたマイクロサービスアーキテクチャの構造を簡単にする、たくさんの抽象化層や API を提供しています.

  • Pod、すなわちコンテナのグループが、さまざまなチームが開発したコンテナイメージをグループ化して、1つの単位としてデプロイ可能とする
  • Service が、マイクロサービス間の分離のためにロードバランシングやネーミング、ディスカバリ機能を提供する
  • Namespace が、マイクロサービス同士の連携範囲を制御できるよう、分離とアクセス制御を行う
  • Ingress が、複数のマイクロサービスをまとめつつ、単一の外部からアクセス可能な API を提供できる、簡単なフロントエンドを提供する

 

一貫性とスケールのための依存関係の切り離し

Kubernetes のスタックによる依存関係の切り離しと分離は、インフラの低いレベルでも一貫性を高めます.この分離で重要なのは、コンテナオーケストレーション API が、クラスタオーケストレーションのオペレータの責任と、アプリケーションオペレータの責任とを切り離すためのルールとして存在している点です.アプリケーション開発者は、SLA(Service-level agreement) がどのように実現されているかを気にせずに、コンテナオーケストレーション API によって提供される SKA に依存できます.コンテナオーケストレーション API の SRE(Site Reliability Engineer) は、自分の担当するオーケストレーション API 上で動いているアプリケーションのことを気にせずに、SLA を守ることに集中できます.

この依存関係の切り離しにより、Kubernetes クラスタを動かすチーム自体は小さくても、そのクラスタ上で何千というサービスが動かせることになります.さらに、そのチームは数十のクラスタが世界中で動いていても、クラスタの面倒を見られます.コンテナと OS を切り離すと、OS の SRE が各マシンの OS の SLA に集中できるようになる点も重要です.これは、Kubernetes のオペレータは OS の SLA に依存しつつ、OS のオペレータは OS の SLA を守ればよいというように、責任範囲を切り分けたことになります.ここでもまた、OS 専門家の小さなチームで、たくさんのマシンの集まりを管理できるのです.

もちろん、小規模だとしても OS の管理にチームを割り当てるのは、難しいことが多いでしょう.そういった環境では、パブリッククラウドプロバイダが提供しているマネージドな Kubernetes-as-a-Service(KaaS) が候補に挙がります.

KaaS を使うか自分でサーバを管理するかは、スキルや状況を考えて、必要とされるものに応じて判断します.小さな組織にとっては、クラスタを管理することよりも、ソフトウェアを作ることに時間とエネルギーを使えるので、KaaS は簡単に使えるソリューションになります.Kubernetes クラスタを管理するのに専任のチームを用意できるような大きな組織では、クラスタの能力やオペレーションの点で大きな柔軟性がある自前のクラスタを持つ意味があります.

 

インフラの抽象化

パブリッククラウドの目的は、開発者が使用できる簡単でセルフサービスなインフラを提供することです.ところが、クラウド API のほとんどは IT インフラを反映するものになっていて、開発者が使いたいコンセプトを表していません(例えば「アプリケーション」とは言わず「仮想マシン」と言うことなど).さらに、クラウドを使うなら、多くの場合はクラウドプロバイダごとに異なる実装やサービスの詳細を知る必要があります.このような API を直接使ってしまうと、複数のクラウドあるいはクラウドと物理環境をまたいでアプリケーションを動かすのは難しくなります.

Kubernetes のようなアプリケーション指向のコンテナ API へ移行するのは、2つの具体的な利点があります.1つめは、前述したように特定のマシンから開発者を分離できることです.クラスタをスケールするのに全体でマシンを共有できると、マシン指向な IT の作業が簡単になるだけでなく、Kubernetes の特定のクラウドインフラ向けの高レベルな API を使えるので、クラウド上で高度なポータビリティを持つことができます.

開発者がコンテナイメージでアプリケーションを構築し、ポータビリティのある Kubernetes の API を使ってそれをデプロイする場合、環境間でアプリケーションを移動したり、ハイブリッドな環境でアプリケーションを動かすには、単に宣言的設定を新しいクラスタに送ればいいだけになります.Kubernetes は特定のクラウドを抽象化するたくさんのプラグインを持っています.例えば、主要なパブリッククラウドに加え、いくつかのプライベートクラウドや物理インフラ上でロードバランサを作成するそれぞれの方法を Kubernetes の Service は知っています.さらに、Kubernetes の PersistentVolume や PersistentVolumeClaim を使えば、特定のストレージ実装を抽象化することも可能です.

これらをすべて考え合わせると、Kubernetes のアプリケーション指向な抽象化層の上で構築を行うことで、アプリケーションの構築やデプロイ、管理の仕組みが、さまざまな環境において本当にポータブルなものになります.

 

効率性

Kubernetes がもたらす開発者や IT 管理に対する利点に加えて、抽象化には具体的な経済的利点もあります.開発者はマシンのことを考えなくてよくなるので、アプリケーションは何の影響も受けずに1台のマシンに同居できるようになります.つまり、複数のユーザからのタスクを、少数のマシンにきっちり詰め込めるようになるのです.

サーバを動かすには、電源使用料、冷却設備、データセンタのスペース、実計算能力といったコストが掛かります.CPU のアイドル時間はそのままお金の無駄遣いです.したがって、使用率を一定に保つのはシステム管理者の責任の1つであり、継続的な管理が必要になります.これがコンテナと Kubernetes のワークフローが入り込むところです.Kubernetes は、クラスタ全体にわたってアプリケーションの分散を自動化するツールを提供し、従来型のツールを使うよりも高い使用率を実現します.

共用の Kubernetes クラスタを個人単位で使えるようになり、開発者のテスト環境をコンテナのセットとしてすばやく安価に作ることが可能になる点でも、効率性が大きく改善されます.昔は、1人の開発者にテストクラスタを1つ作るだけで、3台のマシンを起動する必要がありました.Kubernetes を使えば、テストクラスタの使用量をまとめ、ずっと少ない数のマシン上で、簡単に全開発者のテストクラスタを動かせます.使用されるマシン全体の数を減らすと、各システムの効率化を後押しすることになります.

 

まとめ

Kubernetes は、クラウド上にアプリケーションを構築し、デプロイする方法を根底から変えるために作られました.基本的に Kubernetes は、開発者にベロシティ、効率性、敏捷性を提供するためにデザインされています.