コンテナを1つデプロイするのは簡単です。10個なら管理できます。しかし、数十台のマシンにわたって数百のコンテナを運用するようになると、手動での管理は「困難」なレベルを超え、「不可能」なものになります。どのコンテナがどこで動いているのか、把握できなくなります。サーバーがダウンすれば、誰かが起きて再起動するまでアプリケーションは消滅したままです。新しいインスタンスを立ち上げる前に、トラフィックの急増がシステムを圧倒してしまいます。まさにここで、Kubernetesの出番となります。これは単なるDevOpsツールではありません。コンテナ管理をスクリプトによる作業ではなく、制御問題として扱うオーケストレーション層なのです。
なぜスクリプトは最終的に破綻するのか
ほとんどのチームは、シェルスクリプトや基本的な自動化から始めます。イメージのプル、コンテナの起動、ログの監視、失敗したプロセスの再起動といったコマンドを記述していきます。その手法は概念実証(PoC)には有効ですが、実環境の負荷がかかると崩壊します。マイクロサービスは異なるホスト間で通信し、特定の環境変数に依存し、コンテナの再起動後も維持される永続ストレージを必要とし、バージョン間での一貫したネットワークを期待します。スクリプトでは、仮想マシンが消失したときにワークロードを自動的に再スケジューリングすることはできません。クラッシュループに陥っているインスタンスを回避しながら、正常なインスタンスにネットワークトラフィックを分散させることもできません。Kubernetesは、クラスター自体にこれらの決定を委ねることで、この問題を解決します。あなたが「あるべき姿」を記述すれば、システムがその状態を継続的に維持します。
Kubernetesが提供する3つの価値
Kubernetesは、手動での火消し作業を自動化された信頼性に置き換える、3つのコア機能を提供します。
**高可用性(High availability)**とは、インフラの一部が故障してもアプリケーションがオンラインを維持できることを意味します。コンテナがクラッシュすれば、Kubernetesは数秒以内にそれを置き換えます。ワーカーノード全体がダウンした場合、スケジューラーはハートビートの消失を検知し、影響を受けるワークロードをクラスター内の他の正常なマシンへと移動させます。システムは、定義された「あるべき状態(desired state)」を常に監視し、人の手を介さずにその乖離を修正します。
**スケーラビリティ(Scalability)**とは、ユーザーの増加に合わせてアプリケーションを拡張できることを意味します。2時間のトラフィックピークを乗り切るためだけに20台のサーバーを準備する代わりに、CPU使用率やリクエストのレイテンシといった重要なメトリクスを定義し、しきい値を超えたときにクラスターにコンテナインスタンスを追加させます。需要が下がれば、レプリカ数は再び減少します。必要なときに、必要な分だけコストを支払えばよいのです。
**ディザスタリカバリ(Disaster recovery)**とは、クラッシュ後もデータと設定が復元されることを意味します。Kubernetesはクラスター全体のステートを分散型キーバリューストアに保存します。壊滅的な障害によってワーカーノードやコントロールプレーンの一部が消失しても、保存されたステートによって、システムはワークロードを構成通りに正確に再構築できます。オーケストレーターが「あるべき姿」を記憶しているため、データは戻ってくるのです。
セットアップ:脳と筋肉
Kubernetesクラスターには、脳と筋肉に例えられる2つの基本的な役割があり、その比喩は実務においても非常に的を射ています。
Master Nodeは「脳」です。顧客向けのアプリケーションを実行する場所ではありません。その代わりに、タスクのスケジューリング、クラスター状態の管理、変更への対応を行うコントロールプレーンのコンポーネントをホストします。コマンドを発行したり設定ファイルを送信したりすると、マスターノードはワークロードをどこで動かすべきか、それが正常かどうか、そして異常な場合にどう対処すべきかを決定します。
Worker Nodesは「筋肉」です。各ワーカーは、マスターと通信し、コンテナランタイムを使用して実際のPodを実行する軽量なエージェントを動作させます。これらのノードこそが、アプリケーションコードがCPUやメモリを消費する場所です。ワーカーノードを追加すれば、クラスターの生のキャパシティが増えます。冗長化されたマスターノードを追加すれば、コントロールプレーンは個々のハードウェア障害に対して耐性を持ちます。
Pods, Containers, and Services
Kubernetesを扱うには、ソフトウェアがどのようにパッケージ化され、どのようにアクセスされるかを定義する3つの用語を理解する必要があります。
Containersは、アプリケーションを依存関係、ライブラリ、設定と一緒にまとめたパッケージです。これらはソフトウェアを基盤となるホストから隔離するため、開発、ステージング、本番環境のどこでも同じように動作させることができます。
PodsはKubernetesにおける最小のデプロイ可能ユニットです。Podは、リソースを共有する必要がある1つ以上のコンテナをラップします。これらは同じネットワーク名前空間を共有し、同じローカルストレージボリュームにアクセスできます。ここで重要なのは、コンテナを単体で直接デプロイするのではなく、それを保持するPodをデプロイするということです。また、Podは意図的にエフェメラル(一時的)に設計されています。状況の変化に応じて、作成、破棄、置換が行われます。その寿命は設計上、動的です。
Servicesが存在するのは、Podが一時的なものであるためです。Podが再起動するたびに、新しい内部IPアドレスが割り当てられる可能性が高いからです。アプリケーションの他の部分がこれらの変動するアドレスに直接接続しようとすると、接続が絶えず切断されてしまいます。ServiceはPodに対して固定のIPアドレスとDNS名を提供します。Serviceは安定した「フロントドア」として機能し、セレクターに一致するすべての正常なPodに対して、入ってくるリクエストをロードバランシングします。これにより、クライアントを個々のコンテナのライフサイクルに伴う混乱から切り離すことができます。
スケールするKubernetes:Netflixの事例
Netflixは、コンテンツ配信ネットワーク(CDN)の管理にKubernetesを使用しています。このインフラストラクチャは、世界中の何百万人もの視聴者にビデオストリームを同時に配信します。人気の番組が公開されて需要が急増すると、クラスターはビデオセグメントをユーザーの近くに保存するキャッシュノードをスケールアウトします。リージョン内のノードが故障した場合、トラフィックは自動的に再ルーティングされます。その結果、エンジニアへの手動の緊急呼び出しなしに、何百万人もの人々が映画を視聴し続けることができます。オーケストレーターがスケールと障害を処理するため、サービスは中断することなく継続されます。
はじめの一歩:YAML、JSON、そしてAPI Server
Kubernetesを使い始めるということは、命令的な「クリック操作(click-ops)」を捨て、宣言的な構成を受け入れることを意味します。YAMLまたはJSONファイルに、実現したい内容を記述します。これらのマニフェストには、コンテナイメージから、レプリカ数、公開ポート、環境変数、ストレージマウントに至るまで、あらゆるものが記述されます。ファイルの準備ができたら、マスターノード上のAPI Serverに送信します。コントロールプレーンはその宣言を取り込み、クラスターの状態データベースに保存し、現実の状態を記述内容に一致させる作業を開始します。Kubernetesに対して、どのように仕事を進めるべきかを具体的に指示するわけではありません。最終的な結果がどうあるべきかを伝えれば、Kubernetesがその手順を導き出します。
真の教訓
Kubernetesには学習曲線があります。最初は用語が難解に感じられるかもしれません。多くの構成要素が動いており、分散システムのデバッグは、単一サーバーのデバッグよりも本質的に困難です。しかし、その見返りは「運用の平穏」です。個々のマシンを監視し続ける必要はなくなります。午前3時の障害発生時に、スタートアップスクリプトがうまく動くように祈る必要もなくなります。ノードは停止するものだと想定し、アプリケーションの整合性を保つためにオーケストレーターを信頼するという、「デフォルトで障害を前提とした設計」ができるようになります。「何も壊れないように願う」ことから、「システムが故障に対処できることを知っている」ことへのマインドセットの転換こそが、その努力に見合う価値なのです。
出典: What Is Kubernetes? Kubernetes Explained in 15 Mins
オプションの学習コミュニティ: GyaanSetu AI on Telegram
