Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Deploying a Laravel app on Google Cloud Run: the pitfalls and the fixes

2026年11月04日に「Dev.to」が公開したITニュース「Deploying a Laravel app on Google Cloud Run: the pitfalls and the fixes」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Google Cloud RunでLaravelアプリを動かす際の注意点と解決策を解説。コンテナ設定、フロントエンドビルド、Composer依存関係、HTTPS対応、シークレット管理、起動時の挙動、エラー対策、キュー処理など、安定稼働のための具体的な落とし穴と回避策を提示する。

ITニュース解説

Google Cloud Run上にLaravelアプリケーションをデプロイする際、システムエンジニアを目指す初心者の方が知っておくべき重要なポイントと、遭遇しがちな課題、そしてその解決策について解説する。この記事は、実際の開発プロジェクトでの経験に基づいているため、実践的な内容が多い。

まず、Google Cloud Runがコンテナに何を求めているのか理解する必要がある。Cloud Runは、開発者が作成したコンテナイメージを実行するサービスで、主にウェブアプリケーションやAPIの実行に使われる。コンテナは、Cloud Runが指定するポート(通常は8080)でリクエストを待ち受けるように設定しなければならない。ここが一つ目のポイントで、アプリケーションのウェブサーバー(例えばNginx)がこのポートを監視するように設定する必要がある。

次に重要なのは、TLS(HTTPS)の終端についてだ。Cloud Runは、外部からのHTTPSリクエストを受け取ると、それを一度Cloud Runのシステム内でHTTPに変換し、平文のHTTPとしてコンテナに転送する。これはセキュリティ面で問題があるわけではなく、Cloud Runが通信を管理しているためだ。しかし、Laravelアプリケーションがこの仕組みを知らないと、「自分はHTTPでアクセスされている」と誤解し、生成するURLがすべてhttp://になってしまう。ウェブページがhttps://で表示されているのに、画像やJavaScriptファイルがhttp://で読み込まれようとすると、ブラウザのセキュリティ機能(コンテンツセキュリティポリシー)によってブロックされ、ページが正常に表示されない、といった問題が発生する。この対策として、Laravelにプロキシの存在を教え、HTTPSであることを強制する設定が必要となる。具体的には、LaravelのTrustProxiesミドルウェアを有効にし、APP_URLやASSET_URLをHTTPSのドメインに設定し、必要に応じてURL::forceScheme('https')を使ってHTTPS URLの生成を強制する。

ファイルシステムの扱いも重要だ。Cloud Runのコンテナは、ディスクに書き込んだデータが、そのインスタンスが停止すると消滅するという特性がある。これはコンテナが一時的なものであり、必要に応じて自動的に起動・停止を繰り返すためだ。そのため、セッション情報、ユーザーがアップロードしたファイル、ログファイルといった永続化が必要なデータは、データベース、オブジェクトストレージ(Google Cloud Storageなど)、または標準出力(ログの場合はCloud Loggingに送られる)に保存するように設計しなければならない。一時ファイルを除き、コンテナのローカルディスクにデータを保存するような設計は避けるべきだ。

また、コンテナの起動とシャットダウンにも時間制限がある。起動後4分以内にリクエストを受け付けられる状態にならなければならない。シャットダウン時には、まずSIGTERMシグナルが送られ、10秒後にSIGKILLで強制終了される。この間、アプリケーションは優雅にシャットダウン処理を行う必要があるが、長時間かかる処理は避けるべきだ。

具体的なデプロイ時の落とし穴としては、まずフロントエンドアセットの欠落が挙げられる。Laravelアプリケーションでは、Viteなどのツールを使ってJavaScriptやCSSといったフロントエンドのリソースをビルドする。これらのビルド成果物は通常.gitignoreで管理され、Gitリポジトリには含まれない。しかし、Cloud Runにデプロイする際、.gcloudignoreファイル(これは.gitignoreと似ており、Cloud Buildにアップロードしないファイルを指定する)のデフォルト設定が.gitignoreを取り込んでいると、ビルド済みのフロントエンドアセットがコンテナイメージにコピーされず、デプロイ後にウェブサイトがスタイルや機能を失ってしまう。解決策としては、CI/CDパイプラインのデプロイステップでDockerイメージをビルドする前に、フロントエンドアセットをビルドし、そのビルド成果物だけをDockerイメージにコピーするようにする。これにより、コンテナイメージを小さく保ち、ビルド時間を短縮することもできる。

次に、vendor/ディレクトリがローカルのものに上書きされてしまう問題がある。Dockerイメージをビルドする際には、composer installを実行してPHPの依存関係をインストールするのが一般的だ。しかし、もし.gcloudignoreにvendor/ディレクトリが指定されていないと、開発者のローカル環境にあるvendor/ディレクトリ(composer installの前に存在していたり、キャッシュされていたりする可能性がある)がコンテナイメージにコピーされてしまい、意図しない古いライブラリや不整合な依存関係がデプロイされることがある。これを避けるためには、vendor/とnode_modules/ディレクトリをアップロード対象から除外し、Dockerイメージのビルドプロセス内で常にクリーンな状態で依存関係をインストールするようにする。

Composerのパスリポジトリとシンボリックリンクも問題の原因になることがある。アプリケーション内で独自に開発したモジュールをComposerのパスリポジトリとして利用する場合、Composerはデフォルトでシンボリックリンクを作成する。しかし、Dockerのビルド時にファイルがコピーされる際、このシンボリックリンクが実際のディレクトリとしてコピーされてしまい、オートローダーがクラスを見つけられなくなることがある。この場合は、Composerのsymlink: falseオプションを試すか、ビルドステップでプラグインのPSR-4名前空間をComposerのオートロードマップに明示的に追加するなどの対策が必要になる。

Dockerのレイヤーキャッシュを最適化しようとしてビルドが壊れることもある。Dockerのビルドは、Dockerfileの各ステップがレイヤーとしてキャッシュされることで効率化される。一般的に、依存関係のインストール(composer installなど)はアプリケーションコードのコピーより前に行うことで、コードの変更があっても依存関係のレイヤーを再利用し、ビルド時間を短縮できる。しかし、パスリポジトリのように依存関係が自身のコードに依存している場合、この順序がビルドを壊すことがある。まずは動作するイメージを作成し、その後で慎重に最適化を進め、実際のCIビルドで変更を検証することが重要だ。

HTTPリンクがHTTPSプロキシの背後で問題になることは既に触れたが、これは非常に一般的な問題であり、サイト全体の機能停止につながることもある。LaravelがHTTPSの背後で動作していることを正しく認識していないと、認証、検索、予約などの機能が動かなくなる。前述の通り、LaravelのTrustProxiesミドルウェアを有効にし、APP_URLをHTTPSドメインに設定することが不可欠だ。

CI/CDパイプラインで秘密情報(データベースパスワードやAPIキーなど)を直接環境変数として渡すことも避けるべきだ。これらの情報はCloud Runのサービス設定に残りやすく、セキュリティリスクとなる。Google Cloudでは、秘密情報の管理にSecret Managerの利用を推奨している。また、認証には、GitHub ActionsなどのCIツールからGoogle Cloudへの認証にWorkload Identity Federationを利用することで、長期的な認証情報(サービスアカウントキーファイルなど)を管理する必要がなくなり、セキュリティが向上する。

コールドスタートとメモリの管理も重要だ。Cloud Runのインスタンスは、リクエストがないと停止し、新しいリクエストが来ると起動する。この起動(コールドスタート)時に、アプリケーションの設定キャッシュやルートキャッシュが古い情報を持っていると問題が発生する。そのため、起動スクリプトでphp artisan config:clearやphp artisan route:clearといったコマンドを実行し、キャッシュをクリアしてからアプリケーションを起動するのが良い。この起動スクリプトはコールドスタートのたびに実行されるため、可能な限り短くする必要がある。また、Cloud Runのインスタンスにはデフォルトでメモリ制限があり、これを超過するとインスタンスが終了させられる。アプリケーションの安定稼働のためには、必要に応じてメモリ制限を増やすことを検討する。

アプリケーションの起動時に発生するエラーも注意が必要だ。管理者向けの機能など、特定の環境でのみ必要なコンポーネントの登録処理が、アプリケーション全体の起動処理に含まれていると、その部分でエラーが発生した際に、ウェブサイト全体がダウンしてしまう可能性がある。このようなコードはtry/catchブロックで囲み、エラーが発生してもアプリケーションの他の部分が動作を継続できるように堅牢性を高めるべきだ。また、エラーページ自体も、アプリケーションのルーティングや他のコンポーネントに依存せず、常にレンダリングできるようにシンプルに設計することが重要だ。

最後に、Laravelのキューワーカーとスケジュールされたタスクの扱いだ。Cloud Runのデフォルトの「リクエストベース課金」モデルでは、インスタンスはリクエスト処理中のみCPUが割り当てられる。そのため、ウェブコンテナ内でphp artisan queue:workのようなバックグラウンドプロセスを実行しても、リクエストがないとCPUが停止し、キューが処理されない。キューや定期的なタスクを実行するには、「インスタンスベース課金」に変更してCPUを常に割り当てるか、Cloud RunジョブとCloud Schedulerを組み合わせて、指定した時間にコマンドを実行する方法を検討する必要がある。

これらの落とし穴は、デプロイされたコンテナ環境で初めて顕在化することが多い。そのため、小さく頻繁なデプロイを行い、問題が発生した際に原因を特定しやすくすることが重要となる。デプロイ前にはブラウザテストをCI/CDに組み込み、エンドツーエンドでの動作確認を行うことで、多くの問題を未然に防げる。Cloud Runは非常に強力なサービスだが、その特性を理解し、適切に設定することが安定したアプリケーション運用には不可欠だ。

関連コンテンツ

関連IT用語