Cloud RunにデプロイしたLaravelアプリケーションをCloud Schedulerで定期実行

Cloud RunにデプロイしたLaravelアプリケーションをCloud Schedulerで定期実行

こんにちは、tomatsuriです。

Cloud Schedulerを触ってみたいという衝動に駆られ、Cloud RunにLaravelアプリケーションをデプロイし、Cloud Schedulerで定期実行するサンプルを作成してみました。

Laravelアプリケーションの作成

まず、Cloud Schedulerから定期的にアプリケーションが実行されていることを確認するために、/batchにGETリクエストをしたらログに“batch executed.“と出力するだけの簡単な機能を用意しておきます。

Cloud Runは標準出力に出力したログはCloud Loggingによって自動的に取得されるため1、Laravelから標準出力にログを出力するためにconfig/logging.phpのchannelsに以下を追加します。

Plain text
'stdout' => [
    'driver' => 'monolog',
    'handler' => StreamHandler::class,
    'with' => [
        'stream' => 'php://stdout',
    ],
],

(Laravel8系を使用)

あとは環境変数のLOG_CHANNELをstdoutに書き換えればOKです。 環境変数はCloud Run上で設定が可能です。2

Dockerイメージの作成

以下のようなDockerfileをプロジェクトのルートに用意します。 Cloud RunにLaravelをデプロイする方法としてApacheを使用している例をいくつか見たので、 今回はnginxでやってみました。

Plain text
FROM php:8.0-fpm-alpine

RUN apk add --no-cache nginx wget

RUN mkdir -p /run/nginx
COPY docker/nginx.conf /etc/nginx/nginx.conf

RUN mkdir -p /app
COPY . /app

RUN sh -c "wget http://getcomposer.org/composer.phar && chmod a+x composer.phar && mv composer.phar /usr/local/bin/composer"
RUN cd /app && \
    /usr/local/bin/composer install --no-dev

RUN chown -R www-data: /app

CMD sh /app/docker/startup.sh

nginx.confとstartup.shはこちら。 ドキュメント3に従い、PORT環境変数で定義されたポートをリッスンするように構成しています。

Plain text
worker_processes  1;

events {
    worker_connections  1024;
}
http {
    include mime.types;
    keepalive_timeout 65;

    server {
        listen LISTEN_PORT default_server;
        server_name _;
        root /app/public;
        index index.php;
        charset utf-8;
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }

        location = /favicon.ico { access_log off; log_not_found off; }
        location = /robots.txt  { access_log off; log_not_found off; }
        access_log /dev/stdout;
        error_log /dev/stderr;

        client_max_body_size 100m;

        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }
}

daemon off;
Plain text
#!/bin/sh

sed -i "s,LISTEN_PORT,$PORT,g" /etc/nginx/nginx.conf

php-fpm -D

nginx

startup.shはchmod a+x docker/startup.shでパーミッションを変更しておきます。

これらはプロジェクトのルートにdockerフォルダを作成し、その中に配置しています。

Dockerfile、nginx.conf、startup.shが用意できたらdocker build -t laravel-batch01 . を実行してビルドします。

ビルドが完了したら、docker run -e PORT=80 -p 8080:80 laravel-batch01で起動し、localhost:8080でアクセスして確認してみましょう。

Container Registryへイメージをpush

まずはビルドしたイメージにレジストリ名をタグ付けします。4

docker tag laravel-batch01 asia.gcr.io/[PROJECT-ID]/laravel-batch01

次に、Container Registryへアクセスするための認証を行います。今回は推奨とされているgcloud 認証情報ヘルパーを使用します。5

ユーザーまたはサービスアカウント(推奨)で認証を行い、gcloud auth configure-dockerでgcloudをDockerの認証ヘルパーとして設定します。

これでタグ付きイメージをContainer Registryにpushできるようになりました。

docker push asia.gcr.io/[PROJECT-ID]/laravel-batch01

でpushし、Cloud ConsoleのContainer Registry上で確認できればOKです。

Cloud Runを作成

laravel-batch01という名前のCloud Run サービスを作成します。

Cloud Console上でCloud Runのページにアクセスし、サービスの作成へ進みます。

Cloud Runを作成の画面(1)

「サービスの最初のリビジョンの構成」のコンテナイメージのURLは、先程pushしたイメージを選択します。

Container Registryのイメージ詳細から直接作成することも可能です。

Cloud Runを作成の画面(2)

最後の「このサービスをトリガーする方法の構成」では、 Ingressは「すべてのトラフィックを許可する」を選択します。

現時点(2021/05/14)ではCloud Schedulerから内部サービスに対してhttpリクエストすることはできません。6

認証は「認証を必要とする」を選択し、作成します。

Cloud Runを作成の画面(3)

Cloud SchedulerからCloud Runを起動するためのサービスアカウントを作成

このままCloud SchedulerからCloud Runへhttpリクエストをしても、権限がなく失敗してしまいます。

そこで、作成したCloud Runを起動する権限を持つサービスアカウントを作成し、それを使用してCloud SchedulerからCloud Runへリクエストするように設定します。

ここではlaravel-batch01-invokerという名前のサービスアカウントを作成し、以下のコマンドで権限を付与します。

Plain text
gcloud run services add-iam-policy-binding laravel-batch01 \
    --member=serviceAccount:[サービスアカウントのメールアドレス] \
    --role=roles/run.invoker

Cloud Run詳細ページの権限タブを開き、Cloud Run 起動元の権限を持つサービスアカウントが追加されていればOKです。

Cloud Schedulerの設定

「ジョブを定義する」で名前、頻度(unix-cron形式)、タイムゾーンを設定します。

「ジョブのターゲットを構成する」で、どこにどのようなリクエストを送信するのかを設定します。 今回は以下のようになります。

  • ターゲットタイプ:HTTP
  • URL:Cloud Runにデプロイしたアプリケーションのエンドポイント
  • HTTPメソッド:GET

Authヘッダーは「OIDC トークンを追加」を選択し、先程作成したサービスアカウント(laravel-batch01-invoker)のメールアドレスを入力します。

Cloud Schedulerの設定の画面

「詳細設定を構成する」でリトライ回数などを設定できますが、今回はデフォルトのままにします。

ジョブを作成したら、ジョブが実行されるまで待ってもよいですし、「今すぐ実行」ボタンで任意のタイミングで実行することもできます。

実行結果

ジョブの結果が「成功」となり、Cloud Runのログにアプリケーションで実装したログのメッセージが出力されていれば完了です。

実行結果の画面

おわり

Cloud Run、Cloud Schedulerを使用して手軽にバッチ処理のサンプルを作成できました。

ちなみにCloud Scheduler料金は実行単位ではなくジョブ単位です。

請求アカウント毎(プロジェクト毎ではない)に3ジョブの無料枠があり、課金対象となってもジョブあたり$0.10/月とお手頃です。

今後はCloud Schedulerのhttp以外のターゲットを使ってみたり、他のサービスを使用したバッチ処理のアーキテクチャなど色々試していけたらなと思います。

脚注


Footnotes

  1. Cloud Run ドキュメント ログの記録と表示 コンテナログを作成する

  2. Cloud Run ドキュメント 環境変数の使用

  3. Cloud Run ドキュメント コンテナポートの構成

  4. Container Registry ドキュメント ローカル イメージにレジストリ名でタグ付けする

  5. Container Registry ドキュメント gcloud 認証情報ヘルパー

  6. Cloud Run ドキュメント 内部サービスへのアクセス