LaravelアプリでHTMLから画像を生成する際、多くのプロジェクトがBrowsershotを選択する。しかし「開発機では動くのに本番で動かない」という問題は、コードのバグではなく、アーキテクチャ上の依存関係の設計に起因する。この記事では、その依存関係の構造を整理しながら、各手段のトレードオフを設計判断の視点で検討する。
Browsershotが要求する依存スタックの全体像
Browsershotは一見PHPパッケージだが、実際にはPHP・Node.js・Puppeteer(Node.js製のヘッドレスブラウザ制御ライブラリ)・ChromiumバイナリとそのOSライブラリ群(libnss3やlibatk等)、さらにフォントセットという複数レイヤーの依存を持つ複合ランタイムである。これらすべてが実行環境に揃って初めて動作する。
この構成が問題になる場面は、シード記事でも具体的に列挙されている。Laravel VaporのようなサーバーレスPHP環境(AWSのLambdaランタイムを利用する仕組み)では、LambdaにはNodeもChromeも含まれておらず、パッケージインストールも自由にできない。共有ホスティング環境ではrootアクセス自体がなく、Chromiumのインストールは不可能である。Alpine Linuxベースのスリムなコンテナイメージ(php:8.3-fpm-alpineなど)を使う場合、Chromiumとその依存ライブラリ・フォントを追加すると数百MBの増加を招く。CIパイプラインでは毎回ブラウザをダウンロードするオーバーヘッドが発生する。
さらに、spatie/laravel-og-imageのような周辺パッケージも内部でlaravel-screenshotを経由してBrowsershotを呼び出す構造になっているため、この依存の連鎖はパッケージツリー全体に伝播する。
3つのアーキテクチャパターンとそれぞれのトレードオフ
現実的な対処法は大きく3つに分類できる。
1つ目は「ファットコンテナ」パターンである。DockerfileにChromium・共有ライブラリ・フォントをすべて焼き込み、サンドボックスフラグを設定して運用する。環境依存の問題は解消されるが、PHPアプリケーションと同一プロセスグループでChromeが起動するため、メモリ消費量が恒常的に高くなる。OGP画像(SNSシェア時に表示されるサムネイル画像)の生成リクエストが集中した際にPHP-FPM(PHPのプロセス管理デーモン)が圧迫される可能性がある。
2つ目は「サイドカー」パターンである。wnx/sidecar-browsershotはBrowsershotをAWS Lambda上のNode関数として切り出し、LaravelアプリからHTTPで呼び出す構成を取る。サーバーレス環境でも動作し、メモリ競合は回避できる。ただし、IAMロール(AWSのアクセス権限管理)の設定・Lambdaレイヤーの管理・Node関数のバージョン管理という独立した運用コストが生まれる。PHPコードと別にデプロイパイプラインを持つことになり、両者のバージョン整合性を維持し続ける必要がある。
3つ目が「レンダリングAPIへのオフロード」パターンである。html2img/html2img-laravelパッケージを使うと、Chrome部分をAPI側に委譲し、アプリはHTTPリクエストを1本送るだけで画像URLを取得できる。
composer require html2img/html2img-laravel環境変数にAPIキーを設定するだけで動作し、DockerfileへのChromium追加もLambdaレイヤーの管理も不要になる。APIサーバー側では実際のChromeが動作するため、Flexbox・CSS Grid・カスタムプロパティといった現代的なCSSは完全にサポートされる。
設計判断の軸:何をどこで動かすべきか
この3パターンを比較すると、判断軸は「ブラウザプロセスをどの境界で管理するか」に集約される。
- ファットコンテナ: アプリとブラウザを同一境界に置く。運用はシンプルだがリソース競合リスクを持つ
- サイドカー: ブラウザを別境界(別Lambda)に分離する。責務は明確だが運用対象が増える
- APIオフロード: ブラウザを自組織の境界外に出す。運用対象は減るが外部依存と通信コストが生まれる
アーキテクチャ設計の文脈では、「自分たちが管理すべきもの」と「外部に委ねてよいもの」を区別することが技術的負債の管理につながる。ブラウザのバイナリ管理・OSライブラリの互換性維持・フォントセットの更新は、Webアプリケーションのコア機能とは別のドメインの関心事である。それを自前で抱えることの保守コストと、外部APIへの依存リスク(障害時の影響範囲・料金体系の変更など)を天秤にかけることが判断の本質となる。
どのパターンが適切かは、チームが管理できるインフラの範囲・デプロイ環境の制約・画像生成の頻度によって変わる。「動けばよい」ではなく「誰が何を維持するのか」を設計段階で明確にしておくことが、後工程での運用負荷を大きく左右する。