AWS CodeDeploy デプロイ失敗を修正: 指定場所のスクリプトが300秒以内に完了しなかった

intermediate☁️ AWS2026-04-15| EC2上のAWS CodeDeploy(Amazon Linux 2 / Ubuntu 20.04以降)、CodeDeploy Agent 1.x

Error Message

Script at specified location: scripts/before_install.sh failed to complete in 300 seconds
#codedeploy#デプロイ#ライフサイクルフック#タイムアウト#ec2

エラーの概要CodeDeployのデプロイが途中で失敗し、次のようなエラーが表示されます:

Script at specified location: scripts/before_install.sh failed to complete in 300 seconds
LifecycleEvent - BeforeInstall
Status - Failed
Deployment failed

CodeDeployコンソールでデプロイが失敗とマークされ、EC2インスタンスは中途半端なデプロイ状態のまま放置されます。これはBeforeInstallAfterInstallApplicationStartValidateServiceなど、あらゆるライフサイクルフックで発生する可能性があります。

根本原因CodeDeployはライフサイクルフックスクリプトごとに**300秒(5分)**のハードタイムアウトを適用します。スクリプトが時間内に終了しない場合、CodeDeployはそれを強制終了してデプロイを失敗させます。

スクリプトがハングしたり長時間実行される典型的な原因は以下の通りです:

  • パッケージマネージャー(aptyum)がyes/noプロンプトを待っているか、低速なミラーでスタックしている- EC2インスタンスから到達不能な内部URLやエンドポイントにスクリプトがアクセスしようとして、TCPコネクションがハングしたまま- 数百のパッケージを含むnpm install、重いML依存関係のpip install、または実際に数分かかる同様のインストール処理- スクリプトがsystemdサービスのactive状態への移行を待ってから処理を続行しようとしている- スクリプト末尾のexit 0が欠落しており、実際の処理完了後もバックグラウンドプロセスがシェルを開いたままにしている- gpgdebconf、または特定のインストーラーで発生しやすい、スクリプト内で意図せずインタラクティブプロンプトが起動されている## 修正方法1:appspec.ymlでタイムアウトを増やすスクリプトが正当に長い時間を必要とする場合の最速の修正方法です。appspec.ymlの各フックはtimeoutキーを秒単位で受け付けており、最大3600秒(1時間)まで設定できます:
hooks:
  BeforeInstall:
    - location: scripts/before_install.sh
      timeout: 600
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 900
      runas: ec2-user

保存後に再デプロイしてください。CodeDeployはそれらのスクリプトの完了を10〜15分まで待つようになります。 **使用すべき場面:**依存関係のインストールやデータベースマイグレーションなど、5分以上かかる処理が実際に必要な場合です。なぜスクリプトが遅いのかを確認せずにタイムアウトを延ばすのは最初の手段としては避けてください。単にハングをマスキングしているだけかもしれません。

修正方法2:スクリプトが実際に何をしているか診断するEC2インスタンスにSSHでログインし、新しいデプロイをトリガーしながらCodeDeployエージェントのログをtailします:

sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log

出力がどの行で止まるかを確認してください。それでも不明な場合は、スタックしている箇所を特定するためにスクリプトに直接タイムスタンプを追加します:

#!/bin/bash
set -e

echo "[$(date)] Starting before_install"

echo "[$(date)] Installing dependencies..."
apt-get install -y nginx

echo "[$(date)] Done"

ログで最後に表示されたタイムスタンプから、どのコマンドがハングしているかが正確にわかります。デプロイごとのスクリプトログも確認できます:

/opt/codedeploy-agent/deployment-root/{deployment-group-id}/{deployment-id}/logs/scripts.log

修正方法3:パッケージインストールを非インタラクティブにする最もよくある原因の一つです。apt-getがキーボード入力を待ったり、低速なミラーからパッケージを取得しようとしてスタックします。非インタラクティブモードを強制することで修正できます:

#!/bin/bash
set -e

export DEBIAN_FRONTEND=noninteractive

apt-get update -y
apt-get install -y --no-install-recommends nginx

Amazon LinuxやRHELベースのインスタンスでは、yumはより簡単です。-yフラグで対応できます:

yum install -y nginx

CodeDeployスクリプト内ではapt-get installに必ず-yを付けてください。付けないとパッケージマネージャーが永遠に確認待ちでブロックされます。

修正方法4:ネットワーク呼び出しにタイムアウトを追加する設定ファイルの取得、内部APIの呼び出し、S3からのダウンロードを行うスクリプトは、VPCルートが欠落していたりセキュリティグループが誤設定されていると無期限にハングすることがあります。常に明示的なタイムアウトを設定してください:

# 危険 — タイムアウトなし、不正なルートで永遠にハング
curl https://internal-config.example.com/config.json -o /etc/app/config.json

# 安全 — 30秒後に素早く失敗し、3回リトライ
curl --max-time 30 --retry 3 --retry-delay 5 \
  https://internal-config.example.com/config.json \
  -o /etc/app/config.json

wgetでも同様です:

wget --timeout=30 --tries=3 https://internal-config.example.com/config.json

1回の試行に30秒、3回のリトライで最悪のケースは90秒となり、300秒の制限内に十分収まります。

修正方法5:バックグラウンドプロセスがスクリプトを開いたままにするのを防ぐこれは微妙な問題です。スクリプトが実際の処理を完了し、バックグラウンドサービスを起動したにもかかわらず、シェルがそのサービスがactiveになるのを待ち続けます。実際にはすべてが正常に動作しているにもかかわらず、CodeDeployがタイムアウトします。

#!/bin/bash
set -e

# サービスがactiveになるまで時間がかかる場合、これはブロックする可能性がある
systemctl start myapp

# より良い方法 — 起動して処理を続ける
systemctl start myapp || true

# または待機するが、60秒で上限を設ける
timeout 60 bash -c 'until systemctl is-active myapp; do sleep 2; done'

バックグラウンドジョブも完全にデタッチする必要があります。アンパサンド単独では不十分です:

# まだシェルにアタッチされている
./start_worker.sh &

# 完全にデタッチ — CodeDeployはこれを待たない
nohup ./start_worker.sh > /var/log/worker.log 2>&1 &
disown

修正方法6:スクリプトを常にexit 0で終了する短い修正ですが、時に重要です。一部のシェル設定では、明示的なexitがないとプロセスが宙ぶらりんの状態になります。CodeDeployはゼロ以外の終了コードを失敗として扱います。すべてのスクリプトをきれいに終了させてください:

#!/bin/bash
set -e

# ... スクリプトのロジック ...

exit 0

修正の確認再デプロイして、同時に3か所を確認します:

# EC2インスタンス上 — リアルタイムのエージェント出力
sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log

# AWSコンソール
# CodeDeploy → デプロイメント → [対象のデプロイメント] → イベントの表示

# デプロイごとのスクリプトログ
ls /opt/codedeploy-agent/deployment-root/
# デプロイフォルダに移動 → logs/scripts.log

正常な実行では、コンソールで各ライフサイクルイベントにStatus: Succeededが表示されます。スクリプトログには末尾が切れた行なしの完全な出力が記録されます。

予防策- **まず実際のEC2インスタンスでスクリプトをテストする。**CodeDeployに組み込む前に、デプロイ対象と同じ環境のインスタンスで手動実行してください。テスト実行で10分かかるnpm installを発見する方が、本番デプロイの失敗よりはるかにコストが低いです。- **すべてのネットワーク呼び出しに明示的なタイムアウトを設定する。**内部APIやS3エンドポイントがハードリミットなしで適切な時間内に応答すると信頼しないでください。VPCの誤設定は思いのほか多く発生します。- **重い処理をライフサイクルフックから移動する。**大きなダウンロード、データベースマイグレーション、ウォームアップ処理は、デプロイフックの中ではなく、CodeBuildステージやAMIベイクに含めるべきです。- 常にset -eを使い、デバッグ中はset -xを使う。-xフラグはすべてのコマンドをログにトレースします。スクリプトがハングした場合、最後にトレースされた行から正確にどこで止まっているかがわかります。

Related Error Notes