AWS Elastic Beanstalk Container Commands Failing: Troubleshooting Django App Deployment Issues
Deploying a Django application to AWS Elastic Beanstalk (EB) streamlines scaling and management, but even seasoned developers encounter roadblocks. One common frustration is container command failures—critical scripts (like database migrations or static file collection) that run during deployment but fail to execute, breaking the app launch.
Container commands in Elastic Beanstalk are powerful: they run on EC2 instances after your code is extracted but before the application server starts. For Django apps, they’re often used for migrate, collectstatic, or custom setup scripts. When these fail, deployment halts, and debugging can feel like navigating a black box.
This blog demystifies container command failures, breaking down their root causes, troubleshooting steps, and Django-specific solutions. By the end, you’ll confidently diagnose and fix issues to ensure smooth deployments.
Table of Contents#
- Understanding AWS Elastic Beanstalk Container Commands
- Common Causes of Container Command Failures
- Step-by-Step Troubleshooting Methodology
- Django-Specific Container Command Issues
- Advanced Troubleshooting Techniques
- Conclusion
- References
1. Understanding AWS Elastic Beanstalk Container Commands#
Before diving into failures, let’s clarify what container commands are and when they run.
What Are Container Commands?#
Container commands are scripts defined in your Elastic Beanstalk configuration (via .ebextensions/*.config files) that execute on EC2 instances after your application code is extracted (to /var/app/staging/) but before the application server (e.g., Gunicorn, uWSGI) starts. They’re ideal for pre-deployment setup tasks like:
- Running Django migrations (
python manage.py migrate). - Collecting static files (
python manage.py collectstatic). - Setting file permissions or environment variables.
Key Characteristics#
- Execution Context: Run as the
ec2-userby default (notroot—usesudofor elevated privileges). - Working Directory: Defaults to
/var/app/staging/(your app’s codebase). - Order of Execution:
- Files in
.ebextensions/are processed alphabetically (e.g.,01_django.configruns before02_db.config). - Within a file, commands run in the order they’re listed.
- Files in
- Leader-Only Execution: Use
leader_only: trueto run a command on only one instance (critical for migrations to avoid race conditions).
Example Configuration#
A typical .ebextensions/django.config file for a Django app might look like this:
container_commands:
01_migrate:
command: "python manage.py migrate"
leader_only: true # Run migrations on only one instance
02_collectstatic:
command: "python manage.py collectstatic --noinput"
leader_only: false # Run on all instances to collect static files2. Common Causes of Container Command Failures#
Container commands fail for predictable reasons. Let’s break down the most frequent culprits.
2.1 YAML Syntax Errors#
Elastic Beanstalk uses YAML for .ebextensions configs, and YAML is unforgiving of syntax mistakes. Common issues:
- Missing Indentation: YAML relies on consistent spaces (not tabs). For example:
# BROKEN: Missing indent for "command" container_commands: 01_migrate: command: "python manage.py migrate" # ❌ Indentation error - Incorrect Key Names: Typos like
container_command(singular) instead ofcontainer_commands(plural). - Unquoted Special Characters: Commands with spaces or special characters (e.g.,
--noinput) must be quoted.
2.2 Incorrect Working Directory or Paths#
Container commands run in /var/app/staging/, but if your Django project uses a subdirectory (e.g., myproject/manage.py instead of manage.py), relative paths will fail:
# BROKEN: Assumes manage.py is in /var/app/staging/, but it’s in /var/app/staging/myproject/
container_commands:
01_migrate:
command: "python manage.py migrate" # ❌ File not found2.3 Permission Issues#
By default, commands run as ec2-user, which lacks root privileges. Tasks like writing to system directories (e.g., /var/www/static/) or installing system packages will fail without sudo:
# BROKEN: collectstatic tries to write to /var/www/static/ (owned by root)
container_commands:
02_collectstatic:
command: "python manage.py collectstatic --noinput" # ❌ Permission denied2.4 Timing/Dependency Issues#
Commands often depend on external services (e.g., RDS databases) that aren’t ready when the command runs. For example:
- Running
migratebefore the RDS instance initializes results inOperationalError: could not connect to server.
2.5 Missing Environment Variables#
Django commands like migrate or collectstatic rely on environment variables (e.g., DATABASE_URL, SECRET_KEY). If these aren’t set in Elastic Beanstalk (via Configuration > Software > Environment properties), commands fail:
# Error in logs: django.core.exceptions.ImproperlyConfigured: SECRET_KEY not set
2.6 Resource Limitations#
Commands like collectstatic or heavy migrations may exhaust memory or CPU on t2.micro instances, causing the OS to kill the process (look for Killed in logs).
3. Step-by-Step Troubleshooting Methodology#
When a container command fails, follow this workflow to diagnose the issue.
Step 1: Check Elastic Beanstalk Deployment Logs#
The first stop is Elastic Beanstalk’s eb-activity.log, which captures deployment steps, including container command output.
How to Access Logs:
- Via EB CLI: Run
eb logs --allto download logs to your local machine. - Via AWS Console: Go to your EB environment > Logs > Request Logs > Last 100 Lines (or Full Logs for more detail).
Key Log File: /var/log/eb-activity.log contains container command execution details. Look for lines like:
2024-03-01 12:34:56,789 [INFO] Running container command: 01_migrate
2024-03-01 12:34:57,123 [ERROR] Command failed: python manage.py migrate
Step 2: Validate Container Command Configuration#
Ensure your .ebextensions/*.config files are valid YAML and correctly structured.
Checklist:
- Use a YAML linter to catch syntax errors.
- Verify
container_commands(plural) is used, notcontainer_command. - Confirm command paths: If
manage.pyis in a subdirectory (e.g.,myapp/manage.py), update the command:# FIXED: Specify subdirectory path container_commands: 01_migrate: command: "python myapp/manage.py migrate"
Step 3: Test Commands Locally#
Replicate the Elastic Beanstalk environment locally to isolate issues:
- Use the EB Local Run tool to simulate deployment:
eb local run - Manually run the failing command in the local container to see errors in real time:
docker exec -it <container_id> bash # Enter the local EB container cd /var/app/staging/ python manage.py migrate # Replicate the command
Step 4: Inspect the EC2 Instance via SSH#
If local testing doesn’t reveal the issue, SSH into the EB instance to debug live:
- Enable SSH access via the EB CLI:
eb ssh - Navigate to the staging directory:
cd /var/app/staging/ - Check file permissions, environment variables, and run commands manually:
# Check environment variables (Elastic Beanstalk sets these) echo $DATABASE_URL # Test the failing command with verbose output python manage.py migrate --traceback # Show full error stack
Step 5: Check for Resource Limits#
Use top or htop on the EC2 instance to monitor CPU/memory usage during deployment. If commands are killed, upgrade to a larger instance type (e.g., t2.small) or optimize the command (e.g., split large migrations).
4. Django-Specific Container Command Issues#
Django apps have unique dependencies that often cause container command failures. Let’s address the most common.
4.1 Django Migrations Failing#
python manage.py migrate is the most critical (and error-prone) container command.
Common Causes & Fixes#
-
Missing Environment Variables: Migrations require database credentials (e.g.,
DATABASE_URL). Ensure these are set in EB’s Environment Properties.# In EB Configuration > Software > Environment properties: DATABASE_URL: postgres://user:[email protected]:5432/mydb -
Database Not Ready: RDS or Aurora instances may take 1–2 minutes to initialize. Add a retry loop to wait for the database:
container_commands: 01_migrate: command: | until python manage.py migrate; do echo "Migration failed. Retrying in 5 seconds..." sleep 5 done leader_only: true -
Corrupted Migration Files: If a migration file is missing or invalid,
migratewill fail. Runpython manage.py showmigrationsvia SSH to check for gaps.
4.2 Static File Collection (collectstatic) Failing#
Django’s collectstatic gathers static assets (CSS, JS) into a single directory, but it’s prone to permission and configuration issues.
Common Causes & Fixes#
-
Missing
STATIC_ROOT: Django requiresSTATIC_ROOTinsettings.pyto know where to collect files:# settings.py (add this) STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # Or '/var/www/static/' -
Permission Denied: If
STATIC_ROOTis a system directory (e.g.,/var/www/static/), usesudoand set permissions:container_commands: 01_create_static_dir: command: "sudo mkdir -p /var/www/static && sudo chown ec2-user:ec2-user /var/www/static" 02_collectstatic: command: "python manage.py collectstatic --noinput" -
Missing
STATIC_URL: While not required forcollectstatic,STATIC_URLmisconfiguration can break static file serving post-deployment.
4.3 Django Settings Not Loading#
Commands may fail if Django can’t load settings due to missing environment variables or incorrect DJANGO_SETTINGS_MODULE.
Fix#
Ensure DJANGO_SETTINGS_MODULE is set (default: myproject.settings), and all required variables are in EB’s environment properties:
# In EB Environment Properties:
DJANGO_SETTINGS_MODULE: myproject.settings.production
SECRET_KEY: your_secure_key
DEBUG: false5. Advanced Troubleshooting Techniques#
For stubborn issues, use these pro tips.
5.1 Enable Verbose Logging#
Modify container commands to output more details. For Django commands, use --traceback or redirect output to a log file:
container_commands:
01_migrate:
command: "python manage.py migrate --traceback > /var/log/migrate.log 2>&1"
leader_only: trueThen SSH into the instance and check /var/log/migrate.log.
5.2 Use leader_only for Single-Instance Commands#
Migrations, database seeding, or cache clearing should run on only one instance to avoid race conditions. Always add leader_only: true to these commands:
container_commands:
01_migrate:
command: "python manage.py migrate"
leader_only: true # Critical for multi-instance environments5.3 Override the Working Directory#
If your Django project isn’t in the root of /var/app/staging/, explicitly set the working directory for commands:
container_commands:
01_migrate:
command: "python manage.py migrate"
cwd: "/var/app/staging/myproject/" # Set custom working directory5.4 Retry Flaky Commands#
For commands that fail intermittently (e.g., due to network/database latency), use a retry loop with a timeout:
container_commands:
01_migrate:
command: |
MAX_RETRIES=5
RETRY_DELAY=10
for ((i=1; i<=$MAX_RETRIES; i++)); do
if python manage.py migrate; then
echo "Migration succeeded on attempt $i"
exit 0
fi
echo "Migration failed. Retrying in $RETRY_DELAY seconds (attempt $i/$MAX_RETRIES)..."
sleep $RETRY_DELAY
done
echo "Migration failed after $MAX_RETRIES attempts"
exit 1
leader_only: true6. Conclusion#
Container command failures in Elastic Beanstalk are rarely mysterious—they boil down to syntax errors, permission issues, missing dependencies, or environment misconfigurations. By methodically checking logs, testing locally, and debugging on EC2 instances, you can resolve most issues quickly.
For Django apps, focus on migration/database readiness, static file permissions, and environment variables. Use leader_only for single-instance commands and retry loops for flaky dependencies like RDS. With these tools, you’ll turn deployment headaches into smooth sailing.