This project is a Django-based web application configured to run using Docker. The application has been migrated from SQLite to PostgreSQL. This README outlines the steps required for local development, CI/CD testing, and production deployment—including the configuration for Docker Compose and Nginx.
- Prerequisites
- Environment Variables
- Local Development
- CI/CD Environment
- Switching Between SQLite and PostgreSQL
- Troubleshooting
- Additional Notes
- Docker & Docker Compose:
Ensure you have Docker and Docker Compose installed. - Python 3.12+:
(For local development outside Docker, if needed.) - Git:
To clone the repository.
The project uses environment variables to configure database settings, secret keys, and other configurations. Below is an example .env
file:
# .env file for local development and CI/CD
DEBUG=True
DJANGO_ENV=development
SECRET_KEY=development-secret-key
# PostgreSQL settings
POSTGRES_DB=vocationalnyc_db
POSTGRES_USER=db_admin
POSTGRES_PASSWORD=secret-db-password
POSTGRES_HOST=db
POSTGRES_PORT=5432
# Optionally, you can set DATABASE_URL like:
# DATABASE_URL=postgres://db_admin:secret-db-password@db:5432/vocationalnyc_db
For production, configure environment variables via the deployment platform (e.g., AWS Elastic Beanstalk) rather than using a .env
file.
The docker-compose.yml
file defines the multi-container environment. An example configuration:
# This file is used to override the docker-compose.yml file for local development and testing purposes.
services:
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
container_name: nginx
ports:
- "80:80"
redis:
image: redis:latest
container_name: redis
ports:
- "6379:6379"
app:
build:
context: .
dockerfile: Dockerfile
env_file: .env
environment:
# - DJANGO_ENV=development_w/channel # Uncomment this line to test the websocket
- DJANGO_ENV=development
container_name: app
depends_on:
- redis
- nginx
volumes:
- .:/vocationalnyc
ports:
- "5000:5000"
Note:
In order to test websocket functionalities you must set DJANGO_ENV
to development_w/websocket
.
Commands to Build and Run Locally:
-
Build the images:
docker-compose build
-
Start the containers:
docker-compose up --build
-
Run Migrations (if needed):
docker-compose exec app python manage.py migrate
-
Creating a Superuser (Optional):
docker-compose exec app python manage.py createsuperuser
The Nginx configuration (located in the nginx
directory) forwards requests to the Django app using Docker’s internal DNS.
Example nginx.conf
:
server {
listen 80;
server_name vocationalnyc-env.eba-uurzafst.us-east-1.elasticbeanstalk.com; # Replace with the domain for production or use localhost for testing
client_max_body_size 200M;
# Use Docker's internal DNS resolver (127.0.0.11 is fixed for Docker)
resolver 127.0.0.11 valid=30s;
# Standard HTTP requests
location / {
set $app "app:5000";
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://$app;
}
# WebSocket requests (e.g., those under /ws/)
location /ws/ {
set $app "app:5000";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass http://$app;
}
}
Note:
Current configuration uses the fixed IP address of Docker's internal DNS resolver.
For the CI/CD pipeline (e.g., Travis CI):
-
Environment Variables:
Configure CI/CD secrets forSECRET_KEY
,POSTGRES_DB
,POSTGRES_USER
,POSTGRES_PASSWORD
. -
Build & Test Process:
The CI pipeline can use Docker Compose to spin up the app and database. For example:docker-compose up --build -d docker-compose exec -T app python manage.py migrate docker-compose exec -T app python manage.py test
-
Important:
Ensure you do not includedocker-compose.override.yml
or any development-only configurations in the CI/CD pipeline.
The Dockerfile
is optimized for production and uses Daphne for ASGI to serve the application on port 5000
.
Do not include the .env
file in production deployments. Instead, configure environment variables via the Elastic Beanstalk console or the CI/CD pipeline.
Modify settings.py
to use SQLite if DJANGO_ENV
is set as any value other than production
.
When DJANGO_ENV
is set as production
, use PostgreSQL. For example, in settings.py
:
import environ
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
env = environ.Env(DEBUG=(bool, False))
env_file = BASE_DIR / ".env"
if env_file.exists():
environ.Env.read_env(env_file)
# Database Configuration
if DJANGO_ENV == "travis":
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "travis_ci_test",
"USER": "postgres",
"PASSWORD": "postgres",
"HOST": "db",
"PORT": 5432,
}
}
elif DJANGO_ENV == "production":
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": env("POSTGRES_DB", default="db"),
"USER": env("POSTGRES_USER", default="postgres"),
"PASSWORD": env("POSTGRES_PASSWORD", default="postgres"),
"HOST": env("POSTGRES_HOST", default="localhost"),
"PORT": env.int("POSTGRES_PORT", default=5432),
}
}
else:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
PostgreSQL data is persisted via the named volume (e.g., postgres_data
). On Linux, this is typically stored at /var/lib/docker/volumes/postgres_data/_data
.
-
Stop All Running Containers:
docker-compose down
-
Remove All Volumes:
docker-compose down -v
-
Remove All Containers and Images (Optional Cleanup):
docker system prune -a
-
Delete Migration Files:
(Ensure you keep
__init__.py
in each migrations folder.)rm path/to/VocationalNYC/users/migrations/0*.py rm path/to/VocationalNYC/courses/migrations/0*.py rm path/to/VocationalNYC/review/migrations/0*.py rm path/to/VocationalNYC/bookmarks/migrations/0*.py
-
Rebuild and Start Containers:
docker-compose build --no-cache docker-compose up -d docker-compose exec app python manage.py makemigrations docker-compose exec app python manage.py migrate
-
Nginx and Docker DNS:
The Nginx configuration usesresolver 127.0.0.11;
to access Docker's built-in DNS for resolving container names dynamically. -
Exposed Ports:
app:5000
&nginx:80
.