Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,27 @@ COUCHDB_USER=
COUCHDB_PASSWORD=
COUCHDB_PORT=

# Bind-mount volume paths on the host — use the db/ directory in the repo root
# Windows: H:/Dev_Mentoring/Animals Healthcare Application/db/postgres
DB_VOLUMEN_POSTGRES=
DB_VOLUMEN_COUCH=

# CouchDB for settings.py - dev
COUCH_CONNECTOR=Server("")
COUCH_CONNECTOR=

# Celery for settings.py - dev
CELERY_BROKER_URL=
CELERY_BACKEND=

# SMTP for settings.py - dev
EMAIL_BACKEND = ""
EMAIL_HOST = ""
EMAIL_PORT = ""
EMAIL_USE_TLS =
EMAIL_HOST_USER = ""
EMAIL_HOST_PASSWORD = ""

# Discord bot token
DISCORD_TOKEN = ""
EMAIL_BACKEND=""
EMAIL_HOST=""
EMAIL_PORT=""
EMAIL_USE_TLS=
EMAIL_HOST_USER=""
EMAIL_HOST_PASSWORD=""

# Discord bot token for settings.py
DISCORD_TOKEN=""

# DB volume paths for docker-compose.yml - dev
DB_VOLUMEN_COUCH=
DB_VOLUMEN_POSTGRES=

# Traefik - production deploy
AHC_DOMAIN=ahc.home
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.PHONY: up down restart logs logs-flower build deploy shell

COMPOSE = docker compose --env-file .env -f docker/docker-compose-traefik.yml

up:
$(COMPOSE) up -d --build

down:
$(COMPOSE) down

restart: down up

logs:
docker logs -f ahc-web

logs-flower:
docker logs -f ahc-flower

build:
$(COMPOSE) build

deploy:
git pull
$(MAKE) up

shell:
docker exec -it ahc-web python manage.py shell
1 change: 1 addition & 0 deletions docker/Dockerfile-app.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ htmlcov/
.ty_cache/
.ruff_cache/

db/
db.sqlite3
db.sqlite3-journal
local_settings.py
Expand Down
177 changes: 177 additions & 0 deletions docker/docker-compose-traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
name: ahc

services:
web:
build:
context: ..
dockerfile: docker/Dockerfile-app
image: ahc-app:latest
container_name: ahc-web
env_file:
- ../.env
environment:
- PYTHONUNBUFFERED=1
- DB_HOST=postgres_db
- DB_PORT=5432
depends_on:
postgres_db:
condition: service_healthy
queue:
condition: service_started
couch_db:
condition: service_healthy
entrypoint: ["/bin/bash", "-c"]
command:
- |
python manage.py migrate
python manage.py collectstatic --noinput
gunicorn ahc.wsgi:application --bind 0.0.0.0:8000 --workers 4
networks:
- ahc_net
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.ahc.rule=Host(`${AHC_DOMAIN}`)
- traefik.http.routers.ahc.entrypoints=web
- traefik.http.services.ahc.loadbalancer.server.port=8000
restart: unless-stopped

postgres_db:
image: postgres:18-alpine
container_name: ahc-postgres
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- animals_db:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 30s
retries: 6
networks:
- ahc_net
restart: unless-stopped

couch_db:
build:
context: ..
dockerfile: docker/Dockerfile-couchdb
args:
COUCHDB_USER: ${COUCHDB_USER}
COUCHDB_PASSWORD: ${COUCHDB_PASSWORD}
container_name: ahc-couchdb
environment:
- COUCHDB_USER=${COUCHDB_USER}
- COUCHDB_PASSWORD=${COUCHDB_PASSWORD}
- COUCHDB_PORT=${COUCHDB_PORT}
volumes:
- couchdb_data:/opt/couchdb/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5982/_up"]
interval: 5s
timeout: 30s
retries: 6
networks:
- ahc_net
restart: unless-stopped

queue:
image: ahc-app:latest
command: celery -A celery_notifications.config:celery_obj worker -l info
env_file:
- ../.env
environment:
- DJANGO_SETTINGS_MODULE=ahc.settings
- PYTHONUNBUFFERED=1
- DB_HOST=postgres_db
- DB_PORT=5432
depends_on:
redis:
condition: service_healthy
postgres_db:
condition: service_healthy
couch_db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "celery -A celery_notifications.config:celery_obj inspect ping -d celery@$$HOSTNAME --timeout 5 2>&1 | grep -q pong"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
networks:
- ahc_net
restart: unless-stopped

celery_beat:
image: ahc-app:latest
command: celery -A celery_notifications.config:celery_obj beat -l info
env_file:
- ../.env
environment:
- DJANGO_SETTINGS_MODULE=ahc.settings
- PYTHONUNBUFFERED=1
- DB_HOST=postgres_db
- DB_PORT=5432
depends_on:
redis:
condition: service_healthy
postgres_db:
condition: service_healthy
networks:
- ahc_net
restart: unless-stopped

redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 30
networks:
- ahc_net
restart: unless-stopped

celery_flower:
image: mher/flower:2.0.1
container_name: ahc-flower
environment:
- CELERY_BROKER_URL=${CELERY_BROKER_URL}
- FLOWER_PORT=${FLOWER_PORT}
- FLOWER_BASIC_AUTH=${FLOWER_BASIC_AUTH}
depends_on:
queue:
condition: service_healthy
networks:
- ahc_net
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.ahc-flower.rule=Host(`flower.${AHC_DOMAIN}`)
- traefik.http.routers.ahc-flower.entrypoints=web
- traefik.http.services.ahc-flower.loadbalancer.server.port=5555
restart: unless-stopped

networks:
ahc_net:
driver: bridge
proxy:
external: true

volumes:
animals_db:
driver: local
driver_opts:
type: none
device: ${DB_VOLUMEN_POSTGRES}
o: bind
couchdb_data:
driver: local
driver_opts:
type: none
device: ${DB_VOLUMEN_COUCH}
o: bind
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ dependencies = [
"python-dateutil",
"pyjwt",
"defusedxml",
"aiohttp>=3",
"aiohttp>=3.14.0",
"gunicorn>=26.0.0",
"whitenoise>=6.12.0",
]

[dependency-groups]
Expand Down
5 changes: 5 additions & 0 deletions src/ahc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def _skip_external_services() -> bool:

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.middleware.csp.ContentSecurityPolicyMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
Expand Down Expand Up @@ -180,6 +181,10 @@ def _skip_external_services() -> bool:

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "static_collected"
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}
STATICFILES_DIRS = [
BASE_DIR / "static",
]
Expand Down
Loading
Loading