Cloud Runにローカルから一発デプロイできる魔法のオプションを試してみた


はじめに

この記事は、「Google Cloud Platform Advent Calendar 2020」の23日目の記事です。

Cloud Runのgcloud run deployコマンドについ先日--sourceオプションがベータ版に追加されたということでdocを読んでると、こいつがかなり強力そうだったので試し&中身を追ってみました。

release note : https://cloud.google.com/run/docs/release-notes#December_16_2020
docs : https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy#--source

TL;DR

ローカルでgcloud run deploy --source一発で本当にリリースできた

--sourceオプションでやってることは実は意外とシンプル
└ ソースコードをgcsに圧縮して上げて、buildpacksを用いてランタイム検出してイメージを作成、デプロイ

--sourceオプションとは

今まではGCRに上がっているイメージを--imageオプションを指定することでcliでデプロイできていました。
GCRに上げるには別途コマンドを用意する必要がありました。

--sourceオプションとはこれら全てを取っ払い、デプロイしたいローカルのパスを指定するだけでCloud Runにデプロイしてくれるというものです。

...

そう、GCRに上げる手間が無いので、今まで秘伝のタレのごとく使い回していた.circleci/config.ymlに記載してるCDジョブから開放されます!!

試してみる

さっそくやってみましょう

サービス作成

とりあえず、Cloud Runをコンソールから作成します

コンソールから作成する際、イメージの指定が必須だったため、gcr.io/cloudrun/helloを使用しました

疎通確認できました

簡単なhttpサーバ作成

超ミニマムなhttpサーバ作成しました

main.go
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

ただhello worldと出てくるだけです。
Cloud Runがデフォルトで8080開けてたのでこちらも8080開けときます。

いざ実践

❯ gcloud beta run deploy test --project xxx --region xxx --platform managed --source .

Building using Buildpacks and deploying container to Cloud Run service [test] in project [xxx] region [xxx]
✓ Building and deploying... Done.
  ✓ Uploading sources...
  ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/xxx].
  ✓ Creating Revision...
  ✓ Routing traffic...
Service [test] revision [test-00004-hos] has been deployed and is serving 100 percent of traffic.
Service URL: https://xxx.a.run.app

1分くらいで終了しましたw(GAE FEとは...)
早速確認してみましょう

わーお...
今まで一生懸命yamlを書いていた自分が馬鹿らしくなるくらい簡単にデプロイができました。
--source 恐るべし

中身を追ってみる

せっかくなので--sourceで何をやっているのか追ってみたいと思います。

改めて出力内容を確認すると


Building using Buildpacks and deploying container to Cloud Run service [test] in project [xxx] region [xxx]
✓ Building and deploying... Done.
  ✓ Uploading sources...
  ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/xxx].
  ✓ Creating Revision...
  ✓ Routing traffic...
Service [test] revision [test-00004-hos] has been deployed and is serving 100 percent of traffic.
Service URL: https://xxx.a.run.app

やっていることは以下の4つのようです

  • Uploading sources
    • gcsにソースコードをアップロード
  • Building Container
    • イメージの作成・GCRへアップロード
  • Creating Revision
    • ↑のイメージを用いてCloud Runの新しいリビジョンの作成
  • Routing traffic
    • トラフィックを新しいリビジョンに100%移行

個人的に
「なぜdokcerfile作成してないのにgolangのイメージでビルドできてるんだろう」
という点が謎だったので、ビルドログを見ながら詳細を追っていきたいと思います。

Uploading sources

ビルドログの最初になにやらgcsにアップロードしてるようなログが見つかりました。

Fetching storage object: gs:/xxx_cloudbuild/source/yyy.tgz#zzz
Copying gs://xxx_cloudbuild/source/yyy.tgz#zzz...
/ [0 files][    0.0 B/  3.6 MiB]                                                
/ [1 files][  3.6 MiB/  3.6 MiB]                                                
Operation completed over 1 objects/3.6 MiB. 

GCSをみてみるとたしかにアップロードされてますね。
おそらく後述のイメージビルドのときにここのリソースを見てビルドしているんでしょう。

ダウンロードしてみると、たしかにソースコードがはいってました。

Building Container

さらにログを追っていくと、今度は何やらbuildpacksというイメージをダウンロードしており、そこからGoのランタイムを用いて自分のコードをビルドしてるようでした。
このbuildpacksなるものがデプロイしたいプロジェクトのランタイムを推測してくれるものっぽいです。
調べてみるとビンゴ

ビルダーにはソースコード言語を自動検出する機能が備わっています。

Status: Downloaded newer image for gcr.io/buildpacks/builder:latest
v1: Pulling from buildpacks/gcp/run
0630ec5cfbac: Already exists
cb52d192561b: Already exists
3c2cba919283: Already exists
a9868d531da1: Already exists
6e839ca0739c: Already exists
Digest: sha256:9eee082ca3961dc89d4b720552c62b50d90bb9ea40fb92fd7d6e5d80b0ba0f3c
Status: Downloaded newer image for gcr.io/buildpacks/gcp/run:v1
0.9.3: Pulling from buildpacksio/lifecycle
5c7fe08dec51: Pulling fs layer
bc1d6b18b4c1: Pulling fs layer
5c7fe08dec51: Verifying Checksum
5c7fe08dec51: Download complete
bc1d6b18b4c1: Verifying Checksum
bc1d6b18b4c1: Download complete
5c7fe08dec51: Pull complete
bc1d6b18b4c1: Pull complete
Digest: sha256:bc253af2edf1577717618cb3a95f0f16bb18fc9e804efbcc1b85f657d931a757
Status: Downloaded newer image for buildpacksio/lifecycle:0.9.3
===> DETECTING
[detector] 3 of 6 buildpacks participating
[detector] google.go.runtime  0.9.1
[detector] google.go.build    0.9.0
[detector] google.utils.label 0.0.1
===> ANALYZING
[analyzer] Previous image with name "gcr.io/xxx/cloud-run-source-deploy/test:yyy" not found
===> RESTORING
===> BUILDING
[builder] === Go - Runtime ([email protected]) ===
[builder] Using runtime version from go.mod: 1.13
[builder] Installing Go v1.13

こうして作成されたイメージはGCRにあがります。

[exporter] *** Images (015d5a9fefbb):
[exporter]       gcr.io/xxx/cloud-run-source-deploy/test:yyy
[exporter] Adding cache layer 'google.go.runtime:go'
Successfully built image gcr.io/xxx/cloud-run-source-deploy/test:yyy
PUSH
Pushing gcr.io/xxx/cloud-run-source-deploy/test:yyy
DONE

Creating Revision, Routing traffic

こちらはimage指定する通常のdeployコマンドと一緒のフローですので割愛

最後に

中身を追ったことで、ブラックボックスみが深いコマンドがだいぶ咀嚼できました。

今回はソースコードがgolang & 2ファイルのみでしたが、ソースコードをgcsにあげてる仕組み上これがnode.jsとかになってくるとnode_modulesもアップロードしだすと思うので速度が気になる所。

ただ、バージョン管理したいような大規模なものじゃない限りもう全部これでいいじゃん、という気分になりました。Cloud Runすごい。
この魔法、これから活用する機会が多そうです。

最後までありがとうございました。

参考

https://cloud.google.com/run/docs/release-notes
https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy#--source
https://cloud.google.com/blog/ja/products/containers-kubernetes/google-cloud-now-supports-buildpacks