ほりひログ

所属組織の製品 (Azure とか) に関連する内容が多めだけど、個人の見解であって、所属組織を代表する公式情報ではないです。

PHP8/Laravel8 アプリを App Service on Linux で動かす方法 (2022/04 暫定版)

どうやら App Service on Linux で PHP8 / Laravel8 のアプリを動かす時に、いろいろ気を付けることがあるようなので、回避策含め備忘録としてまとめておく。

主な注意点

大きく分けて二つ。

  1. PHP を動かす Web サーバーの設定
  2. ビルド方法

1. Web サーバー設定

App Service on LinuxPHP のコンテナー イメージは、PHP7 までは apache だったのが nginx に変更になった。
それに伴って、PHP を動かす設定も変えないといけないらしい。
# ちなみに、OS は Debian 10 (buster)

具体的には、Startup Command として、nginx へのリクエストを PHP アプリへルーティングする?ための設定を変更する処理を指定する。

まずは nginx の設定変更。
App Service on Linux 内の nginx は /etc/nginx/sites-available/default を見ているので、これをコピーして PHP8/Laravel8 の構成に合わせて変更する。

これをアプリケーション プロジェクトの scripts/default として保存しておく。

scripts/default

server {
    #proxy_cache cache;
        #proxy_cache_valid 200 1s;
    listen 8080;
    listen [::]:8080;

    # 変更 1) index.php があるディレクトリを指定。これは Laravel8 の場合。
    root /home/site/wwwroot/public;  
    index  index.php index.html index.htm;
    server_name  example.com www.example.com; 

    location / {            
        index  index.php index.html index.htm hostingstart.html;
        # 変更 2) 詳細は https://docs.microsoft.com/en-us/answers/questions/542749/deploying-an-app-service-with-laravel-8-and-php-8.html
        try_files $uri $uri/ /index.php?$args;
    }

    # 以下デフォルトのまま
}

次に scripts/default/etc/nginx/sites-available/default に戻して、nginx を再起動し、変更した設定を反映するスクリプトを書く。
同じく scripts/startup.sh としておく。

scripts/startup.sh

#!/bin/bash

cp /home/site/wwwroot/scripts/default /etc/nginx/sites-available/default
service nginx reload

最後に App Service 側の Startup Command を使って、起動時に scripts/starup.sh を実行するよう設定する。

これで nginx と PHP との間の設定は解決。

2. ビルド設定

2022 年 4 月現在、PHP8 のアプリは既定の設定のままだと App Service のビルド エンジンである Oryx でのビルド (compser install コマンドの実行) ができない。

下記 Oryx の GitHub リポジトリの issue にある通り、Kudu コンテナー*1上でのビルド時に必要なファイル libonig.so.4 が見つからずエラーになってしまう。

github.com

追えるとこまで頑張ってみた感じ、これは、

  1. Kudu コンテナー上での composer install 実行に使用される PHP バイナリーが libong.so.4 とリンクしている
  2. リンクされている libonig.so.4 は、Debian 9 (コードネーム stretch) 向けのライブラリーである
    https://packages.debian.org/search?keywords=libonig
  3. でも Kudu コンテナーは Debian 10 (コードネーム buster) ベースのコンテナーである

    だから libonig.so.4 は入っていないし入れられない。

なので、この PHP バイナリーは今の Kudu コンテナーでは実行できない、という話。
たぶん PHP バイナリーをビルドしている環境が stretch だったのではないか、という疑惑。

一応、修正済みの Oryx が GitHub 上にはリリースされているので、Azure 上への次のリリース*2を待てばビルドできるようになるはず。

github.com


(以下 4/30 追記)

上記修正が適用されているかどうかは、Kudu コンソール上で oryx --version を実行してみて、ReleaseTagName20220427.1 かそれ以降になっているかを見たらいいっぽい。

(追記ここまで)


それが待てない人は以下の回避策をお試しあれ。

回避策 1. Oryx でビルドしない

最初はシンプルな策、Oryx でのビルドをやめる。
Oryx でビルドできないんだから、ローカルや CI 環境でビルドして、ビルド済みのものを App Service にデプロイしてしまえばいい。

App Service のアプリケーション設定で SCM_DO_BUILD_DURING_DEPLOYMENTfalse を指定すると、デプロイ時のビルドは無効になる。

回避策 2. Kudu を stretch ベースにする

issue で Corp. のエンジニアから出ている方法で、アプリケーション設定で SCM_DISABLE_BUSTER_KUDUtrue を指定する。
すると、Kudu のコンテナーが stretch ベースのものになるらしい。

試してみる。

既定の状態は buster なのは上のスクショの通り。

次に SCM_DISABLE_BUSTER_KUDUtrue を指定した状態。

おー確かに stretch になった。マジかよ知らなかった*3

これで libonig.so.4 が使えるので、composer install はできるはず。

ただし、ビルドは stretch ベースのコンテナー上で行われる一方で、実際のアプリケーションは buster ベースのランタイム コンテナー上で動くことになるので、ライブラリーによってはこの違いで動かなくなる(かもしれない)。

回避策 3. PHP バイナリー自体を置き換える

Kudu コンテナー内での composer install に使われている PHP バイナリーは、上記の通り stretch 上でビルドされたものと推察されるが、これは Oryx を起動した時にここからダウンロードして Kudu コンテナー内に展開したもの。
これを buster 上でビルドされた PHP バイナリーとに置き換えてしまえばいい。

そうすると

  • buster ベースの KutuLite コンテナー
  • buster 向けの PHP バイナリーを使って composer install を実行してビルド
  • ランタイムも buster

という感じで全て buster で統一できてハッピー。

buster 向け PHP バイナリーは自前でビルドしてデプロイ パッケージに入れることもできるし、実は stretch 向けの PHP バイナリーと同じところにあるのでそっちも使える。

「置き換え」処理そのものは、Oryx が持っている「ビルド前後に任意のスクリプトを実行する」仕組みを使う。

github.com

PHP バイナリーの置き換えはビルドの前にやらないといけないので、 PRE_BUILD_SCRIPT_PATHPRE_BUILD_COMMAND を使う。
単発コマンドでいい場合、またはワンライナーで書ける場合は PRE_BUILD_COMMAND がいいが、スクリプト ファイルを書く場合は PRE_BUILD_SCRIPT_PATH でファイルを指定する。

例えば、下記のようなスクリプトscripts/prebuild.sh として配置するなら、PRE_BUILD_SCRIPT_PATHscripts/prebuild.sh と指定する。

scripts/prebuild.sh

#!/bin/bash

PHP_VERSION=8.0.17

cd /tmp
mkdir -p /tmp/oryx/platforms/php/${PHP_VERSION}
curl -O https://oryx-cdn.microsoft.io/php/php-buster-${PHP_VERSION}.tar.gz
tar -xzf /tmp/php-buster-${PHP_VERSION}.tar.gz -C /tmp/oryx/platforms/php/${PHP_VERSION}

これで、composer install の直前に buster 向けの PHP バイナリーに差し替えができる。

懸念点は Corp. のエンジニアから「そっちのバイナリーは、依存モジュールが変わっているから、何が起こるか。。。」(超意訳)と言われたこと*4だけど、試した限り composer install くらいなら動く。
もちろん自前でビルドして持ち込む場合は自己責任で。

startup.sh など scripts 配下もまとめて GitHub に公開してみた。

github.com

一応、修正リリースと同じアプローチのはず。

ビルド エラー回避策のまとめ

ここまで書いたビルド設定に関する 4 種類の回避策のまとめ。

# 回避策 設定方法 メリット デメリット
1 Oryx でのビルドをやめる SCM_DO_BUILD_DURING_DEPLOYMENT = false ビルド環境の自由度が高い CI 等のビルド環境が別途必要
2 stretch ベースの Kudu コンテナー SCM_DISABLE_BUSTER_KUDU = true 設定簡単 ビルド/ランタイム環境でベース OS が異なり、アプリ実行時に不整合が起こるかも。
3 ビルド用 PHP バイナリーの変更 PRE_BUILD_SCRIPT_PATH = <script_path> ビルド/ランタイム環境の統一感 動くことは動くがエンジニアが前向きじゃない。自己責任。
4 次リリースを待つ - 公式方法。 「いつから使える」ってはっきりしたことは言えない

あなたはどれを選びます?

*1:KuduLite と言われるコンテナー イメージ。1. の nginx が動くアプリ コンテナーとは別コンテナー

*2:2022 年 5 月か 6 月かな?

*3:App Service にはこういう知らない設定がいっぱいある

*4:なんで公開しているんですかねぇ。。。