はじめに
GMOコネクトの小倉です。
ECS(Fargate)上で稼働していた Keycloak 16.1.1 が、ある日突然ヘルスチェックに通らなくなりました。アプリのコードもDockerイメージもタスク定義も、2022年から一切変更していないのに、です。
調査の結果、Fargate のプラットフォームパッチ適用に伴い、コンテナ内の hostname --all-ip-addresses の挙動が変わったことで、WildFly の HA 設定が壊れていたことが原因でした。
本投稿では、原因の特定プロセスと対処法を共有します。同じような構成で運用されている方の一助になれば幸いです。
まとめ
- Fargate プラットフォームパッチにより、コンテナ内のネットワーク情報取得コマンドの挙動が変わることがある
- WildFly の
interface privateが解決不能になり、47 サービスが連鎖停止 →/authが 404 に → ALB ヘルスチェック不合格 → ECS がタスクを TERM -
再ビルド不要、ECS タスク定義の環境変数
BIND_OPTSを追加するだけで解消
構成
ALB (Target Group)
└─ ECS Service (Fargate)
└─ Keycloak 16.1.1 コンテナ
└─ Aurora Serverless v2 (PostgreSQL)
- Keycloak は WildFly ベース(16.1.1)で、
standalone-ha.xmlを使用 - JGroups の JDBC_PING でクラスタ構成
- ALB のヘルスチェックは
HTTP:8080 /auth/realms/masterで 200 を期待
発生した事象
症状
- ALB ターゲットグループで Keycloak タスクが Unhealthy
-
curl http://<タスクIP>:8080/auth/realms/master→ 404 Not Found -
curl http://<タスクIP>:8080/→ 200 OK(WildFly の welcome ページのみ) - ECS タスクの Stopped reason:
Task failed ELB health checks
ポイント
/ が 200 を返すので「起きている」ように見えますが、これは Undertow の静的ファイルハンドラ(welcome-content) が返しているだけで、Keycloak アプリケーション(/auth)が載っている証拠にはなりません。
原因の特定
起動ログの ERROR
ERROR [org.jboss.msc.service.fail] MSC000001: Failed to start service
org.wildfly.network.interface.private:
WFLYSRV0082: failed to resolve interface private
WFLYCTL0186: Services which failed to start:
service org.wildfly.network.interface.private:
WFLYSRV0082: failed to resolve interface private
WFLYCTL0448: 47 additional services are down due to their dependencies
being missing or failed
ERROR [org.jboss.as] WFLYSRV0026: Keycloak 16.1.1 (WildFly Core 18.0.4.Final)
started (with errors) in 3524ms
- Started 470 of 930 services
(54 services failed or missing dependencies,
694 services are lazy, passive or on-demand)
WildFly の interface private が解決できず、JGroups / Infinispan 等の HA 系サービスが連鎖的にダウン。WAR のデプロイ自体は完了しているものの、アプリとして /auth をサービスできない状態でした。
なぜ interface private が解決できなくなったか
Keycloak 16.1.1 の公式 Docker イメージの docker-entrypoint.sh(GitHub)には、以下のロジックがあります。
if [[ -z ${BIND:-} ]]; then
BIND=$(hostname --all-ip-addresses)
fi
if [[ -z ${BIND_OPTS:-} ]]; then
for BIND_IP in $BIND
do
BIND_OPTS+=" -Djboss.bind.address=$BIND_IP -Djboss.bind.address.private=$BIND_IP "
done
fi
SYS_PROPS+=" $BIND_OPTS"
hostname --all-ip-addresses でコンテナの IP を取得し、それを jboss.bind.address.private に渡しています。
Fargate のプラットフォームパッチ適用後、このコマンドが正しい IP を返さなくなった(空や不正な値になった)ことで、WildFly が private インターフェースを解決できなくなったと考えられます。
Fargate パッチとの因果
以下の事実から、Fargate プラットフォームパッチが主因と判断しました。
- Docker イメージは 2022 年から一切変更なし(ECR の
latestは同一ダイジェスト) - ECS タスク定義も 変更なし
- アプリケーションコードも 変更なし
- Aurora のマイナーバージョンアップ(16.2→16.11)があったが、ログ上 DB 接続は成功しており、エラーは DB より手前の WildFly ネットワーク層で発生
実際に、AWS Health Dashboard から以下の通知が届いていました。
AWS Fargate has deployed a new platform version revision
and will retire any tasks running on previous platform version revision(s)
starting at Wed, 8 Apr 2026 00:00 GMT as part of routine task maintenance.
Fargate は利用者に個別の承諾なく OS・ランタイム・ネットワークスタックを更新 します。これにより、コンテナ内の NIC 構成や hostname コマンドの挙動が変わることがあります。
対処法
再ビルド不要:ECS タスク定義の環境変数追加のみ
docker-entrypoint.sh は BIND_OPTS が既にセットされていればそれをそのまま使う ロジックになっています。したがって、ECS タスク定義の environment に以下を追加するだけで解決しました。
{
"name": "BIND_OPTS",
"value": "-Djboss.bind.address=0.0.0.0 -Djboss.bind.address.private=0.0.0.0"
}
これにより hostname --all-ip-addresses の結果に依存しなくなり、全インターフェースでリッスンするようになります。
修正後の起動ログ(正常)
WFLYSRV0025: Keycloak 16.1.1 (WildFly Core 18.0.4.Final)
started in 10933ms
- Started 674 of 976 services
(696 services are lazy, passive or on-demand)
-
failed to resolve interface private→ 出ない -
Started (with errors)→ 出ない -
Registered web context: '/auth'→ 出る -
curl /auth/realms/master→ 200 OK
注意点
-Djboss.bind.address.private=0.0.0.0 だけでは不十分だった
最初に JAVA_OPTS_APPEND で -Djboss.bind.address.private=0.0.0.0 だけを追加しましたが、効果がありませんでした。
理由は、docker-entrypoint.sh が SYS_PROPS に BIND_OPTS を組み立てて standalone.sh の コマンドライン引数 として渡すため、JAVA_OPTS 側で同じプロパティを設定しても SYS_PROPS の値で上書き されてしまうためです。
したがって、BIND_OPTS 環境変数そのものを上書きする のが正解でした。
0.0.0.0 とクラスタ
単一タスクであれば 0.0.0.0 で問題ありません。複数タスクで JGroups クラスタを組む場合は、ノード間の advertised address や JDBC_PING の設定を別途確認してください。
教訓
- Fargate は「マネージドだから安心」ではない。プラットフォームパッチでコンテナ内の挙動が変わりうる
-
hostname --all-ip-addressesのような OS コマンドに依存する設定は脆い。環境変数で明示的に制御するのがベター -
WildFly が
Deployed "keycloak-server.war"と出していても、Started (with errors)なら/authは死んでいる ことがある -
/が 200 でも Keycloak が正常とは限らない(welcome-content は別経路で配信される) -
古い Docker イメージでも
docker-entrypoint.shを読んでおく と、環境変数でどこまで制御できるか分かる
最後に
ご一読いただき、ありがとうございました。
弊社では、AWSを使ったサービスの開発や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。