この記事は、Itamar Turner-Trauring氏によって2020年3月に公開された「“Let’s use Kubernetes!” Now you have 8 problems」の翻訳転載です。著者の許可を得て配信しています。
Dockerを使用している場合、その次にKubernetes、別名K8sを使うのが自然な流れのようです。これが本番環境での実行方法ですよね?
まあ、おそらくそうでしょう。同じアプリケーションで作業する500人のソフトウェアエンジニア向けに設計されたソリューションは、50人のソフトウェアエンジニア向けのソリューションとはまったく異なります。 また、どちらも5人のチーム向けに設計されたソリューションとも全く違うものです。
自分が小さなチームに所属している場合、Kubernetesはおそらくそういう小さい規模のチームには向いていないでしょう。非常に扱いが難しく、メリットはほとんどないからです。
ではその理由を説明しましょう。
##誰もが動くパーツが大好き
Kubernetesには、コンセプト、サブシステム、プロセス、マシン、コードなど…多くの可動部品があり、それは同時に多くの問題があることを意味します。
###複数のマシン
Kubernetesは分散システムです。ワーカーマシンを制御するメインマシンがあります。 作業は異なるワーカーマシン全体でスケジュールされます。 その後、各マシンはコンテナで作業を実行します。
何かを成し遂げるために、2台のマシンまたは仮想マシンについて話しています。それなのに、あなたには…1台のマシンしかありません。 スケールする場合(ここが重要なポイントです)、3〜4台、もしくは17台のVMが必要です。
###ものすごい大量のコード
2020年3月初旬の時点で、Kubernetesコードベースには、58万行を超えるGoコードがあります。 これは実際のコードであり、コメントや空白行はカウントせず、ベンダーが提供するパッケージもカウントしません。 2019年のセキュリティレビューでは、コードベースについて次のように説明しています。
「…Kubernetesコードベースには、改善の余地があります。 コードベースは大きく複雑であり、Kubernetesの外部システムを含む最小限のドキュメンテーションと多数のディペンデンシーを含むコードの大きなセクションがあります。 コードベース内のロジックの再実装をするケースが数多くあります。このコードベースは、サポートライブラリに一元化されていて、複雑さが緩和され、パッチの適用を容易にし、コードベースの異なる領域にわたるドキュメンテーションの負担を減らします。」
公平に見ると、これは多くの大規模プロジェクトと違いはありません。そのコードはすべて、アプリケーションが壊れないときに作業する必要があるものです。
###アーキテクチャの複雑さ、オペレーションの複雑さ、コンフィグレーションの複雑さ、コンセプトの複雑さ
Kubernetesは、多くの様々なサービス、システム、および部品を備えた複雑なシステムです。
単一のアプリケーションを実行する前に、次に示しているような高度に簡素化されたアーキテクチャが必要です(Kubernetesドキュメントの元のソース):
K8sドキュメンテーションの概念ドキュメンテーションには、次の行に沿った多くの教育に関するメッセージが含まれています。
Kubernetesでは、EndpointSliceにはネットワークエンドポイントのセットへの参照が含まれています。 セレクターが指定されると、EndpointSliceコントローラーはKubernetesサービスのEndpointSlicesを自動的に作成します。 これらのEndpointSlicesには、サービスセレクターに一致するポッドへの参照が含まれます。 EndpointSlicesは、ユニークなサービスとポートの組み合わせによってネットワークエンドポイントをグループ化します。
デフォルトでは、EndpointSliceコントローラーによって管理されるEndpointSlicesには、それぞれ100以下のエンドポイントがあります。 このスケールを下回ると、EndpointSlicesはエンドポイントおよびサービスと1:1でマッピングされ、同様のパフォーマンスを発揮します。
実際にはある程度それを理解していますが、いくつのコンセプトが必要か気付きました。EndpointSlice、Service、selector、Pod、Endpointの概念です。
もちろん、ほとんどの場合、これらの機能のほとんどは必要ありませんが、ほとんどの場合Kubernetesもまったく必要ありません。
別のランダムセレクション:
デフォルトでは、ClusterIPまたはNodePortサービスに送信されたトラフィックは、サービスのバックエンドアドレスにルーティングされます。 Kubernetes 1.7以降、「外部」トラフィックを トラフィックを受信したノードで実行されているPodにルーティングできていましたが、これはClusterIPサービスではサポートされておらず、ゾーンルーティングなどのより複雑なトポロジは不可能です。 サービストポロジ機能は、サービス作成者が発信元ノードと宛先ノードのノードラベルに基づいてトラフィックをルーティングするためのポリシーを設定できるようにすることで、これをリゾルブします。
先ほど述べたセキュリティレビューの内容は次のとおりです。
「Kubernetesは、オペレーションが非常に複雑な大規模システムです。 評価チームは、Kubernetesのコンフィグレーションとデプロイメントが重要であると認識しており、特定のコンポーネントは、複雑なデフォルト設定になっており、オペレーションコントロールが不可能で、また暗黙的に設定されたセキュリティコントロールを備えています。」
###開発の複雑さ
Kubernetesを信用すればするほど、通常の開発は難しくなります。コードを実行するには、さまざまなコンセプト(Pod、Deployment、Serviceなど)が必要です。 したがって、VMまたはネストされたDockerコンテナを介して、テストするためだけに完全なK8sシステムを起動する必要があります。
また、アプリケーションはローカルで実行するのが大変難しいため、開発がより難しくなり、ステージング環境からローカルプロセスをクラスターにプロキシする(数年前にこのツールを作成しました)、リモートプロセスをローカルマシンにプロキシするなど、さまざまなソリューションにつながります。
不完全な解決策はたくさんあります。 ただ最もシンプルで最適なソリューションは、Kubernetesを使用しないことです。
###マイクロサービス(これはよくないアイデアです)
二次的な問題は、多くのサービスを実行できるこのシステムがあることが原因になって、ついつい多くのサービスを書いてしまうということが頻繁にあることです。 これは悪い考えです。
分散アプリケーションは、正確に書くのが非常に難しいものです。本当にとても難しいんです。可動パーツが多いほど、これらのよりたくさん問題が発生します。
**分散アプリケーションはデバッグが困難です。**モノリシックなアプリケーションのログから得られるものほど良くないという理解をするには、まったく新しいカテゴリのインストルメンテーションとロギングが必要です。
マイクロサービスは組織のスケーリング技術です。1つのライブWebサイトで500人の開発者が作業している時に、もし開発者チームが独立して作業できるとしたら、大規模な分散システムに対する経費を支払うことは理にかなっています。 したがって、5人の開発者からなる各チームに単一のマイクロサービスを与え、そのチームは残りのマイクロサービスが信頼できない外部サービスであるというようにしておくのです。
自分が5人のチームで、20のマイクロサービスがあり、分散システムに対する高いニーズがない場合、そのやり方は間違っています。 大企業のようにサービスあたりのチームが5人ではなく、自分の会社のサービスあたりの人数は0.25人なのですから。
##でも、便利じゃない?
###スケーリング
Kubernetesは、大規模に拡張する必要がある場合には役立ちます。それでは、いくつかの選択肢を考えてみましょう。
- 最大416個のvCPUと8TiB RAMを搭載したクラウドVMを取得できます。これは、本当にありえないくらいの規模です。そうです!もちろん、かなり高価ですが、シンプルです。
- Herokuなどのサービスを使用すると、たくさんのシンプルなWebアプリケーションを非常に簡単にスケーリングできます。
もちろん、これは、社員を増やすことで実際に何らかのメリットがあることが前提になっています。
- ほとんどのアプリケーションは、そこまで拡張する必要はありません。 合理的な最適化で十分です。
- Webアプリケーションのスケーリングは、通常、Webワーカーではなくデータベースによるボトルネックがほとんどです。
###信頼性
可動パーツが増えると、エラーが発生確率が上がります。
Kubernetesが提供する信頼性(ヘルスチェック、ローリングデプロイ)の機能は、ものすごく簡単に実装できますが、既に組み込まれている場合も多くあります。例えば、nginxはworkerプロセスのヘルスチェックを実行できます。また、docker-autohealなどを使用して、これらのプロセスを自動的に再起動することもできます。
ダウンタイムが気になる場合、「どのようにデプロイのダウンタイムを1秒から1ミリ秒に減らすか」ではなく、「失敗をしてしまった場合にデータベーススキーマの変更が確実にロールバックを阻止するにはどうしたらよいか?」 を考えるべきです。
また、単一のマシンを使用せずに信頼できるWebワーカーを障害点にする場合には、Kubernetesを使用しないやり方もたくさんあります。
##ではベストプラクティスは何?
一般的にベストプラクティスなどはありません。 確かに特定の状況に対するベストプラクティスはあります。人気があって、今はやっているからという理由だけで、それがあなたにとって最善の選択になるということはありません。
状況によっては、Kubernetesは本当に素晴らしいツールです。しかし、Kubernetesがただの時間の無駄になりKubernetesを使っても何のメリットもないという人も中にはいます。
非常に複雑なものが本当に必要な場合を除き、単一のマシンでのDocker Compose、オーケストレーションのためのHashicorpのNomad、Herokuやそれに似たシステム、コンピューティングパイプライン用のSnakemakeなど、さまざまなツールがあります。