Lỗi Gặp PhảiQuá trình triển khai CodeDeploy của bạn bị dừng giữa chừng với thông báo kiểu như:
Script at specified location: scripts/before_install.sh failed to complete in 300 seconds
LifecycleEvent - BeforeInstall
Status - Failed
Deployment failed
Deployment bị đánh dấu thất bại trong console CodeDeploy, và EC2 instance của bạn rơi vào trạng thái triển khai dở dang. Điều này có thể xảy ra ở bất kỳ lifecycle hook nào — BeforeInstall, AfterInstall, ApplicationStart, ValidateService, đều có thể gặp.
Nguyên NhânCodeDeploy áp dụng giới hạn cứng 300 giây (5 phút) cho mỗi lifecycle hook script. Script không kịp thoát trong thời gian đó? CodeDeploy sẽ buộc dừng và đánh dấu deployment thất bại.
Dưới đây là những nguyên nhân phổ biến khiến script bị treo hoặc chạy quá lâu:
- Package manager (
apt,yum) đang âm thầm chờ xác nhận yes/no hoặc bị kẹt ở một mirror chậm- Script gọi đến một URL hoặc endpoint nội bộ không thể truy cập từ EC2 instance — kết nối TCP cứ treo mãi-npm installvới hàng trăm package,pip installvới các dependency ML nặng, hoặc các cài đặt tương tự thực sự mất vài phút- Script đang chờ một systemd service đạt trạng tháiactivetrước khi tiếp tục- Thiếuexit 0ở cuối — một tiến trình nền giữ shell mở sau khi công việc thực sự đã xong- Một interactive prompt vô tình được kích hoạt bên trong script (thường gặp vớigpg,debconf, hoặc một số trình cài đặt)## Cách Sửa 1: Tăng Timeout trong appspec.ymlCách khắc phục nhanh nhất khi script của bạn thực sự cần thêm thời gian. Mỗi hook trongappspec.ymlchấp nhận một khóatimeouttính bằng giây, tối đa 3600 (một giờ):
hooks:
BeforeInstall:
- location: scripts/before_install.sh
timeout: 600
runas: root
ApplicationStart:
- location: scripts/start_server.sh
timeout: 900
runas: ec2-user
Triển khai lại sau khi lưu. CodeDeploy bây giờ sẽ chờ tới 10 hoặc 15 phút để các script đó hoàn thành. Khi nào nên dùng: Cài đặt dependency hoặc database migration thực sự cần hơn 5 phút. Đừng tăng timeout ngay mà không kiểm tra tại sao script chậm — bạn có thể chỉ đang che giấu một sự cố treo.
Cách Sửa 2: Chẩn Đoán Script Đang Thực Sự Làm GìSSH vào EC2 instance và theo dõi log của CodeDeploy agent trong khi kích hoạt một deployment mới:
sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
Quan sát xem output dừng ở dòng nào. Vẫn chưa rõ? Thêm timestamp trực tiếp vào script để xác định chính xác điểm bị treo:
#!/bin/bash
set -e
echo "[$(date)] Starting before_install"
echo "[$(date)] Installing dependencies..."
apt-get install -y nginx
echo "[$(date)] Done"
Timestamp cuối cùng bạn thấy trong log sẽ cho biết chính xác lệnh nào bị treo. Bạn cũng có thể kiểm tra log script theo từng deployment:
/opt/codedeploy-agent/deployment-root/{deployment-group-id}/{deployment-id}/logs/scripts.log
Cách Sửa 3: Cài Đặt Package Ở Chế Độ Non-InteractiveMột trong những thủ phạm phổ biến nhất: apt-get âm thầm chờ nhập liệu từ bàn phím, hoặc tải package từ một mirror bị giới hạn tốc độ. Khắc phục bằng cách bắt buộc chế độ non-interactive:
#!/bin/bash
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y --no-install-recommends nginx
Trên Amazon Linux hoặc các instance dùng RHEL, yum đơn giản hơn — cờ -y là đủ:
yum install -y nginx
Không bao giờ chạy apt-get install mà thiếu -y bên trong script CodeDeploy. Package manager sẽ chặn mãi mãi chờ xác nhận mà không bao giờ đến.
Cách Sửa 4: Thêm Timeout Cho Các Lệnh Gọi MạngCác script tải file cấu hình, gọi API nội bộ, hoặc lấy dữ liệu từ S3 có thể bị treo vô thời hạn nếu thiếu route VPC hoặc security group bị cấu hình sai. Luôn đặt timeout tường minh:
# Nguy hiểm — không có timeout, treo mãi nếu route có vấn đề
curl https://internal-config.example.com/config.json -o /etc/app/config.json
# An toàn — thất bại nhanh sau 30 giây, thử lại 3 lần
curl --max-time 30 --retry 3 --retry-delay 5 \
https://internal-config.example.com/config.json \
-o /etc/app/config.json
Tương tự với wget:
wget --timeout=30 --tries=3 https://internal-config.example.com/config.json
30 giây mỗi lần thử với 3 lần thử lại nghĩa là trường hợp xấu nhất là 90 giây — hoàn toàn nằm trong giới hạn 300 giây.
Cách Sửa 5: Ngăn Tiến Trình Nền Giữ Script MởĐây là một trường hợp tinh tế. Script của bạn hoàn thành công việc thực sự, khởi động một dịch vụ nền, nhưng shell vẫn mở chờ dịch vụ đó báo cáo trạng thái active. CodeDeploy timeout dù mọi thứ thực ra đã hoạt động.
#!/bin/bash
set -e
# Có thể bị chặn nếu service mất nhiều thời gian để active
systemctl start myapp
# Tốt hơn — khởi động và tiếp tục luôn
systemctl start myapp || true
# Hoặc chờ, nhưng giới hạn 60 giây
timeout 60 bash -c 'until systemctl is-active myapp; do sleep 2; done'
Các tiến trình nền cũng cần được tách hoàn toàn — chỉ dùng dấu ampersand là chưa đủ:
# Vẫn còn gắn với shell
./start_worker.sh &
# Tách hoàn toàn — CodeDeploy sẽ không chờ cái này
nohup ./start_worker.sh > /var/log/worker.log 2>&1 &
disown
Cách Sửa 6: Luôn Kết Thúc Script Bằng exit 0Sửa nhanh, nhưng đôi khi rất quan trọng. Trên một số cấu hình shell, thiếu lệnh exit tường minh khiến tiến trình rơi vào trạng thái lơ lửng. CodeDeploy cũng xử lý bất kỳ mã thoát khác 0 nào là thất bại. Hãy kết thúc mọi script một cách gọn gàng:
#!/bin/bash
set -e
# ... logic script của bạn ...
exit 0
Kiểm Tra Sau Khi SửaTriển khai lại và theo dõi ba nơi cùng lúc:
# Trên EC2 instance — output agent theo thời gian thực
sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
# Trên AWS Console
# CodeDeploy → Deployments → [deployment của bạn] → View events
# Log script theo từng deployment
ls /opt/codedeploy-agent/deployment-root/
# Vào thư mục deployment → logs/scripts.log
Một lần chạy thành công sẽ hiển thị từng lifecycle event với Status: Succeeded trên console. Log script sẽ có đầy đủ output mà không bị cắt đứt ở cuối.

