Cloud Runへのデプロイ時間短縮方法の模索

に公開

はじめに

こんにちは!今年社会人2年目を迎える山﨑です。
近年、クラウドの普及によって、インフラ管理や運用でサーバーレスなサービスを利用している人も多いのではないでしょうか。
私自身も業務でCloud Runを使っています。
その中で、Cloud Runへのデプロイ手法にはどのようなものがあるのか、手法によるデプロイ時間に差異はあるのか、という疑問を持っていました。
この記事では、自分の備忘録もかねて、デプロイ手法とデプロイ時間の差異についてまとめています。

背景

  • これまでgcloud run deployコマンドでソースからデプロイしていましたが、ソースコードの軽微な修正にもかかわらず、再デプロイ完了までに初回デプロイと同程度の時間を要することが気になっていました。
  • gcluod run deployコマンドを実行すると、裏ではCloud Buildによるビルドプロセスが実行されることは知っていたため、Cloud Buildを明示的に使用するとデプロイ時間に変化があるのか気になりました。
  • また、(多分)Google Cloud Professional Cloud Developer Certificationの学習をしている際、cache-from引数を使用するとビルド時間を短縮できるということを知りました。
  • 以上を踏まえ、複数のデプロイ手法を実施・比較し、デプロイ時間を短縮するという目標を達成するためにどの手法が良いか模索します。

デプロイ手法

以下の手法でデプロイし、時間を計測します。操作はすべてCloud Shellから行います。
なお、cache-from引数ありの手法の時間については、2回目以降のビルド・デプロイ時間です。

1. gcloud run deployでソースからデプロイする
2. Dockerfileからgcloud builds submitでビルドし、gcloud run deployでイメージからデプロイする
3. cloudbuild.yamlでビルド〜デプロイまで行う
 3-1. cache-from引数なし
 3-2. cache-from引数あり
4. cloudbuild.yamlでビルド~プッシュまでを行い、gcloud run deployでデプロイする
 4-1. cache-from引数なし
 4-2. cache-from引数あり

cache-from引数に関する補足(参考

Docker イメージビルドの速度を上げる最も簡単な方法は、後続のビルドに使用できるようにキャッシュ イメージを指定することです。ビルド構成ファイルに --cache-from 引数を追加すると、キャッシュされたイメージを指定できます。これにより、Docker はこのイメージをキャッシュ ソースとしてビルドします。
Docker イメージは、スタックレイヤから構成されています。--cache-from を使用すると、変更されたレイヤからビルドの最後までのすべてのレイヤが再構築されます。したがって、Docker ビルドの初期段階でレイヤを変更する場合には、--cache-from の使用は得策ではありません。

ビルドに --cache-from を常に使用することをおすすめしますが、次の点に注意してください。

  • キャッシュから取得するには、以前にビルドした Docker イメージが必要です。
  • --cache-from は Docker ビルドにのみ使用できます。他の種類のアーティファクトを作成するビルダーには使用できません。
  • キャッシュされたイメージはレジストリから取得する必要があります。このため、ビルドにかかる時間が長くなることがあります。

補足:今回の検証でデプロイするアプリの概要

  • 言語:Python
  • フレームワーク:streamlit
  • 依存ライブラリ数:少ない
test_app/
    ├app.py
    ├cloudbuild.yaml
    ├Dockerfile
    ├.gcloudignore
    ├requirements.txt
    └run.sh #下記の時間計測コマンド実行用スクリプト

時間計測方法

以下を使うことで時間を計測します。
実行後に表示されるrealの時間をかかった時間とします。
手法2と4は、2つのgcloudコマンドを実行し、それらを合算します。

#手法1
time gcloud run deploy --source=.  --project=<PROJECT_ID>

#手法2
time gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME
time gcloud run deploy --image=<IMAGE>

#手法3
time gcloud builds submit --config cloudbuild.yaml .

#手法4
time gcloud builds submit --config cloudbuild.yaml .
time gcloud run deploy --image=<IMAGE>

結果

それぞれの手法における時間は以下の表のようになりました。
結果から以下の2点が分かりました。
1. ビルドとデプロイは分離した方が早い
2. cache-from引数を使用した方が早い

# 手法 時間 順位
1 gcloud run deployでソースからデプロイ 2m19s 4
2 Dockerfileからgcloud builds submitでビルドし、gcloud run deployでイメージからデプロイ 1m38s+18s=1m56s 2
3-1 cloudbuild.yamlでビルドからデプロイまで行う(cache-from引数なし) 3m8s 6
3-2 cloudbuild.yamlでビルドからデプロイまで行う(cache-from引数あり) 2m33s 5
4-1 cloudbuild.yamlでビルド~プッシュまでを行い、gcloud run deployでデプロイする(cache-from引数なし) 1m52s+20s=2m12s 3
4-2 cloudbuild.yamlでビルド~プッシュまでを行い、gcloud run deployでデプロイする(cache-from引数あり) 1m1s+19s=1m20s 1

気になった点

  • cloudbuild.yamlでビルドからデプロイまで行ったときに最も時間がかかったこと
  • 実質的に同じ処理を行っていそうな#1と#3-1で50秒程度、#2と#4-1で20秒弱の差があること

考察

  • Cloud Buildは一連のビルドステップを分離したコンテナ環境で実施され、各ステップの実行後にそのコンテナが破棄されます(参考)。そのため、各ステップにおけるコンテナ起動時間などの小さなオーバーヘッドの積み重ねによりデプロイ時間が最も遅くなったと考えます。
  • gcloud run deployコマンドでイメージからデプロイした場合のデプロイ単体に要した時間はいずれも20秒程度であり(結果の表#2, #4-1, #4-2)、ビルドプロセスに大半の時間を要していることがわかります。gcloud run deployコマンドではビルドプロセスを柔軟に設定することができず、キャッシュを利用するといった設定もできません。したがって、デプロイまでの時間を短縮するという私の目標を達成するためには、ビルドとデプロイを分離し、キャッシュを利用できるようにすることが求められます。

おわりに

今回6つの手法を実施して、ビルドとデプロイの分離cache-from引数によりデプロイ時間を短縮できるという結果が得られました。
今回検証した以外の手法や、より効率的なファイルの書き方を調べつつ、適したデプロイ方法を見つけたいです。
おすすめの方法があればぜひご教示お願いします。

参考

デロイトトーマツグループ エンジニアリングブログ

Discussion