ダーク/ライト切り替え

Next.js standalone + Docker healthcheck が unhealthy になる罠と解決備忘録

投稿日 2025-12-27T11:21:42.634249+09:00

Next.js standalone + Docker healthcheck が unhealthy になる罠と解決備忘録

目次

目次を読み込み中...

概要

Next.js を standalone ビルドし、Docker イメージを極限まで軽量化した際に、
アプリ自体は正常に動作しているのに healthcheck が unhealthy になる という罠にハマった。

本記事では、

  • 発生した症状
  • 原因の切り分け
  • なぜこの問題が起きるのか
  • 正しい解決方法
  • standalone + Docker 運用時の注意点

を、後から見返してすぐ再現・回避できる形で整理する。


環境

  • GCP e2-micro
  • Docker / docker-compose
  • Next.js(standalone)
  • Nginx(別コンテナでリバースプロキシ)
  • curl 等のデバッグツールは **あえて入れない** 最小構成

発生した症状

  • ブラウザからは `https://example.com/healthz` が **200 OK**
  • Nginx 経由の通信も問題なし
  • しかし `docker ps` では frontend コンテナが

になる。


初期調査

1. curl が入っていない

👉 standalone + 軽量化の結果、curl は存在しない(これは想定通り)


2. node で healthz を直接叩く

❌ 接続失敗

しかし、

👉 ここで決定打


原因(結論)

Next.js standalone は localhost で listen していない

standalone ビルドされた Next.js は、

  • `127.0.0.1` / `localhost` では listen しない
  • Docker ネットワーク上の **eth0(172.18.x.x)でのみ listen**

している。

そのため:

アクセス元結果
ブラウザ(Nginx 経由)OK
Nginx コンテナOK
docker exec localhost
healthcheck(localhost 前提)

👉 アプリは正常、healthcheck の宛先だけが間違っていた


よくある誤解

  • 「Next.js が落ちている」 → ❌
  • 「standalone ビルドが壊れている」 → ❌
  • 「Docker の不具合」 → ❌

実際は:

**healthcheck の設計が standalone と噛み合っていないだけ**

解決方法(正解ルート)

localhost を使わない

healthcheck では eth0 の IPv4 アドレスを取得して叩く

docker-compose.yml(完成形)


なぜ curl を入れないのか

  • イメージサイズ増加
  • RSS 増加
  • 攻撃面の増加

👉 node があるなら node で十分

standalone 最小構成では curl 依存は避ける。


最終確認

これで解決。


注意点まとめ

  • standalone + Docker では localhost 前提を疑う
  • healthcheck は「アプリが listen しているアドレス」を叩く
  • 軽量化するとデバッグツールは消える(想定内)
  • unhealthy = アプリ異常とは限らない

総括

この問題は、

  • standalone
  • 極限までの軽量化
  • 正しい Docker ネットワーク理解

まで踏み込んだ人だけが遭遇する 最適化の副作用

逆に言えば、ここまで来ていれば設計は正しい。

同じ構成を再現する際は、
最初から eth0 ベースの healthcheck を書くことで回避できる。


以上、Next.js standalone + Docker healthcheck の罠と解決の備忘録。


準備中

このサイトをシェアする

Next.js standalone + Docker healthcheck が unhealthy になる罠と解決備忘録