開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. GCP >
  4. PHP対応したGoogle Cloud's BuildpacksでLaravelアプリのコンテナイメージをビルドしてCloud Runにデプロイする

PHP対応したGoogle Cloud's BuildpacksでLaravelアプリのコンテナイメージをビルドしてCloud Runにデプロイする

こんにちは、ナカエです。

今回は 以前の記事 で紹介した Cloud Native Buildpacks を活用するシリーズの続きです。

Google Cloud’s Buildpacks(日本語訳: Google CloudのBuildpack) がいつの間にやらPHPをサポートしていたので、こちらを使ってLaravelアプリをサクッとCloud Runにデプロイするというになります。

今まではPHPアプリをCloud Runにデプロイするには

  • 自前のDockerfileを書く
  • Cloud Native Buildpacksを利用したコンテナイメージのビルドのために自前でCloud Buildを設定する

などの必要性がありました。

参考: Cloud Native BuildpacksでビルドしたLaravelアプリのイメージをCloud Runにデプロイする

後者をGoogle CloudのBuildpackの仕組みで置き換えることができるので非常に楽になりましたよ、という話になります。

検証環境とソフトウェアのバージョン

  • OS: macOS Ventura 13.4
  • CPU: Apple M1 Max
  • zsh 5.9
  • GNU bash 3.2.57
  • PHP 8.2.0
  • Composer 2.5.8
  • Laravel 10.2.3

Google CloudのBuildpack

Google Cloudでは、 Google Cloud’s Buildpacks としてCloud Native Buildpacksに準拠した仕組みを備えており、コンテナイメージの自動生成が可能です。

言語は

  • Python
  • Node.js
  • Java
  • Go
  • Ruby
  • PHP
  • .NET Core


に対応しています。

サポートされているバージョンについて詳しくはドキュメントの ビルダー  |  Buildpacks  |  Google Cloud をご覧ください。

Cloud Runなど向けの汎用ビルダーのPHP対応はいつの間にか行われていましたが、割と最近です。

ちなみにGoogle App EngineとCloud Functionsも同じくGoogle Cloud’s Buildpacksのビルダーを活用されています。特にApp Engineの第2世代ランタイム向けに使われるビルダーは、App Engine特有の設定が追加されています。

ビルダーのドキュメントに記載されている gcr.io/buildpacks/builder:v1 などのGoogle Cloud’s Buildpacksが用意しているビルダーを指定することで、ローカルでもpackコマンドでコンテナイメージをビルドし、Google Cloudで動くコンテナイメージと同じものの内容を確認することができます。

今回の記事も、ローカルでビルドしたコンテナイメージを調べて試行錯誤した成果です。

Laravelアプリを作成

まずはComposerを使ってLaravelアプリを作成します。

参考: Installation - Laravel - The PHP Framework For Web Artisans のページの #Your First Laravel Project

作業用のディレクトリに移動し下記コマンドを打つとセットアップが始まります。

composer create-project laravel/laravel laravel-google-clouds-buildpacks

この状態で一度Gitコミットしておきます。

git init
git add .
git commit -m "first commit"
git branch -M main

Google Cloud’s Buildpack向けのビルド設定

Laraelプロジェクトに直下で引き続き作業します。

以前のCloud Native Buildpacksの記事 ではHerokuのBuildpackを利用していましたが、今回はGoogle Cloud’s Buildpackのビルダー gcr.io/buildpacks/builder:v1 を利用します。

設定ファイルを作成・追記していきます。

Procfile

web: pid1 --nginxBinaryPath nginx --nginxConfigPath /layers/google.php.webconfig/webconfig/nginx.conf --serverConfigPath /workspace/nginxserver.conf --nginxErrLogFilePath /layers/google.php.webconfig/webconfig/nginx.log --customAppCmd "php-fpm -R --nodaemonize --fpm-config /layers/google.php.webconfig/webconfig/php-fpm.conf" --pid1LogFilePath /layers/google.php.webconfig/webconfig/pid1.log --mimeTypesPath /layers/google.utils.nginx/nginx/conf/mime.types --customAppSocket /layers/google.php.webconfig/webconfig/app.sock

コンテナのエントリポイントとなるコマンドを指定するファイルです。 pid1 という実行ファイルからnginxとPHP-FPMを起動するようになっています。オプションがとても長いです。

nginxserver.conf

fastcgi_read_timeout 24h;

# proxy_* are not set for PHP because fastcgi is used.

upstream fast_cgi_app {
    server         unix:/layers/google.php.webconfig/webconfig/app.sock fail_timeout=0;
}

server {
    listen      8080 default_server;
    listen      [::]:8080 default_server;
    server_name "";
    root        /workspace/public;

    rewrite     ^/(.*)$ /index.php$uri;

    location    ~       ^/index.php     {
        error_log stderr;

        fastcgi_pass    fast_cgi_app;
        fastcgi_buffering       off;
        fastcgi_request_buffering       off;
        fastcgi_cache   off;
        fastcgi_store   off;
        fastcgi_intercept_errors        off;

        fastcgi_index   index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        fastcgi_param   QUERY_STRING    $query_string;
        fastcgi_param   REQUEST_METHOD  $request_method;
        fastcgi_param   CONTENT_TYPE    $content_type;
        fastcgi_param   CONTENT_LENGTH  $content_length;

        fastcgi_param   SCRIPT_NAME     $fastcgi_script_name;
        fastcgi_param   SCRIPT_FILENAME $document_root/index.php;
        fastcgi_param   PATH_INFO       $fastcgi_path_info;
        fastcgi_param   REQUEST_URI     $request_uri;
        fastcgi_param   DOCUMENT_URI    $fastcgi_script_name;
        fastcgi_param   DOCUMENT_ROOT   $document_root;
        fastcgi_param   SERVER_PROTOCOL $server_protocol;
        fastcgi_param   REQUEST_SCHEME  $scheme;
        if ($http_x_forwarded_proto = 'https') {
            set $https_setting 'on';
        }
        fastcgi_param   HTTPS   $https_setting if_not_empty;

        fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
        fastcgi_param   REMOTE_ADDR     $remote_addr;
        fastcgi_param   REMOTE_PORT     $remote_port;
        fastcgi_param   REMOTE_HOST     $remote_addr;
        fastcgi_param   REMOTE_USER     $remote_user;
        fastcgi_param   SERVER_ADDR     $server_addr;
        fastcgi_param   SERVER_PORT     $server_port;
        fastcgi_param   SERVER_NAME     $server_name;
        fastcgi_param X_FORWARDED_FOR $proxy_add_x_forwarded_for;
        fastcgi_param X_FORWARDED_HOST $http_x_forwarded_host;
        fastcgi_param X_FORWARDED_PROTO $http_x_forwarded_proto;
        fastcgi_param FORWARDED $http_forwarded;
    }
}

HerokuのBuildpackと比べるとnginxの設定ファイルも若干長めですね。ドキュメントルートを変えたかっただけなのですが。

project.toml

[_]
id = "my-project"
name = "My Project"
version = "1.0.0"
schema-version="0.2"

[io.buildpacks]
builder = "gcr.io/buildpacks/builder:v1"
exclude = [
    ".idea",
    "/README.md",
    ".git",
    "/vendor",
    "/node_modules",
    "/bootstrap/cache/*.php",
]

[[io.buildpacks.group]]
uri = "google.nodejs.runtime"
[[io.buildpacks.group]]
uri = "google.nodejs.npm"
[[io.buildpacks.group]]
uri = "google.php.runtime"
[[io.buildpacks.group]]
uri = "google.php.composer-install"
[[io.buildpacks.group]]
uri = "google.php.composer"
[[io.buildpacks.group]]
uri = "google.php.webconfig"
[[io.buildpacks.group]]
uri = "google.utils.nginx"
[[io.buildpacks.group]]
uri = "google.config.entrypoint"
[[io.buildpacks.group]]
uri = "google.utils.label-image"

[[io.buildpacks.build.env]]
name = "GOOGLE_COMPOSER_VERSION"
value = "2.5.8"

project.tomlの書式(スキーマ)はバージョン0.2としています。 Google CloudのビルダーはHerokuより機能の粒度が細かい印象ですね。

composer.json

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "require": {
-         "php": "^8.1",
+         "php": "~8.2.0",
+         "ext-grpc": "*",
        "guzzlehttp/guzzle": "^7.2",
        "laravel/framework": "^10.10",
        "laravel/sanctum": "^3.2",
        "laravel/tinker": "^2.8"
    },
// 

PHPのバージョンを8.2系に指定し、HerokuのBuildpackでは扱いづらかったext-grpcを試しに追加します。

追記したらcomposer.lockを最新にしておきます。

composer update --ignore-platform-reqs

Herokuのようにcomposer.jsonのrequireにバージョン指定しただけではPHP拡張は有効にはならないので、下記のphp.iniの設定も必要です。

php.ini

[opcache]
zend_extension=opcache
opcache.enable=1

[grpc]
extension=grpc.so

; PHP extension files in gcr.io/buildpacks/builder:v1
; grpc.so
; imagick.so
; mailparse.so
; memcached.so
; mongodb.so
; opcache.so
; opencensus.so
; protobuf.so
; redis.so

gRPC拡張の有効化に加え、デフォルトではOPcacheが無効だったので有効化しています。gcr.io/buildpacks/builder:v1 のビルダーでサポートされている(というよりはsoファイルの存在を確認した)PHP拡張は上記ファイル下部のコメントの一覧のとおりです。

なお、次期バージョンのビルダー gcr.io/buildpacks/builder:google-22 はPHP拡張がほとんどサポートされていないようでした。

package.json

{
    "private": true,
    "type": "module",
+    "engines": {
+        "node": "18.x"
+    },
    "type": "module",
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "axios": "^1.1.2",
        "laravel-vite-plugin": "^0.7.5",
        "vite": "^4.0.0"
    }
}

enginesの設定を追記してNode.jsのバージョンを18系に指定しています。

GitHubのリポジトリにPush

ここまでのローカルのLaravelプロジェクトの変更をコミットしてリモートにpushします。

{GITHUB_ACCOUNT}/laravel-google-clouds-buildpacks という名前で GitHubリポジトリを作成します。

※ {GITHUB_ACCOUNT} は適宜置換してください。

git add .
git commit -m "build configuration"

git remote add origin https://github.com/{GITHUB_ACCOUNT}/laravel-google-clouds-buildpacks.git
git push -u origin main

Google Cloud の設定とデプロイ

続いて本命のGoogle Cloudの設定です。

Google Cloud Consoleから laravel-google-cloud-buildpack という名前でプロジェクトを作成します 。
 

プロジェクトの作成が完了したら、Cloud Runのページにアクセスしましょう。

「サービスを作成」 ボタンをクリックしてサービス作成画面に遷移します。 この際、自動的にCloud Run Admin APIが有効化されます。

「ソース リポジトリから新しいリビジョンを継続的にデプロイする」を選択肢、「CLOUD BUILD の設定」ボタンをクリックします。

右サイドにCloud Buildの設定が開くので、ソースリポジトリ としてリポジトリ プロバイダはGitHubを選択し、リポジトリを選択します。

GitHubのアカウントでGoogle Cloud Buildのアプリをインストールしたことがない場合は「Google Cloud Build のインストール」ボタンが表示されているのでこちらをクリックし、案内に従ってリポジトリを追加できます。 Only select repositoriesを選択してCloud Buildが接続できるリポジトリを絞るほうがおすすめです。

すでにGoogle Cloud BuildのGitHubアプリをインストール済みで設定したいリポジトリが見つからない場合は、「接続されたリポジトリを管理します」というリンクをクリックすることでGoogle Cloud Buildが参照できるリポジトリを追加しましょう。

リポジトリを新規に追加した後に、注意事項への同意のチェックが必要です。

「次へ」 ボタンをクリックして ビルド構成 に進みます。

google-cloud-buildpack-build-configuraiton.png

ビルドタイプ として 「Go、Node.js、Python、Java、.NET Core、Ruby、PHP(Google Cloud の Buildpacks を使用)」を選択します。ほかはデフォルトのままでOKです。

「保存」をクリックするとCloud Buildの設定は完了し、Cloud Runのサービス作成画面に戻ります。

表示されている項目を下記のとおり設定してください。

  • サービス名: laravel-google-cloud-buildpack
  • リージョン: asia-northeasat1 (東京)
  • 自動スケーリング インスタンスの最大数 1
  • 認証: 未認証の呼び出しを許可

google-cloud-buildpack-service-create1.png

続けて「コンテナ、ネットワーキング、セキュリティ」を展開し、コンテナの環境変数を設定します。

google-cloud-buildpack-service-create-env.png

APP_KEYはローカル環境で生成されているはずなので.envのAPP_KEYの値をコピー&ペーストしてください。また、LOG_CHANNELの値をstderrにして、標準出力にログが出力されるようにしておくとデバッグしやすくなります。

他はデフォルトのままで「作成」をクリックします。

本体であるCloud Runのサービスに加え、Cloud BuildのトリガーやArtifact Registryのコンテナイメージ用リポジトリなどが自動で作成されます。

作成した laravel-google-cloud-buildpack のサービスの詳細ページに移り、初 期設定と初回のデプロイが開始されます。

デプロイが完了するまで2〜3分程かかるのでしばらく待ちます。

Cloud Runのサービスの詳細の上部に表示されているURLをクリックしするとデプロイされたアプリケーションにアクセスできます。

google-cloud-build-pack-deployed.png
 

まとめ

Google Cloud’s Buildpacksを利用してLaravelアプリケーションをCloud Runにデプロイする仕組みを構築しました。

用意する設定ファイルは少し多いものの、以前より遥かに簡単になりましたね。

この記事もPHPerのGoogle Cloud/Cloud Run利用が広がる一助となれば幸いです。

TOPに戻る