Dockerize Django app with dev/beta/prod env config and uv.
Replace hardcoded settings with environment-driven config, add Docker compose for local and production deploys, migrate from pip to uv, and split Gitea workflows so PRs run tests only while master pushes deploy.
This commit is contained in:
+54
-12
@@ -2,10 +2,9 @@
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="/home/westfarn/Documents/django_live_sites/Company_Site"
|
||||
APP_DIR="$REPO_ROOT/company_site"
|
||||
VENV="$REPO_ROOT/venv"
|
||||
SETTINGS="$APP_DIR/company_site/settings.py"
|
||||
LOCAL_SETTINGS="$APP_DIR/company_site/local_settings.py"
|
||||
ENV_FILE="$REPO_ROOT/.env"
|
||||
COMPOSE_FILE="$REPO_ROOT/docker-compose.prod.yml"
|
||||
VALIDATE_SCRIPT="$REPO_ROOT/scripts/validate-env.sh"
|
||||
|
||||
if [[ $# -lt 1 || -z "${1:-}" ]]; then
|
||||
echo "Usage: $0 <checkout-directory>" >&2
|
||||
@@ -13,24 +12,67 @@ if [[ $# -lt 1 || -z "${1:-}" ]]; then
|
||||
fi
|
||||
|
||||
CHECKOUT="$1"
|
||||
DEPLOY_MODE="${DEPLOY_MODE:-docker}"
|
||||
|
||||
cp "$SETTINGS" /tmp/company_site_settings.py.bak
|
||||
if [[ "$DEPLOY_MODE" == "docker" ]]; then
|
||||
echo "Syncing application files to $REPO_ROOT (preserving server .env)..."
|
||||
rsync -a --delete \
|
||||
--exclude .git/ \
|
||||
--exclude .venv/ \
|
||||
--exclude .env \
|
||||
--exclude db.sqlite3 \
|
||||
--exclude staticfiles/ \
|
||||
"$CHECKOUT/" "$REPO_ROOT/"
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Missing $ENV_FILE on the server." >&2
|
||||
echo "Create it from .env.prod.example and configure production values." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bash "$VALIDATE_SCRIPT" "$ENV_FILE"
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
echo "Building Docker images..."
|
||||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" build
|
||||
|
||||
echo "Starting containers..."
|
||||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --remove-orphans
|
||||
|
||||
echo "Running database migrations..."
|
||||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec -T web \
|
||||
uv run python manage.py migrate --noinput
|
||||
|
||||
echo "Deploy complete."
|
||||
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Legacy venv/systemd deploy (DEPLOY_MODE=legacy)
|
||||
APP_DIR="$REPO_ROOT/company_site"
|
||||
VENV="$REPO_ROOT/.venv"
|
||||
SETTINGS_DIR="$APP_DIR/company_site/settings"
|
||||
LOCAL_SETTINGS="$APP_DIR/company_site/local_settings.py"
|
||||
|
||||
cp -r "$SETTINGS_DIR" /tmp/company_site_settings.bak
|
||||
cp "$LOCAL_SETTINGS" /tmp/company_site_local_settings.py.bak 2>/dev/null || true
|
||||
|
||||
rsync -a --delete \
|
||||
--exclude venv/ \
|
||||
--exclude .venv/ \
|
||||
--exclude .git/ \
|
||||
--exclude 'company_site/company_site/settings.py' \
|
||||
--exclude .env \
|
||||
--exclude 'company_site/company_site/settings/' \
|
||||
--exclude 'company_site/company_site/local_settings.py' \
|
||||
"$CHECKOUT/" "$REPO_ROOT/"
|
||||
|
||||
cp /tmp/company_site_settings.py.bak "$SETTINGS"
|
||||
rm -rf "$SETTINGS_DIR"
|
||||
cp -r /tmp/company_site_settings.bak "$SETTINGS_DIR"
|
||||
cp /tmp/company_site_local_settings.py.bak "$LOCAL_SETTINGS" 2>/dev/null || true
|
||||
|
||||
source "$VENV/bin/activate"
|
||||
pip install -r "$REPO_ROOT/requirements.txt"
|
||||
uv sync --frozen --directory "$REPO_ROOT"
|
||||
cd "$APP_DIR"
|
||||
python manage.py migrate --noinput
|
||||
python manage.py collectstatic --noinput
|
||||
uv run python manage.py migrate --noinput
|
||||
uv run python manage.py collectstatic --noinput
|
||||
|
||||
sudo systemctl restart company
|
||||
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd /app/company_site
|
||||
|
||||
wait_for_database() {
|
||||
if [[ -z "${DATABASE_URL:-}" && -z "${DB_HOST:-}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Waiting for database..."
|
||||
for _ in $(seq 1 30); do
|
||||
if uv run python - <<'PY'
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "company_site.settings")
|
||||
|
||||
import django
|
||||
from django.db import connections
|
||||
from django.db.utils import OperationalError
|
||||
|
||||
django.setup()
|
||||
|
||||
try:
|
||||
connections["default"].ensure_connection()
|
||||
except OperationalError:
|
||||
sys.exit(1)
|
||||
PY
|
||||
then
|
||||
echo "Database is ready."
|
||||
return 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "Database did not become ready in time." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for_database
|
||||
|
||||
uv run python manage.py migrate --noinput
|
||||
uv run python manage.py collectstatic --noinput
|
||||
|
||||
exec uv run gunicorn company_site.wsgi:application \
|
||||
--bind "${GUNICORN_BIND:-0.0.0.0:8000}" \
|
||||
--workers "${GUNICORN_WORKERS:-2}"
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ENV_FILE="${1:?Usage: $0 <env-file>}"
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Environment file not found: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
DJANGO_ENV="${DJANGO_ENV:-prod}"
|
||||
|
||||
required_vars=(
|
||||
DJANGO_SECRET_KEY
|
||||
DJANGO_ALLOWED_HOSTS
|
||||
DB_PASSWORD
|
||||
DB_NAME
|
||||
DB_USER
|
||||
DATABASE_URL
|
||||
)
|
||||
|
||||
if [[ "$DJANGO_ENV" == "prod" || "$DJANGO_ENV" == "beta" ]]; then
|
||||
required_vars+=(
|
||||
RECAPTCHA_PUBLIC_KEY
|
||||
RECAPTCHA_PRIVATE_KEY
|
||||
EMAIL_HOST_USER
|
||||
EMAIL_HOST_PASSWORD
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ "$DJANGO_ENV" == "prod" ]]; then
|
||||
required_vars+=(TIANJI_WEBSITE_ID)
|
||||
fi
|
||||
|
||||
missing=()
|
||||
for var in "${required_vars[@]}"; do
|
||||
if [[ -z "${!var:-}" ]]; then
|
||||
missing+=("$var")
|
||||
fi
|
||||
done
|
||||
|
||||
if ((${#missing[@]} > 0)); then
|
||||
echo "Missing required environment variables in $ENV_FILE:" >&2
|
||||
printf ' - %s\n' "${missing[@]}" >&2
|
||||
echo "Copy .env.prod.example to .env on the server and set production values." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$DJANGO_ENV" == "prod" && "$DJANGO_SECRET_KEY" == change-me* ]]; then
|
||||
echo "DJANGO_SECRET_KEY must be changed from the example value for production." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Environment validation passed (DJANGO_ENV=$DJANGO_ENV)."
|
||||
Reference in New Issue
Block a user