ラベル Docker の投稿を表示しています。 すべての投稿を表示
ラベル Docker の投稿を表示しています。 すべての投稿を表示

2025/08/25

Docker+Kubernetesでいいの?

動機

 前スレの『さくらのクラウドとサーバレスアーキテクチャ』で書いた以下について説明不足と感じたので、ここで詳しく書いておこうと思います。

「クラウドに移行したもののランニングコストが予測よりずっと高く、期待したように下がらない」という話を時々聞きます。

自治体システム標準化、ガバクラ移行で運用コスト2~4倍に悲鳴「議会に通らない」(有料記事ですが1ページ目のみ無料で閲覧可能)

 ガバメントクラウド移行で自治体の年間コストが5.7倍に…計画の重要性

 ガバメントクラウド移行で自治体の運用コストは本当に下がるのか?

上記の引用はガバメントクラウドに関するものですが、過去に私が関わった民間企業のwebアプリケーションでも同様の現象が起きていました。この企業で使っていたのもKubernetes(GKE)ですが、「思うようにスケーリングできない」ので無駄にリソースを割り当ててアプリケーションを実行しているという状況でした。


問題点

クラウド上に実装されたアプリケーションで「Dockerコンテナに突っ込んでKubernetesでオーケストレーション」という作りをよく見ますが、webアプリケーションでこれが有効なケースは、実際には一部に限られます。

実際にはこの構成でwebアプリケーションを実装すると、以下の問題が発生します。

  • オートスケールを設定しているのに、リクエストの急増でサーバビジーが発生する。
  • (上記のように)運用コストが高いケースがある。


原因

クラウドがオンプレミス/レンタルサーバに比べて有利になる要因は、スケーリングの恩恵によるところが大きくなっています。

従来(オンプレミス/レンタルサーバ)では、あらかじめ契約により用意したリソースの中で、それを有効活用できるようにユーザがやりくりしていました。確保されるリソースは契約で変更するのが前提なので、迅速な変更はできず、これがリソースの無駄の原因となっていました。

対するクラウドでは、複数のプロジェクト(これには他人のプロジェクトも含みます)にまたがってデータセンター全体の中で、リアルタイムでリソースの割り当てを変更することで、リソースの無駄を削減します。必要なものを、必要な時に、必要なだけ確保します。ここが従来と最も異なる点です。無駄がなくなることによって運用コストが下げられます。


ここまでならKubernetesによるオートスケールでも実現できそうに感じるのですが、実際には一般的なwebアプリケーションでは、そう思いどおりにならないケースが多いようです。


一般的なwebアプリケーションではエンドユーザの操作に従ってクライアントからリクエストが送信され、サーバがそれに答えます。この間はエンドユーザが待っているので短い方が好ましく、一般的には1秒以下、瞬間的に遅くなっても3秒程度が限度とされます。

Kubernetesによるオートスケールはデフォルトでは30秒ごとにCPU負荷を監視して、Pod/ノードをスケーリングします。そのため負荷の変化が起きてからでないとスケーリングは始まりません。負荷を急増させるリクエストがあっても、そのリクエストはすでに処理を開始した後なので、スケーリングの恩恵を受けられません。

またwebアプリケーションのリクエストの一般的な処理時間に比べて、Kubernetesによる負荷監視の間隔はあまりに長いので、適切な監視およびスケーリングを行いきれません。監視間隔を短くすれば改善できるでしょうが、CPU負荷の測定そのものがコンテナに負荷をかけるので、短いのも悪影響があります。

さらにPodの水平スケールは秒単位で終わりますが、ノードのスケールは分単位で時間がかかります。これだけ長いとエンドユーザは待ってくれません。


つまりKubernetesでのオートスケールが有効なのは、リソース要求の変化が比較的ゆっくり(分単位かそれ以上)の場合です。急激に変化する場合は追従しきれず、サーバビジーを発生する原因となります。


解決策

解決策の構成の1つが以下です。

webサーバのオートスケールのコントロールをKubernetesではなく、Knativeで行うことで改善が期待できます。KnativeはKubernetesに替えてサーバレスアーキテクチャに基づいてスケーリングを行います。
webサーバの場合はリクエストはイベントとして処理され、リクエスト数がスケーリング指標となるので、CPU負荷に頼らずスケーリングが可能です。リクエストがプラットフォームに届いた時点でスケールアウトの必要性が判断され実行されるので、スケールアウトの要因となったリクエストもスケーリングの恩恵を受けられます。そのためサーバビジーは発生しにくくなります。
またCPU負荷監視の間隔がスケーリングに与える影響が少なくなり、負荷の変化に対して迅速なスケーリングが可能となります。これによってリソースの無駄がなくなり、運用コストを削減できます。

Knativeを利用したApp EngineやCloud Runサービスを長年使ってますが、ノードのスケールアウトに相当するケースに遭遇したことがありません。ノードについてはプラットフォーム側である程度プールしているものと推測されます。ノードのスケールインは観測できないので、いつ起きているのか不明です。

またKnativeには、複雑なKubernetesの設定を簡略化してくれるという側面もあります。

設計

ユーザが自分でKnativeを組み込むことはまずなく、一般的にはすでにKnativeが組み込まれたPaaSを利用します。Google Cloudでは以下が該当します。

Knativeによるサーバレスアーキテクチャでの実装については、アプリケーション(=コンテナへの分割の仕方、コンテナの中身)の設計・実装も従来とは変える必要があります。これはモノシリック構成に替えてマイクロサービス化する程度では対応できません。スケーリングがいつ起きてどこに影響するのかを考慮する必要があります。
具体的にどうすればいいのかは、長くなるのでまた別の記事で。(書くかもしれませんが書かないかもしれません)

例外

論理的に、アクティブユーザ(=同時接続していて操作しているユーザ)が十分多い大規模アプリケーションの場合、各ユーザの操作が平均化されて極端なリクエストの変化が起きにくくなる可能性があります。このような場合はKubernetesによる緩慢なスケーリングでも十分となります。
しかしこれに該当するには相当な規模のアクティブユーザ数が必要なようです。具体的にどの程度の規模が必要かを知るには、私自身もこの業界もまだ経験が足りないようです。toBの規模ではないと想像しています。toCでは「何時から開始」のようなサービスを提供するケースで、緩慢なスケーリングでは一時的に対応できなくなる可能性が高くなります。
またどのようなサービスでも最初は小規模から始まるものなので、ある程度の規模がないと効果がないKubernetesよりKnativeのほうが、損失を抑えながらサービスを立ち上げることができるという利点もあります。

またイベントドリブンではなく、要件やアプリケーションの仕様(操作方法)の工夫によってスケーリングの要求を緩慢なものにできるアプリケーションでは、Kubernetesで十分な性能を発揮できることがあると思われます。

まとめ

以下はwebアプリケーション、正確に言えばその中でも、エンドユーザからのリクエストを処理するフロントエンドを構成するwebサーバに限った話です。

コンテナの中身については、クラウド以前の古い設計・実装のままでも機能的には動くかもしれませんが、それではKubernetesにせよKnativeにせよ、性能面でクラウドが能力を発揮することはまずないでしょう。
オーケストレーションについては、ここで最適なのはKubernetesではなく、Knativeです。クラウドと同時に登場したサーバレスアーキテクチャこそが、イベントドリブンの場合の本来の使い方だと言えます。

最後に

「従来の設計・実装のままDockerコンテナに突っ込んでKubernetesでオーケストレーション」という例が未だになくならないのは、クラウドの使い方を理解している人が少ないだけでなく、仕事を受注してお金を稼げればいいだけの意識の低い受託開発業者が多く、発注側もこのような技術面での認識が出来ていないということだと思います。
もう少し踏み込んでモノシリックな構成から脱却しマイクロサービスアーキテクチャを取り入れているケースや、DDD(ドメイン駆動設計)を取り入れているケースもあります。これらはコンテナの使い方を意識したものと思われますが、スケーリングを考慮しないならクラウドでの効果は限定的です。またコンテナの分割の仕方によっては逆効果となる可能性もあります。

営利目的のサービスの場合は、多少運用コストが高くても売り上げを増やせば利益を確保できます。しかし行政のような直接売り上げを生み出さないアプリケーションの場合、運用コストの増大は危機的な悪影響となります。まして行政の場合は潜在ユーザは多いもののアクティブユーザは僅かと考えられますので、事実上有望な選択肢はサーバレスアーキテクチャの一択となります。

2025/07/18

さくらのクラウドとサーバレスアーキテクチャ

さくらのクラウドの注目記事

 私が現在利用しているクラウドはGoogle Cloudのみですが、その他には国産クラウドである「さくらのクラウド」にも興味を持っています。現在ガバメントクラウド認定を目指して整備が進められているさくらのクラウドですが、そのアプリケーション実行基盤である「AppRun」はサーバレスであることが発表されています。

さくらインターネット、アプリケーション実行基盤「AppRun β版」にて製品版のトライアルを開始

さくらのクラウド、コンテナをサーバレスで実行する「AppRun」製品版トライアルを開始。トライアル中は全機能が無料に


サーバレスアーキテクチャとは

2008年のApp Engineリリースから使えるようになったものなので、まだご存じない技術者も見かけます。理解が簡単ではないので、普及はこれからといった印象です。またFaaS(Function as a Service)と混同しやすいので注意が必要です。


サーバレスアーキテクチャは、このブログの記事「サーバレスアーキテクチャ」でも説明しています。コンピューティングにおいては、アプリケーションの実行インスタンスは常に起動しているわけではなく、必要な時に必要な分だけのリソースを割り当ててアプリケーションの実行を行うアーキテクチャです。リソースの管理はプラットフォームがやってくれるので、ユーザは意識する必要がありません。

サーバレス アーキテクチャとは

サーバーレス・コンピューティングとは

クラウド以前の従来のサーバは想定された利用状況に応じてあらかじめリソースを割り当てておきます。リソースの管理は、夜間など利用の少ない時間帯にバッチ処理を走らせるなど、計画的で柔軟性はありません。

クラウドでも非サーバレス場合は、最低1つ以上の実行インスタンスが常に割り当てられます。夜間バッチの実装など従来と変わらない設計が主流です。

それに対してサーバレスアーキテクチャでは、リアルタイムで必要なだけリソースを割り当て/開放します。これによりランニングコストの低減や、サーバビジーによる一時的なサービス提供不能の発生低減が期待できます。これはユーザにとって大きなメリットとなります。


しかしクラウドベンダー目線で考えると、上記とは違う特徴を実現することが目的ではないかと考えられます。

リアルタイムにリソース割り当てを変更できることから、データセンター全体でリソースを有効利用できるようになります。またリソースの割り当ては基本的に永続的ではなくなるので、ハードウェアのメンテナンスをしやすくなる(ユーザにとってもメンテナンスの影響を受けにくくなる)利点も考えられます。


「みんなのクラウド」と表現されることがありますが、データセンターのリソースをユーザみんなで共有し、その割り当てをより柔軟にして(非サーバレス以上の)最大限の効果を狙うのがサーバレスアーキテクチャであると言えると思います。


サーバレスアーキテクチャの現状

現在の日本のwebアプリケーションは、まだサーバレスアーキテクチャを採用したものは少ないように見えます。キーワードとしてKubernetesが出てくるアプリケーションは、サーバレスアーキテクチャではありません。それどころかクラウドに最適化されていなくて従来の延長線上でしかないものもあるようです。

現在クラウドの利用方法の主流は、Docker+Kubernetesの構成と思われます。この構成が流行った要因は以下のようなものと考えられます。

  • どのクラウドベンダーでも同じように実装でき、ベンダーロックインが発生しない。これは特に受託開発やSESにとって好都合。
  • クラウド以前の従来の技術・知識・プロダクト(ライブラリ、フレームワーク)を使いまわせる。新たに覚えるべきことはDockerとKubernetesのみ。
  • Kubernetesによって一応スケーリングも可能なので、スケーリングの恩恵も得られる。
主に開発者の都合が中心です。ひどい場合はDockerコンテナにクラウド以前のレガシーな構成をそのまま詰め込んだだけのケースもありそうです。Kubernetesでスケーリングさせているつもりが、その効果さえ確認していないケースもあるようです。クラウドに最適化しないのであれば、クラウドによる恩恵も最低限しか受けられません。


サーバレスアーキテクチャではコンテナオーケストレーションにはKubernetesではなく、Knative(あるいは相当のもの)を用います。


ランニングコストについて

「クラウドに移行したもののランニングコストが予測よりずっと高く、期待したように下がらない」という話を時々聞きます。

自治体システム標準化、ガバクラ移行で運用コスト2~4倍に悲鳴「議会に通らない」(有料記事ですが1ページ目のみ無料で閲覧可能)

 ガバメントクラウド移行で自治体の年間コストが5.7倍に…計画の重要性

 ガバメントクラウド移行で自治体の運用コストは本当に下がるのか?


上記の引用はガバメントクラウドに関するものですが、過去に私が関わった民間企業のwebアプリケーションでも同様の現象が起きていました。この企業で使っていたのもKubernetes(GKE)ですが、「思うようにスケーリングできない」ので無駄にリソースを割り当ててアプリケーションを実行しているという状況でした。

他の原因の1つは、クラウド以前の従来のアーキテクチャを引きずったまま移行していることにあるのではないかと考えられます。クラウドに最適化しないのであれば、クラウドに乗り換える効果も限定的でしかないのは想像に難しくありません。


その他にも、従来の手作業・紙ベースの手順をそのままにしておくことを優先したため、コンピュータ処理に適さない手順を無理やり実装したことによる弊害もあると考えられます。これは今に始まったことではなく、クラウドやアーキテクチャによるものでもない別次元の話なので、本記事ではこれ以上取り上げません。


サーバレスアーキテクチャでの実装

実際にサーバレスアーキテクチャで実装するには、対応するPaaSのプロダクトを利用することになります。しかしそれだけでは実装後に以下のような性能上の問題が発生することがあります。

  • レスポンスが悪い、または悪くなることがある。
  • バッチ処理などバックエンドの処理に時間がかかる。
  • ランニングコストが下がらない。
    (使い方を間違うと効果は得られない)
  • コストの予測が困難。
    (スケーリングする限り非サーバレスでも同じだが、より変化が大きい)


サーバレスアーキテクチャを有効に使いこなすためには、それに対応した設計が必要となります。ここでのノウハウにはサーバレスアーキテクチャを実装した経験からしか得られないものもあります。具体的にここで書ききれる量ではないので別の機会に。

しかしサーバレスアーキテクチャを使いこなせば、スケーリングを最大限に活用できて以下の効果を得られる可能性があります。

  • ランニングコストの削減。
  • サーバビジーによる一時的なサービス不可の減少。


技術的課題

従来のサーバは「起動しておいて必要とされるのを待つ」思想で実装されています。しかしサーバレスアーキテクチャでは「必要とされたから起動する」という思想に変わります。そのためwebサーバのような「ユーザが待っている」ケースでは、起動の遅い実装はユーザを待たせる悪いユーザエクスペリエンスにつながります。バックエンドのような起動の遅延が影響しないケースでは無視できます。

これにより従来のプロダクト(サーバレスアーキテクチャを考量していないライブラリやフレームワーク)が使い物にならなくなっているケースがあります。フレームワークの場合はそれを理解せず使用してしまうと、ほぼすべて再実装でしか改善できないほどの影響も考えられます。たとえ人気で過去に実績もあるプロダクトといえど、サーバレスアーキテクチャを考量してなくて悪影響となるものは、早めに清く捨て去る必要があります。

この思想の違いは開発者にとっては、パラダイムシフトとも言えるほどの影響です。これはサーバレスアーキテクチャの理解や使いこなしを難しくしています。


またクラウドベンダーにより対応の方法がバラバラです。簡単にサーバレスアーキテクチャへの対応をまとめると、以下のようになります。

  • Google Cloud
    • App Engine(Standard Environment):独自コンテナ+Knative、webサーバ。
    • Cloud Run:Docker+Knative。
      • Service:webサーバ。
      • Function:FaaSとしての利用形態で実態はServiceと同じ。
    • GKE + Knative serving:もうCloud Runでよくない?
  • AWS:Serverless Application Modelに基づいてLambdaで実装。
  • Azure:Azure Functionsを利用。
  • さくらのクラウド
    • AppRun:Docker+Knative

そのほかにIBM、Oracleも対応しているようです。

AWS, AzureはFaaS(Function as a Service)の流用にとどまっており、あまりサーバレスアーキテクチャの採用に関して積極的に見えません。

Google CloudはFaaSだけでなくPaaSも用意されており、対応が最も進んでいます。またwebサーバでなくバッチ処理でも同じように使えるプロダクト(Batch, Cloud Run Job)が用意されいます。これらは本来サーバでないのでサーバレスアーキテクチャと呼びませんが、「必要な時に必要な分だけ」リソースを使うことができる点においては同じです。


さくらのクラウドに対する期待

さくらのクラウドでは今後はサーバレスアーキテクチャが普及していくものと予測しているそうです。これは私も同意見で、世の中の技術者たちがサーバレスアーキテクチャの理解を進め、普及していくように活動しています。


2025/06/03

Container RegistryからArtifact Registryへの変更の影響

動機

 少し古い話ですが、Container Registryは2025/3くらいから徐々に停止しています。プロダクトによって具体的な停止のタイミングはいくらか異なるようです。これに伴いContainer Registry→Artifact Registryへの移行が必須となるのですが、この移行により思わぬ影響があったので、ここに記しておきます。


手順

移行は「Container Registry から Artifact Registry に自動的に移行する」による自動移行ではなく、「標準リポジトリへの移行」に従って手作業で移行しています。具体的に変わるのは、Cloud Buildによるコンテナのレジストリへの保存や、レジストリから取り出してCloud Runにデプロイする部分のみだと認識していました。

実際のコマンドだと以下のようになります。

Container Registry

gcloud builds submit --tag gcr.io/プロジェクト名/イメージ名

gcloud run deploy apply --image gcr.io/プロジェクト名/イメージ名 --region=リージョン名

 

Artifact Registry

gcloud builds submit . --pack image=リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名

gcloud run deploy apply --image リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名 --region=リージョン名


その他のソースなどは変更不要の認識です。


現象

ところがCloud Runでデプロイしたイメージを実行してみると、動作が違います。ソースとログから解析して、環境変数がなくなっていると判断しました。
Container Registryを使っていたころの該当環境変数は、以下のような感じでDockerfileで指定していました。

ENV 環境変数名 値の文字列


Artifact RegistryだとDockerfileの環境変数は反映されない様子です。


対処

DockerfileをあきらめてgcloudコマンドでCloud Runにデプロイする際に環境変数を指定することにしました。これはContainer Registryでも実績がある方法です。
実際の指定は以下のような感じ。
gcloud run deploy apply --image リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名 --set-env-vars="環境変数名=値の文字列" --region=リージョン名


これで解決しました。 

ちなみに、複数の環境変数を定義したい場合、"--set-env-vars"の値をコンマで区切って並べます。こんな感じ。

--set-env-vars="環境変数名1=値の文字列1","環境変数名2=値の文字列2"

 

2024/02/29

Cloud Runのインスタンス起動時間

 動機

Cloud Runのドキュメント「実行環境について」については以下の記述があります。
第 2 世代の実行環境は、一般に持続的な負荷の下では迅速に動作しますが、ほとんどのサービスでは、第 1 世代よりもコールド スタート時間が長くなります。
このように書かれると、第1世代/第2世代ともどの程度インスタンスの起動時間がかかるのか、どの程度違うのか気になります。また第2世代のジョブはバックグラウンドで動作するものなので起動時間はあまり気にされるものではありませんが、これも知りたくなってきます。
実行速度は目的によって測定方法も変えることになるので面倒ですが、インスタンスの起動時間については過去の記事「GAEのインスタンス起動時間」「GAEのインスタンス起動時間 #2」と同様に測定できますので測ってみました。


測定方法・条件

今回はCloud Runなので言語やランタイムのバージョンについては、使う人がDockerコンテナを作る際にいいようにすればいいだけの話です。なので純粋にCloud Runのインスタンス起動時間として、Hello World相当のGoでリクエスト→処理開始までを測ることにします。
  • リージョン : 大阪
  • ネットワーク : NTT Flets光 隼、実効300Mbps程度
  • サービス : 
    • ブラウザからAjaxでリクエストし、JavaScriptでレスポンスが返るまでの時間を測定。
    • スピンアップあり/なしの2パターンで、それぞれ10回測定し、平均値を算出。
    • 前記2パターンの差から、インスタンス起動時間を計算。
  • ジョブ : 
    • GAEからジョブを起動し、GAE/Cloud Runそれぞれに仕込んだログから、インスタンス起動時間を測定。
    • スピンアップは毎回行われるのでサービスのような「スピンアップなし」に該当するパターンは無いはず。念のため検証目的で、前回起動から15分以上時間空けてをスピンアップあり相当、前回起動から時間空けずにをスピンアップなし相当として、2パターンでそれぞれ10回測定し、平均値を算出。

測定結果

単位はすべてmsです。測定結果をtableにするのが面倒だったので、今回もExcelのキャプチャ画像です。

スピンアップあり。

スピンアップなし。

そしてインスタンス起動時間。

第1世代第2世代
serviceservicejob
158.7452.59344.4


まとめ


Cloud Runの世代間

公式ドキュメントの記載どおり、インスタンス起動時間は第1世代のほうが速いという結果です。
ジョブの起動時間はおおむね10秒程度でした。ちなみにジョブ終了→GAEで終了を検知も、おおむね10秒程度でした。

GAEとの比較

GAEのインスタンス起動時間 #2」と比較してみるとCloud Runは全体的に遅く、第2世代のサービスだとGAEの素のJavaよりいいくらいになっています。
本稿の趣旨からちょっと外れますが、スピンアップなしのケースではGoだろうがJavaだろうがほぼ確実に100msを切れるGAEに対して、Cloud Runだと3倍程度のレイテンシが発生しています。Webフロントエンド専用のプロダクトとしてgVisorという独自コンテナ技術まで作っただけあって面目躍如といったところで、汎用のDockerコンテナを利用するCloud Runは一歩及びません。

GoのコードはそのままでGAE/Goに実装したRESTful APIを、Cloud Runサービス/Goに変えたところ、ちょっともっさりするようになった気がした経験があります。これは気のせいではなかったと改めて認識しました。
Firebase Hostingには動的コンテンツをCloud Runで配信する機能「Cloud Run を使用した動的コンテンツの配信とマイクロサービスのホスティング」があるのですが、今回の結果を見ると、App Engineにも対応してほしいと思います。