エラーの内容
新しいバージョンをElastic Beanstalkにプッシュしたところ、デプロイが失敗しました。EBコンソールがSevereに変わり、イベントログに以下のようなメッセージが表示されています:
ERROR: Your WSGIPath refers to a file that does not exist.
Instance deployment failed. For details, see 'eb-engine.log'.
Environment health has transitioned from Ok to Severe
多くの場合、ロードバランサーのヘルスチェック失敗も同時に発生します。LBがインスタンスへのリクエストを繰り返すものの、エラーしか返ってこないため、EBがインスタンスをunhealthyと判定します。環境のステータスは2分以内にOk → Warning → Severeと悪化していきます。
2つの問題は別々ですが、互いに関連しています。まずWSGIの設定ミスを修正してください。アプリが正常に起動さえすれば、ヘルスチェックの失敗はほぼ自動的に解消されます。
原因
EBはWSGI呼び出し可能オブジェクトの場所を把握する必要があります。.ebextensions、Procfile、またはaws:elasticbeanstalk:container:python名前空間を通じてこのパスを参照します。そのパスがデプロイ用zipの内容と一致しない場合、アプリサーバー(Amazon Linux 2ではApache + mod_wsgi、AL2023ではgunicorn)が起動しません。
よくある原因:
WSGIPathがapplication.pyを指したままだが、ファイルをリネームまたはプロジェクト構成を変更した- Djangoプロジェクトをデプロイする際に、パスを
myproject/wsgi.pyに設定していない .ebignoreまたは.gitignoreがwsgiファイルをバンドルから密かに除外している- CI/CDのパッケージングミス — S3にアップロードされたzipにファイルが含まれていない
- ヘルスチェックのパスが200ではなくリダイレクト(301/302)や認証画面を返している
ステップ1 — 何もする前にログを確認する
当てずっぽうはデプロイの無駄遣いです。まずログを取得しましょう:
# EB CLIを使う場合
eb logs
# またはリアルタイムでストリーミング
eb logs --stream
注目すべきファイルは2つです。eb-engine.logにはEBが読み込もうとしたパスが正確に記録されています。web.stdout.logにはアプリサーバーが起動しようとした際の内容(インポートエラー、環境変数の不足など)が記録されています。
コンソール操作が好みの場合は、Environment → Logs → Request Logs → Last 100 Linesから確認できます。
ステップ2 — WSGIPathを修正する
EBが現在どのパスを使うよう設定されているか確認します:
eb config
エディタで環境設定が開きます。以下のセクションを探してください:
aws:elasticbeanstalk:container:python:
WSGIPath: application:application
形式はPythonオブジェクトの場合はmodule_path:callable、DjangoのWSGIファイルの場合は通常のファイルパスです。一般的な構成における正しい値の例を示します:
Flask(単一ファイルの場合)
# application.py に含まれる内容: app = Flask(__name__)
aws:elasticbeanstalk:container:python:
WSGIPath: application:app
Django
aws:elasticbeanstalk:container:python:
WSGIPath: myproject/wsgi.py
myprojectは実際のDjangoプロジェクトフォルダ(リポジトリのルートではなく、settings.pyが含まれるフォルダ)に置き換えてください。
最もすっきりした管理方法は、.ebextensions/python.configにバージョン管理することです:
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: myproject/wsgi.py
NumProcesses: 1
NumThreads: 15
こうすることで、すべてのデプロイに正しいパスが含まれるようになり、誰かが誤って上書きするかもしれない環境設定に依存しなくて済みます。
Djangoの場合は、settingsモジュールも設定されていることを確認してください:
eb setenv DJANGO_SETTINGS_MODULE=myproject.settings
ステップ3 — デプロイバンドルにファイルが実際に含まれているか確認する
eb deployを実行すると、EBはgitを使ってプロジェクトをzip圧縮します。つまり.gitignoreの内容が反映されます。wsgiファイルがトラッキングされていなければ、デプロイには含まれません。
# EBが実際に含めるファイルを確認
git ls-files | grep wsgi
何も出力されない場合、そのファイルはトラッキングされていません。コミットするか、.ebignoreで除外設定を上書きしてください:
# .ebignore — .gitignoreで除外されていても強制的に含める
!myproject/wsgi.py
CI/CDで手動でzipを作成している場合は、その内容を直接確認してください:
unzip -l deploy.zip | grep wsgi
これにより、パッケージングステップが誤ったディレクトリから実行されて内部構造が不正なzipが生成されるという、意外によくあるCIのミスを発見できます。
ステップ4 — ヘルスチェックのパスを修正する
アプリ自体は正常に動いていても、ロードバランサーがインスタンスをunhealthyと判定する場合があります。デフォルトでは、EBは30秒ごとに/にアクセスします。そのパスがリダイレクト(例:ログインページへ)するか、2xx以外を返す場合、チェックが失敗します。
常に200を返すシンプルなヘルスエンドポイントを追加しましょう:
# Flask
@app.route('/health')
def health():
return 'OK', 200
# Django (urls.py)
from django.http import HttpResponse
urlpatterns = [
path('health/', lambda request: HttpResponse('OK')),
# ... 残りのURLパターン
]
次に、EBがそのエンドポイントを使うよう設定します。コンソールの場合:Configuration → Load Balancer → Processes → Health check path → /health。
または.ebextensionsに記述します:
option_settings:
aws:elasticbeanstalk:application:
Application Healthcheck URL: /health
ステップ5 — 再デプロイして確認する
eb deploy --staged
実行中のイベントをリアルタイムで確認します:
eb events -f
デプロイは成功したがhealthがまだSevereの場合は、しばらく待ってください。EBがOkに戻るには、連続して複数回(通常3回、約90秒間隔)のヘルスチェック成功が必要です。
確認方法
以下の3つすべてが満たされれば完了です:
- コンソールにHealth: Ok(緑色)が表示されている
eb statusがHealth: Greenと報告している- アプリのURLが正常に応答している
eb status
# 期待される出力:
# Environment details for: your-env-name
# Status: Ready
# Health: Green
curl -I https://your-env.elasticbeanstalk.com/health
# 期待される出力: HTTP/1.1 200 OK
クイックリファレンス — よく使うWSGIPathの値
- Flask (application.py → app):
application:app - Flask (application.py → application):
application:application - Django:
myproject/wsgi.py - FastAPI with Mangum:
main:handler(ただしFastAPIは通常EBではなくLambdaで動かします)
それでも失敗する場合は?SSHで直接接続する
上記をすべて確認してもデプロイが失敗し続ける場合は、インスタンスに直接接続してください:
eb ssh
# アプリサーバーのプロセスを確認
sudo systemctl status web
# エンジンログを直接確認
sudo tail -50 /var/log/eb-engine.log
十中八九、見つかるのは環境変数の不足です。DjangoのSECRET_KEYが典型的な例です。アプリが起動時にクラッシュし、1件もリクエストを処理できないまま、EBはすべてをヘルスチェックの失敗として報告します。本当のエラーはヘルスチェックのイベントではなく、web.stdout.logに埋もれています。

