Cloud Run Jobsをheroku runのように手軽に使いたい

heroku runとは

One-Off Dynos | Heroku Dev Center

Heroku は歴史的に Rails アプリをすぐ deploy できる PaaS として人気が出たわけだけど、痒いところに手が届くなぁと感じるものに heroku run コマンドがある。

heroku run とは

deploy 済みの Web アプリとは別な Dyno ( コンテナ ) が手早く立ち上がって引数に与えたコマンドを実行できる

もので、例えば

heroku run bundle exec rails c

ってやると本番のサーバで rails console を開くことができる1。この例を見ても分かるが、

この時立ち上がるコンテナは git push して build したイメージがそのまま使われている(ただしコンテナとしてはベツモノ)

つまり、Web アプリ用にもバックグラウンドジョブ用にも同じコードから作った同じイメージが利用できる。しかもビルドのために自分で Dockerfile をメンテしたりイメージを更新しなくても定期的に Stack ( OS ) レベルは Heroku 側でメンテナンスされているため自動的に セキュリティ fix などが適用されている。

Cloud Run JobsとCloud Native Buildpacks

Cloud Run は当初 HTTP を listen するコードしか動かせなかったが、2023年4月、HTTP リクエストと関係のないプロセスを動かせる Cloud Run Jobs が General Availability となった。

Cloud Run jobs and second-generation execution environment GA | Google Cloud Blog

これはつまり「ただコマンドを叩くだけ」みたいな伝統的な cron で実行していたようなサーバ上のジョブを Cloud Run で実現できるようになったということである。

すごくいいじゃん!

ただ、image は自分で作る必要があるので、そこだけ注意が必要だ。Cloud Run には gcloud コマンドを使って

gcloud run deploy --source

--source オプションを付けてソースコードから自動的に Google の Cloud Native Buildpacks Builder を利用して deploy する方法があるが、Cloud Native Buildpacks はあくまで web プロセス向けのイメージを作ることがデフォルトの動作であるため、

gcloud run jobs deploy --source

としても、web プロセスを作って deploy することになってしまう。またこの時どんな build プロセスを踏んでいるかを後からログで辿ることも難しいので、Cloud Run Jobs については

自分で手元や Cloud Build などで pack コマンドから Cloud Native Buildpacks の builder を使ってビルドして、できたイメージを deploy する

という手順を踏むのが2023年12月現在は安全なようだ。

具体的に非web向けのイメージをdeployする

前回 も紹介したリポジトリ

wtnabe/example-cnbp-node-ruby

に非 Web 向けのスクリプトを設定しておいたので、そちらを参照して実際に動かしてもらうと分かりやすいが、手順としては以下のようになる。

  1. Procfileweb 以外のプロセスを定義する
  2. pack build -D <process> で 1 で用意した process を default process にした image を作る
  3. できあがった image を artifact registry に push
  4. 3 で準備した image を利用して gcloud run jobs deploy で deploy する

ポイントは 2 で、リンク先のリポジトリの Procfile のように

web: ./bin/start-web
hello: ./scripts/hello

こんな形で hello プロセスがあったとすると、

pack build -D hello

とする2ことで、できあがった docker image を inspect した際に

[
  {
    "ContainerConfig": {
      "Entrypoint: [
        "/cnb/process/hello"
      ]
    }
  }
]

という形でこの hello プロセスで定義されたコマンドを entrypoint から自動的に起動する image ができあがる。

ここで web のように何かを listen し続けるコマンドを起動してしまうとジョブは失敗になってしまう

gcloud run jobs deploy --source を利用すると Cloud Native Buildpacks の Builder のおかげで自動的に web プロセス用の image ができてしまう3ので、上で述べたように Cloud Run Jobs 用には --source オプションの deploy は使えない、という結論になる。

  1. 実際にやるかどうかは置いておく 

  2. この際、builder は何を使ってもよい。Heroku の builder を使えば参照先のリポジトリであれば自動的に Ruby プロジェクトと判定される。ただ Google 製の Builder は判定の順序が期待していたものと異なり Go プロジェクトとなってしまったので、詳細は試せていない。 

  3. source から deploy した際に自動的にビルトされた image を pull してきて inspect すると entrypoint が /cnb/process/web になっていることが分かる。 

More