6年ぶりぐらいにクラウド使った結果、Kubernetes以外のマネージドサービスとか基本要らなくない?となった話
ここ半年ぐらい、かなり久々にクラウド使ってアプリやバッチの基盤作ったりしてきて、色々と思ったことを書き捨てる。
「ちょっと検証してみた」程度のものも含めれば、AWSとGCPは一通り主要なマネージドサービスを触ったし、実際に複数のアプリやらバッチやらをマネージドサービス上で本番稼働させて今も運用してるけど、結局DB以外は基本全部Kubernetesに乗せるのが一番楽だと強く思うようになった。
Kubernetesは学習コストや運用コストがそれなりに高く付くから安易に採用するのはどうなのか、みたいな論調もあるし、つい半年前までは自分もそう思ってた。サーバレスなマネージドサービスが色々出てきているのに、なんでわざわざKubernetesクラスタなんていう設計、運用に手間のかかるクラスタリングサーバーを立てて管理しないとならんのかと。
だけど、実際にいくつかのマネージドサービス使ってアプリやバッチの開発・運用をやり、その後Kubernetesでも3つの基盤構築をやって、その上で複数のアプリやバッチの開発・運用までやってみて思ったのは、大抵のケースではKubernetesを基盤に使うのが結局一番コスパ良いんじゃないか、ってこと。
まずKubernetes(EKS、GKE等)以外のマネージドサービスを使うことの何がつらいのかを書いておきたい。むしろその愚痴を吐き捨てることをモチベーションに今これを書いている..。
AWSで言うと、LambdaとかECSとかBatchとかCloud Functionsとか、GCPだとApp EngineとかCloud Runとか他にも色々あるけど、こういうのは基本的に全部ダメだと思った。
たとえば運用するアプリケーションが1つだけ、あるいは複数あっても全部単一のマネージドサービス上で統一して管理できるんだったら良いと思う。例えばLambdaならLambda、App EngineならApp Engineといった具合に。
だけど現実には複数のアプリケーションがあり、それらの個々の要件に応じて複数のマネージドサービスを使い分け、連携させる必要があって、そうなると結局はつらいことになる。
何がつらいかというと、それぞれのマネージドサービス毎に開発環境、デプロイ方法、認証、認可、サービス連携、イベントトリガ、ロギング、環境変数やシークレットの管理等の諸々の仕様やオペレーションが当たり前だけどバラバラで、いちいち各マネージドサービス固有の仕様を理解して、それぞれのやり方で扱わないといけない。
それぞれ出来ること出来ないことがあり、向き不向きがあり、制約もある中で、ドキュメント読んで仕様理解して検証して、上述した諸々の要素を各マネージドサービス毎に詰めていくというのは結構なコストがかかる。
いざ運用フェーズに入った時に、各マネージドサービスを行き来する際の脳みその切り替えにも結構な負荷がかかる。エンハンスの際には、まず思い出すところからはじめないといけない。
LambdaにPythonのモジュール入れるのどうやるんだっけ?デプロイってどうしてたっけ?AppEngineってローカルでどうやってテストするんだっけ?とか諸々。一応ドキュメントに書き残してはいても、それを読み返してああそうだったわ、って思い出すのが億劫。
今の現場だとdevelop、testing、staging、productionと4つの環境を作ってメンテしないといけないんだけど、サービスが増えてくると必然的にインフラのコード化が必要になり、そうなるとさらにつらみが増してくる。
クラウドのプロビジョニングツールといえばTerraform、Terraform使えば楽勝でしょ、という浅い考えで割と初期の頃からインフラのコード化は手を付けてたけど、これが思った以上につらい。日に日につらみが増していく。
例えばAWS上で複数のマネージドサービスを組み合わせてサービスを構成する場合、AWSの各リソースを全て個別に定義し、さらにそれらをどう紐付けるかを不整合無く定義することで、個々のリソースで構成されたサービスをAWS上に展開出来る。
「全てのリソースを個別に定義して、それらの紐付けを不整合無く定義する」ってのが中々ダルくて、定義ファイルが無駄に膨らんでいくし、リソースやマネージドサービス毎に全然違う書式で定義しないといけない。
しかもTerraformの定義を適用(apply)するのにめっちゃ時間かかるから、トライアンドエラーが高速に回せなくて、些細な修正かけるのに色々いじくり回してたら一日が終わってた、みたいな虚しいことが起こる。
この辺は自分のTerraform力の低さの問題かもしれないけど、とりあえずKubernetes使っておけば前述してきた問題の多くをKubernetesが間に入って吸収してくれる。
そもそもこのご時世、コンテナをそのまま動かせないマネージドサービスはその時点でかなり微妙だと思うんだよね。いや、はっきり言って終わってると思う。
とはいえコンテナのマネージドな実行基盤として普及してるECSにしろAWS BatchにしろApp Engine(Flexible)にしろ、コンテナを動かすための前提条件や制約や独自仕様が多過ぎるし、期待してたCloud Runもメモリ2GB、タイムアウトが最大15分という制約があって、特定のワークロードでしか使えない。
そうなると結局はプロビジョニングの面倒臭さという問題にぶち当たる。
Kubernetesが他のマネージドサービスと決定的に違うのは、他のマネージドサービスが「クラウドがOSSを隠蔽して楽に使えるようにしてくれるもの」であるのに対し、Kubernetesは「OSS(Kubernetes)がクラウドを隠蔽してくれるもの」であるという点。
Kubernetesがクラウド(内の各種リソース)よりもメタにあるというのがめちゃくちゃ重要で、それによってクラウドベンダ間の差異やら、リソース間の紐付けやら依存関係やらの面倒をKubernetesがかなり吸収してくれる。
AWSの個々のリソースを作って紐付けるってのが面倒なわけだけど、KubernetesはKubernetesリソースが媒介になってAWSのリソースを抽象化してくれるので、それだけで大分プロビジョニングの負担が軽減される。
クラウド上のインフラとアプリケーションを同等のリソースとしてyamlで定義して、構築、デプロイが出来る。例えばIngressリソースをyamlで定義してapplyすれば、自動でセキュリティグループ(ファイアーウォール)やALBを作成して紐付けてくれる。
そしてプロビジョニングもめっちゃ速い。Terraformのapplyなんて二度とやりたくなくなった。最近はKubernetesに出来ることは全てKubernetesに任せて、それ以外のことは手順化してマニュアルでやる、みたいな割り切りをするようになった。
環境変数や認証情報の設定や読み込みも超楽。
Kubernetes上に乗せるアプリは全部同じyamlの書式で定義して管理すれば良いので、アプリ間をまたぐ際の脳みそのスイッチングコストも最小限で済む。
kubectlコマンドのいくつかのパターンを覚えておけば、全てのアプリに対して同じコマンドで確認や操作が出来る。コンテナとの距離感が近くて、普通にローカルでDocker操作してるのとさして変わらない操作感。
あとはバッチにもAPIにもワークフローにも使えるし、大抵のワークロードに対応出来る。リソースも自由に確保出来る。
唯一、DBやデータストレージだけはマネージドサービスを使って連携させる必要があるけど、これらもそう遠くない先にKubernetesリソースによって抽象化されると思う。多くのユーザーが欲するものはいずれ実装される宿命にある。
とりあえず自分が言いたいことは、AWSはECSなんていう未来の無い独自仕様のコンテナ実行基盤なんかさっさと廃棄して、EKSに開発リソース全振りしろや、ってこと。普通にFargate for EKSのログをCloud Watchに連携出来ないの困るんですけど。
最近はクラウドネイティブなんていう考え方がもてはやされてるけど、CNCFはあんな回りくどい定義をしないで、もっと具体的に「クラウドネイティブとはKubernetesのことだ!!黙ってKubernetes使え!!」って宣言した方が良いんじゃないか。