Amazon Linux 2023 の PHP を CVE-2026-109618 / 109619 の修正版へ自前ビルドで上げる(公式パッケージ配布前の暫定対応)
はじめに
2026-10-21 に PHP の修正版 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 がリリースされました。critical の脆弱性 2 件(CVE-2026-109618 と CVE-2026-109619)を修正する版です。一方、この記事を書いた時点では、Amazon Linux 2023(以下 AL2023)の公式リポジトリにまだ修正版のパッケージがありません。
この記事では、AL2023 が配布している SRPM をそのまま使い、中の PHP の版だけを upstream の修正版へ上げて再ビルドする手順を紹介します。この方法には次の利点があります。
- ファイル配置、設定ファイル、拡張モジュールの構成が公式パッケージと同じになり、そのまま差し替えられる
- 後で AL2023 が公式の修正版を出せば、
dnf upgradeで自動的に公式版へ置き換わる
対象は、EC2 上で AL2023 公式リポジトリの php8.2 / php8.3 / php8.5 パッケージを使っている方です。この記事の手順は 8.2 / 8.3 / 8.5 で確認しました。8.4 は未検証です。
免責事項
- 自前でビルドしたパッケージには AWS の署名がなく、AWS のサポート対象にもなりません。導入と運用の責任は読者ご自身が負ってください。
- これは公式パッケージが出るまでの暫定対応です。ALAS(Amazon Linux Security Center)で修正版が公開されたら、すぐに公式パッケージへ戻してください。
- 脆弱性の詳細と影響範囲は、本記事の要約ではなく、php-src の公式アドバイザリで確認してください。
- 記事中のコマンドは、筆者の環境で 2026-10-21 に実行して確認したものです。「未検証」と書いた箇所は、読者の環境で確認してから使ってください。
脆弱性の概要
php-src の GitHub Security Advisory として、2026-10-21 13:34 UTC に次の 2 件が公開されました。詳細は必ずリンク先の原文を読んでください。
| ID | 名称 | 深刻度 | 概要 |
|---|---|---|---|
| GHSA-w8hw-w9fx-j79w / CVE-2026-109618 | RCE via OOM corruption | critical | PHP はメモリ不足(OOM)エラーを longjmp() で処理します。このときリクエスト用のメモリが不正な状態のまま残り、リクエスト終了処理でそれが読まれることがあります。multipart の解析を工夫すると、各種制限の範囲内で OOM を起こせます |
| GHSA-6wmf-4rv5-p3rp / CVE-2026-109619 | RCE via stale global state | critical | ワーカーが保持するグローバル状態が、解放済みのリクエストメモリを指したまま残ります。同じワーカーが後続のリクエストを処理するときに use-after-free が起きます |
アドバイザリによると、CVE-2026-109618 には次の特徴があります。
- Apache の mod_php はリクエスト終了処理を無条件に呼ぶため、アプリケーションの実装に関係なく影響を受けます。
- PHP-FPM も通常の起動後は影響を受けうるとされています。ただし、FPM に対する完全な攻撃は実証されていません。
影響を受ける版と修正版は次のとおりです(PHP 8 ChangeLog)。
| ブランチ | 影響を受ける版 | 修正版 |
|---|---|---|
| 8.2 | 8.2.35 未満 | 8.2.35 |
| 8.3 | 8.3.36 未満 | 8.3.36 |
| 8.4 | 8.4.27 未満 | 8.4.27 |
| 8.5 | 8.5.12 未満 | 8.5.12 |
修正は各ブランチ 1 コミットで、タイトルは "Avoid state corruption via bailout" です。
| ブランチ | コミット |
|---|---|
| 8.5 | 31c0ea7d7ff1 |
| 8.3 | 3c832b523ee1 |
| 8.2 | 01a40e89fbfc |
規模は +11,556 / −1,017 行と大きく、Zend/zend_alloc.c などを変更しています。
AL2023 リポジトリの現状
執筆時点で、AL2023 の最新リポジトリにある版は次のとおりでした。いずれも影響を受ける版です。
| パッケージ | 版 |
|---|---|
| php8.2 | 8.2.34-1.amzn2023.0.1 |
| php8.3 | 8.3.35-1.amzn2023.0.1 |
| php8.5 | 8.5.11-1.amzn2023.0.1 |
あなたが読んでいる時点の状況は、次のコマンドで確認できます。修正版がすでに出ていれば、この記事の手順は必要ありません。
dnf repoquery -q --releasever=latest --latest-limit=1 \
--qf '%{name}-%{version}-%{release}' php8.2-cli php8.3-cli php8.5-cli
方針: なぜ SRPM の版を上げるのか
最初は、AL2023 の SRPM に修正コミットをパッチとして追加する方法を試しました。差分が最小で済むからです。しかし、この方法はうまくいきませんでした。
-
8.5: 修正コミットが、8.5.11 より後に入った別の変更に依存しています。
--fuzz=0ではパッチの適用に失敗する hunk が出ます。 -
8.2 / 8.3: パッチは当たりますが、リンクで失敗します。
undefined reference to `php_var_unserialize_set_incomplete_classes_only' undefined reference to `php_url_scanner_early_rinit'修正コミットは re2c のソース(
.re)を変更しています。ところが、リリース tarball には生成済みの.cが同梱されていて、ビルド時に再生成されません。そのため、変更が生成済みのコードに反映されないまま残ります。
そこで、SRPM が参照する tarball を php.net の修正版(php-8.x.y.tar.xz)に差し替える方針にしました。修正版の tarball には、正しく生成されたソースが入っています。AL2023 独自のパッチ群は、そのまま修正版にも当たりました(後述の %prep で確認しています)。
版を上げると、脆弱性の修正以外の変更も入ります。
| 版上げ | 脆弱性の修正以外の変更 |
|---|---|
| 8.2.34 → 8.2.35、8.3.35 → 8.3.36 | CI と Windows 向けの変更、同梱 PCRE2 の修正のみ。AL2023 はシステムの pcre2 を使ってビルドするので、同梱 PCRE2 の修正は関係しません |
| 8.5.11 → 8.5.12 | upstream のほかのバグ修正も含みます。ChangeLog を確認し、アプリケーションでも動作を確認してください |
前提と環境
ビルドは public.ecr.aws/amazonlinux/amazonlinux:2023 のコンテナ内で行います。コンテナのアーキテクチャは、パッケージを入れる先と同じにしてください。
| 対象 | ビルド環境(筆者が使ったもの) |
|---|---|
| Graviton(aarch64) | Graviton の EC2(c7g.4xlarge)上の Docker |
| x86_64 | x86 ホストの Docker(--platform linux/amd64) |
x86 ホストで QEMU エミュレーションを使って arm64 をビルドすることもできますが、非常に遅いのでおすすめしません。
コンパイルオプションは、SRPM と redhat-rpm-config から引き継がれます。自分で指定する必要はありません。公式ビルドと同じオプションになります。
| アーキテクチャ | 主なオプション |
|---|---|
| x86_64 | -march=x86-64-v2 -mtune=generic |
| aarch64 | -march=armv8.2-a+crypto -mtune=neoverse-n1 |
%check(テスト)を含むビルド時間の目安は次のとおりです。
| 版 | 環境 | 時間 |
|---|---|---|
| 8.5 | c7g.4xlarge | 約 12 分 |
| 8.3 | c7g.4xlarge | 約 9〜11 分 |
| 8.2 | 6 コアの Intel デスクトップ | 約 14〜15 分 |
ビルド手順
以下は php8.5 の例です。8.3 / 8.2 の場合は、版番号を読み替えてください。
| 対象 | SRPM | 修正版 |
|---|---|---|
| php8.5 | php8.5-8.5.11-1.amzn2023.0.1 |
8.5.12 |
| php8.3 | php8.3-8.3.35-1.amzn2023.0.1 |
8.3.36 |
| php8.2 | php8.2-8.2.34-1.amzn2023.0.1 |
8.2.35 |
1. ビルド用コンテナを起動する
mkdir -p out
docker run -d --name php-rebuild -v "$PWD/out:/out" \
public.ecr.aws/amazonlinux/amazonlinux:2023 sleep infinity
docker exec -it php-rebuild bash
x86 ホストで x86_64 向けにビルドする場合は、docker run に --platform linux/amd64 を付けます。
以降のコマンドはコンテナ内で実行します。
2. ビルドツールを入れる
dnf install -y dnf-plugins-core rpm-build rpmdevtools
# %prep は tarball の署名検証に gpgv2 を使う。gnupg2-minimal では足りない
dnf -y swap gnupg2-minimal gnupg2
useradd -m builder
rpmbuild は root で実行せず、一般ユーザー builder で実行します。
3. SRPM を取得してビルド依存を入れる
mkdir -p /src && cd /src
dnf download --source php8.5-8.5.11-1.amzn2023.0.1
rpm -K *.src.rpm # "digests signatures OK" と出ることを確認する
dnf builddep -y /src/*.src.rpm
cp /src/*.src.rpm /home/builder/ && chown builder /home/builder/*.src.rpm
su - builder -c 'rpm -ivh --define "_topdir /home/builder/rb" /home/builder/php8.5-*.src.rpm'
4. 【推奨】無改造の SRPM で基準ビルドを取る
%check のテストには、環境によって失敗するものがあります(後述)。版上げによって新たに失敗したテストかどうかを判断するには、比較の基準が必要です。そこで、spec を変更する前に一度ビルドしてログを残しておくことをおすすめします。
T=/home/builder/rb; S=$(ls $T/SPECS/*.spec)
su - builder -c "rpmbuild --define '_topdir $T' -ba $S" 2>&1 | tee /src/build-baseline.log
grep -A30 'FAILED TEST SUMMARY' /src/build-baseline.log
# 基準ビルドの RPM は配布物に混ざらないよう削除する
rm -rf $T/RPMS/* $T/SRPMS/*
基準ビルドの RPM は、修正版の RPM と同じ RPMS/ ディレクトリに出力されます。削除しておかないと、配布物に未修正の RPM が混ざる原因になります。
5. spec の版と Release を書き換える
T=/home/builder/rb; S=$(ls $T/SPECS/*.spec)
sed -i 's/^%global upver .*/%global upver 8.5.12/' $S
sed -i 's/^Release: .*/Release: 0.1.local%{?dist}/' $S
# 消さないと Release の末尾に .0.1 が付く
sed -i '/^%define _trivial/d; /^%define _buildid/d' $S
0.1.local の部分は好きな文字列に変えてかまいません。ただし、公式の 1.amzn2023.0.1 より小さい値になるようにしてください。理由は「版の付け方と公式版への置き換わり」で説明します。
6. 修正版の tarball と署名を取得して検証する
AL2023 の spec では、tarball が Source0、署名(.asc)が Source21 です。spectool に -s を複数指定すると最後の 1 つしか使われないため、1 つずつ実行します。
su - builder -c "cd $T/SOURCES && spectool -g -s 0 $S && spectool -g -s 21 $S"
Source の番号は spec の版によって変わる可能性があります。不安な場合は、spectool -l $S で一覧を確認してから実行してください。
php.net が公開している sha256 と照合します。
echo "08bc2eba2a588654ade1357174aa646b761556c862dda0678345ee29ed481209 $T/SOURCES/php-8.5.12.tar.xz" | sha256sum -c
執筆時点で php.net に掲載されていた tar.xz の sha256 は次のとおりです。
| ファイル | sha256 |
|---|---|
php-8.5.12.tar.xz |
08bc2eba2a588654ade1357174aa646b761556c862dda0678345ee29ed481209 |
php-8.3.36.tar.xz |
dd54693aa334c5c4d72e9aee96b082c2473750a18a6c1d105789c93a3b1692fd |
php-8.2.35.tar.xz |
5737b98601fe5ab1b8c5db0c82ed3158acb9283ed3081ffe2faffb9ac81455e6 |
この表を鵜呑みにせず、php.net から直接取得した値と照合してください。
curl -s 'https://www.php.net/releases/index.php?json&version=8.5'
出力のうち、php-8.5.12.tar.xz に対応する sha256 の値を使います。
7. %prep を実行する
su - builder -c "rpmbuild --define '_topdir $T' -bp $S"
%prep では、次の 2 つが行われます。
- SRPM に同梱されている keyring による tarball の署名検証
- AL2023 独自パッチの適用
ここでエラーが出なければ、署名検証もパッチ適用も成功しています。
8. ビルドする
su - builder -c "rpmbuild --define '_topdir $T' -ba $S" 2>&1 | tee /src/build.log
grep -A30 'FAILED TEST SUMMARY' /src/build.log
9. %check の結果を基準ビルドと比べる
この spec は %check の終了コードを無視します。そのため、テストが失敗してもビルド自体は成功します。 FAILED TEST SUMMARY を必ず確認してください。
筆者の環境で失敗したテストは次のとおりです。いずれも、版を上げる前と後で同じ結果でした。
| 版 | 失敗数 | 失敗したテスト |
|---|---|---|
| 8.5 | 4 | pcre gh11956、openssl ecc_custom_params、opcache preload_006・preload_011
|
| 8.3 | 2 |
gh11956、ecc_custom_params
|
| 8.2 | 1 | gh11956 |
失敗するテストは環境によって変わりうるので、手順 4 で取った基準ビルドのログと比較してください。版上げで新たに失敗したテストがなければ問題ありません。
10. RPM を回収する
cd /out
find $T/RPMS -name '*local*.rpm' ! -name '*debuginfo*' ! -name '*debugsource*' -exec cp {} /out/ \;
sha256sum *.rpm > SHA256SUMS
ls -1
ホスト側の ./out に RPM と SHA256SUMS が出力されます。
版の付け方と公式版への置き換わり
Release: 0.1.local%{?dist} でビルドすると、版は 8.5.12-0.1.local.amzn2023 になります。rpmdev-vercmp で比べると、次の順に並びます。
8.5.11-1.amzn2023.0.1 (現行の公式版)
< 8.5.12-0.1.local.amzn2023 (自前ビルド)
< 8.5.12-1.amzn2023.0.1 (将来の公式版の想定)
rpmdev-vercmp 8.5.12-0.1.local.amzn2023 8.5.11-1.amzn2023.0.1
rpmdev-vercmp 8.5.12-0.1.local.amzn2023 8.5.12-1.amzn2023.0.1
この順序から、次のことが言えます。
- 現行の公式版より新しいので、
dnf upgradeで自前ビルドが入ります。 - 将来の公式版
8.5.12-1.amzn2023.0.1より古いので、公式版が出ればdnf upgradeで自動的に置き換わります。
AWS が upstream の版を上げずに修正をバックポートした場合(例: 8.5.11-1.amzn2023.0.2)は、自前ビルドのほうが「新しい」と判定されます。この場合、dnf upgrade では公式版に戻りません。dnf distro-sync を使うか、AMI を作り直してください(「切り戻し」を参照)。
本番相当環境での検証
いきなり本番に入れず、本番ホストを再現したコンテナで検証します。
1. 本番の状態を調べる
本番ホストで次を確認します。
rpm -qa 'php*' | sort # 入っている PHP パッケージ
rpm -q --qf '%{version}\n' system-release # AL2023 のリリース(2023.x.YYYYMMDD の形式)
php -m > /tmp/php-m.before # 拡張モジュールの一覧(比較用)
2. 本番相当のコンテナを作ってスナップショットにする
ベースイメージは、本番ホストのリリースに合ったタグを使ってください。 最新イメージに古い releasever の PHP を入れようとすると、openssl 3.5 と 3.0 の衝突が起きて失敗します。
<release> は、手順 1 で確認した本番の system-release の版に置き換えてください。
docker run -it --name prodlike \
public.ecr.aws/amazonlinux/amazonlinux:<release>.0 bash
# --- コンテナ内 ---
# releasever を本番に合わせて固定する(末尾の .0 は付けない)
echo <release> > /etc/dnf/vars/releasever
dnf install -y php8.5-cli php8.5-fpm ... # 本番の rpm -qa 'php*' と同じものを入れる
exit
docker commit prodlike prodlike:snapshot
3. 使い捨てのコンテナで試す
以降の検証は、スナップショットから起動した使い捨てのコンテナで行います。失敗したら作り直すだけで済みます。
docker run --rm -it -v "$PWD/out:/rpms" prodlike:snapshot bash
この中で、次の「適用」と「切り戻し」の手順を一通り試します。
適用
1. RPM を検証してインストールする
cd /rpms
sha256sum -c SHA256SUMS
REL=8.5.12-0.1.local.amzn2023
ARCH=$(uname -m) # aarch64 または x86_64
# 入っている php8.5* と同じ名前の自前ビルドだけを選ぶ(PECL 拡張は再ビルドしていないので除外)
pkgs=""
for n in $(rpm -qa --qf '%{name}\n' "php8.5*" | grep -v pecl); do
pkgs="$pkgs ./$n-$REL.$ARCH.rpm"
done
dnf upgrade -y --best --disablerepo='*' $pkgs
dnf upgrade のオプションには、それぞれ理由があります。
-
--disablerepo='*': ローカルの RPM だけを使います。サードパーティのリポジトリが干渉しなくなります。 -
--best: 必須です。 付けないと、依存を解決できないパッケージを dnf が黙って飛ばし、それでもComplete!を表示して終了コード 0 で終わります(詳しくは「ハマりどころ」)。
対応するファイルが out/ にないパッケージが本番に入っていると、dnf はファイルが見つからないというエラーで止まります。その場合は、ビルドしたパッケージの一覧と本番のパッケージを突き合わせてください。
2. 漏れがないことを確認する
# 何も表示されなければ、すべて自前ビルドに置き換わっている
rpm -qa --qf '%{name}-%{release}\n' 'php8.5*' | grep -v pecl | grep -v local
3. 動作を確認する
筆者は、更新後に次の項目を確認しました。
php -v # 8.5.12 になっていること
php -m | diff /tmp/php-m.before - # 拡張モジュールの一覧が更新前と同じこと
php-fpm -t # FPM の設定が有効なこと
rpm -Va 'php*' # 設定ファイル以外に差分がないこと
find /etc -name '*.rpmnew' -o -name '*.rpmsave' # 何も出ないこと
PECL 拡張
| 種類 | 結果 |
|---|---|
AL2023 がパッケージで配布している PECL 拡張(php8.5-pecl-igbinary / msgpack / redis6) |
再ビルドは不要でした。8.5.x の中では Zend API が同じなので、更新後もそのまま動作しました |
pecl install で手動導入した拡張 |
筆者が 8.2.x で試した拡張は、更新後も読み込まれました |
ほかの拡張モジュールについては未検証です。php -m の比較で確認してください。
php-fpm の再起動
spec の %transfiletriggerin fpm が、トランザクションの最後に systemctl try-restart php-fpm を実行します。そのため、稼働中の php-fpm は自動的に再起動されます。再起動の数秒間は、処理中のリクエストが落ちる可能性があります。
再起動後のマスタープロセスが新しいバイナリで動いていることを確認します。
# 出力に "(deleted)" が含まれていなければ、新しいバイナリで動いている
readlink /proc/$(systemctl show -p MainPID --value php-fpm)/exe
常駐している PHP CLI プロセス
cron から起動した長時間処理やキューワーカーなどの常駐 PHP CLI プロセスは、再起動するまで古いバイナリのまま動き続けます。自分で再起動してください。
ハマりどころ
--best を付けないと、依存エラーのパッケージが黙って飛ばされる
--best を付けずに dnf upgrade を実行すると、次のメッセージを出してパッケージを飛ばします。
Skipping packages with broken dependencies
それでも最後は Complete! と表示され、終了コードも 0 です。そのため、スクリプトから実行すると成功したように見えます。--best を必ず付け、適用後は grep -v local の確認を必ず行ってください。
古い AL2023 リリースで php8.2-sodium の依存が解決できない
libsodium 1.0.18 が入っている古い AL2023 リリースで php8.2 を使っているホストでは、依存エラーが起きます。
| libsodium | |
|---|---|
自前ビルドの php8.2-sodium が要求するもの |
libsodium.so.26 |
| 古いホストに入っているもの | libsodium 1.0.18(libsodium.so.23) |
2023.11 以降のリリースには、すでに 1.0.19 が入っています。
対処として、最新リポジトリから libsodium 1.0.19 を取得し、同じトランザクションで入れます。まず、古い libsodium をほかに使っているパッケージがないか確認します。php8.2-sodium 以外が出てきた場合は、そのパッケージも libsodium 1.0.19 で動くかを確認してください。
rpm -q --whatrequires 'libsodium.so.23()(64bit)'
ビルド環境(最新の AL2023 コンテナ)で取得します。
dnf download --arch x86_64 libsodium-1.0.19-5.amzn2023
対象ホストで、PHP のパッケージと一緒に渡します。
dnf upgrade -y --best --disablerepo='*' $pkgs ./libsodium-1.0.19-5.amzn2023.x86_64.rpm
検証用のベースイメージの版が本番と違う
「本番相当環境での検証」で書いたとおり、最新イメージに古い releasever の PHP を入れると、openssl 3.5 と 3.0 が衝突します。ベースイメージのタグは本番のリリースに合わせてください。/etc/dnf/vars/releasever に書く値は、タグの末尾の .0 を除いたものです。
gnupg2-minimal では %prep が失敗する
%prep では、tarball の署名を gpgv2 で検証します。コンテナに標準で入っている gnupg2-minimal には gpgv2 がないため失敗します。dnf -y swap gnupg2-minimal gnupg2 で入れ替えてください。
spectool -s を複数指定すると最後の 1 つだけが使われる
spectool -g -s 0 -s 21 のように指定すると、最後の 1 つしか取得されません。1 つずつ実行してください。
_trivial / _buildid が Release の末尾に付く
AL2023 の spec には %define _trivial と %define _buildid があります。これを残したままにすると、Release の末尾に .0.1 が付きます。意図した版にするには、この 2 行を消してください。
基準ビルドの RPM が配布物に混ざる
基準ビルドの RPM は、修正版と同じ RPMS/ に出力されます。修正版をビルドする前に削除してください。
%check が失敗してもビルドは成功する
spec が %check の終了コードを無視するので、テストが失敗してもビルドは成功します。FAILED TEST SUMMARY を確認し、基準ビルドと比べてください。
切り戻し
dnf distro-sync -y 'php8.5*'
この手順は、本番相当コンテナで確認しました。
- 実行すると、ホストで固定している releasever の公式版に戻ります。
- パッケージの構成は、適用前と同じになります。
libsodium も入れ替えた古い php8.2 ホストでは、libsodium も一緒に戻します。
dnf distro-sync -y 'php8.2*' libsodium
切り戻すと、脆弱性のある版に戻ります。
複数台・AMI への展開
ここからは一般的な構成例です。
-
確認済み: EC2 Image Builder(AL2023 / arm64)で、
S3Downloadで RPM を取得し、dnf upgrade --best --disablerepo='*'で入れ替え、Release とPHP_VERSIONを検査する流れは、8.5.12 と 8.3.36 の両方で通しました。 - 未検証: 記事中のコマンドやコンポーネント定義は、筆者の環境に固有の部分を取り除いて書き直したものです。この字面のままでは流していません。読者の環境に合わせて調整し、検証してから使ってください。
RPM を S3 に置く
RPM と SHA256SUMS を S3 に置きます。
aws s3 cp out/ s3://<your-bucket>/php-rebuild/8.5.12-0.1.local/ --recursive
インスタンスに取得させる方法は、次のどちらかです。
-
インスタンスロールに権限を付ける: そのプレフィックスに対する
s3:GetObjectを許可します。暗号化が SSE-S3 なら、KMS の権限は要りません。 - 署名付き URL を使う: 有効期限の短いものを発行します。
SSM Run Command で 1 台ずつ適用する
ステージング環境から始めて、1 台ずつ適用します。--max-concurrency 1 --max-errors 0 にすると、1 台でも失敗した時点で止まります。
aws ssm send-command \
--document-name AWS-RunShellScript \
--targets 'Key=tag:<your-tag-key>,Values=<your-tag-value>' \
--max-concurrency 1 --max-errors 0 \
--parameters 'commands=["bash /path/to/apply-php-rebuild.sh"]'
apply-php-rebuild.sh の中身は、「適用」の手順(S3 からの取得、sha256sum -c、dnf upgrade --best --disablerepo='*'、漏れの確認、readlink の確認)をスクリプトにしたものです。
AMI に焼き込む
稼働中のインスタンスを更新しただけでは不十分です。Auto Scaling が新しいインスタンスを起動すると、脆弱な AMI から起動されてしまいます。AMI にも RPM を焼き込み、Launch Template を更新してください。
CloudFormation で Launch Template の ImageId に SSM パラメータ型(AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>)を使っている場合、SSM の値を新しい AMI ID に変えただけでは、Launch Template は古い AMI を指したままです。SSM の値はスタックの作成・更新のときにしか解決されないため、AMI を焼いたあとにスタックを更新して、Launch Template に反映してください。ASG に UpdatePolicy(AutoScalingRollingUpdate など)があると、そのスタック更新でインスタンスが入れ替わる点にも注意してください。
EC2 Image Builder の場合は、次のようなコンポーネントで実現できます。
-
S3Downloadステップで RPM を取得する -
ExecuteBashステップで同じdnf upgrade --best --disablerepo='*'を実行する - すべての PHP パッケージが自前の Release を持ち、
PHP_VERSIONが修正版になっていることを検査する
name: php-rebuild-upgrade
schemaVersion: 1.0
phases:
- name: build
steps:
- name: Download
action: S3Download
inputs:
- source: s3://<your-bucket>/php-rebuild/8.5.12-0.1.local/*
destination: /tmp/php-rebuild/
- name: Upgrade
action: ExecuteBash
inputs:
commands:
- |
set -euo pipefail
cd /tmp/php-rebuild
sha256sum -c SHA256SUMS
REL=8.5.12-0.1.local.amzn2023
ARCH=$(uname -m)
pkgs=""
for n in $(rpm -qa --qf '%{name}\n' "php8.5*" | grep -v pecl); do
pkgs="$pkgs ./$n-$REL.$ARCH.rpm"
done
dnf upgrade -y --best --disablerepo='*' $pkgs
# 自前ビルドに置き換わっていないパッケージがあれば失敗させる
if rpm -qa --qf '%{name}-%{release}\n' 'php8.5*' | grep -v pecl | grep -v local; then
echo "some php packages were not upgraded" >&2
exit 1
fi
if [ "$(php -r 'echo PHP_VERSION;')" != "8.5.12" ]; then
echo "unexpected PHP_VERSION" >&2
exit 1
fi
bash では、! で否定したコマンドが失敗しても set -e は発動しません。たとえば ! rpm -qa ... | grep -v local と書いても、検査に失敗したときにスクリプトが止まりません。検査は if ...; then exit 1; fi の形で書いてください。
set -o pipefail の下で php -m | grep -qi 'Zend OPcache' のように書くと、拡張が読み込めていても検査が失敗することがあります。grep -q は一致した時点で読むのをやめるため、まだ書き込み中の php が SIGPIPE で異常終了し、pipefail がそれをパイプ全体の失敗とみなすからです。
筆者の環境では、直前の php -v が with Zend OPcache と表示しているのに、「OPcache が読み込まれていない」としてビルドが落ちました。出力が大きいほど起きやすく、手元で試すと再現しないことがあります。出力をいったん変数に受けてから調べてください。
mods=$(php -m)
if ! grep -qi 'Zend OPcache' <<<"$mods"; then
echo "Zend OPcache is not loaded" >&2
exit 1
fi
grep -v のように入力を最後まで読むコマンドなら、この問題は起きません。head -1 も grep -q と同じ理由で避けてください。
公式版が出たら
ALAS で修正版のパッケージが公開されたら、公式版へ戻します。
- 公式版は自前ビルドより Release が大きいので、通常の
dnf upgradeで置き換わります。 - AMI のビルドから、自前 RPM を入れるステップを外します。
-
localの Release が残っていないことを確認します。
dnf upgrade -y 'php8.5*'
# 何も表示されなければ、公式版に戻っている
rpm -qa --qf '%{name}-%{version}-%{release}\n' 'php*' | grep local
公式の修正が版上げではなくバックポートで出た場合は、dnf upgrade では置き換わりません。「版の付け方と公式版への置き換わり」の注意書きを参照し、dnf distro-sync を使ってください。