Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add traefik #41

Merged
merged 1 commit into from
Dec 27, 2024
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
5 changes: 4 additions & 1 deletion backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from typing import Annotated, Any, Final, Literal, Self

from dotenv import find_dotenv, load_dotenv
from pydantic import (
AnyUrl,
BeforeValidator,
Expand All @@ -13,6 +14,8 @@
)
from pydantic_settings import BaseSettings, SettingsConfigDict

load_dotenv(find_dotenv(".env"))


def _parse_cors(v: Any) -> list[str] | str:
if isinstance(v, str) and not v.startswith("["):
Expand All @@ -23,7 +26,7 @@ def _parse_cors(v: Any) -> list[str] | str:


class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
model_config = SettingsConfigDict(env_file_encoding="utf-8", extra="ignore")

API_V1_PREFIX: str = "/api/v1"
TITLE: Final = "SCAN"
Expand Down
86 changes: 86 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
services:
proxy:
image: traefik:3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "80:80"
- "8090:8080"
# Duplicate the command from docker-compose.yml to add --api.insecure=true
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Add a constraint to only use services with the label for this stack
- --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable debug logging for local development
- --log.level=DEBUG
# Enable the Dashboard and API
- --api
# Enable the Dashboard and API in insecure mode for local development
- --api.insecure=true
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
- traefik.constraint-label=traefik-public
networks:
- traefik-public
- default

backend:
image: backend:dev
restart: no
ports:
- "8000:8000"
networks:
- traefik-public
- default
build:
context: ./backend
container_name: backend
depends_on:
- db
- valkey
env_file:
- .env
environment:
- POSTGRES_HOST=db

labels:
- traefik.enable=true
- traefik.docker.network=traefik-public

# HTTP entry point and rule
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http

# Remove reference to HTTPS and its middlewares
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=

# Clear HTTPS-specific labels
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.middlewares=

db:
restart: "no"
ports:
- "5432:5432"

valkey:
restart: "no"
ports:
- 6379:6379

networks:
traefik-public:
# For local dev, don't expect an external Traefik network
external: false
77 changes: 77 additions & 0 deletions docker-compose.traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
services:
traefik:
image: traefik:3
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 80:80
# Listen on port 443, default for HTTPS
- 443:443
restart: always
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
# Define the port inside of the Docker service to use
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080
# Make Traefik use this domain (from an environment variable) in HTTP
- traefik.http.routers.traefik-dashboard-http.entrypoints=http
- traefik.http.routers.traefik-dashboard-http.rule=Host(`traefik.${DOMAIN?Variable not set}`)
# traefik-https the actual router using HTTPS
- traefik.http.routers.traefik-dashboard-https.entrypoints=https
- traefik.http.routers.traefik-dashboard-https.rule=Host(`traefik.${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-dashboard-https.tls=true
# Use the "le" (Let's Encrypt) resolver created below
- traefik.http.routers.traefik-dashboard-https.tls.certresolver=le
# Use the special Traefik service api@internal with the web UI/Dashboard
- traefik.http.routers.traefik-dashboard-https.service=api@internal
# https-redirect middleware to redirect HTTP to HTTPS
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# traefik-http set up only to use the middleware to redirect to https
- traefik.http.routers.traefik-dashboard-http.middlewares=https-redirect
# admin-auth middleware with HTTP Basic auth
# Using the environment variables USERNAME and HASHED_PASSWORD
- traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable not set}
# Enable HTTP Basic auth, using the middleware created above
- traefik.http.routers.traefik-dashboard-https.middlewares=admin-auth
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the volume to store the certificates
- traefik-public-certificates:/certificates
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Create an entrypoint "https" listening on port 443
- --entrypoints.https.address=:443
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL
- --certificatesresolvers.le.acme.email=${EMAIL?Variable not set}
# Store the Let's Encrypt certificates in the mounted volume
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
# Use the TLS Challenge for Let's Encrypt
- --certificatesresolvers.le.acme.tlschallenge=true
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable the Dashboard and API
- --api
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public

volumes:
# Create a volume to store the certificates, even if the container is recreated
traefik-public-certificates:

networks:
# Use the previously created public network "traefik-public", shared with other
# services that need to be publicly available via this Traefik
traefik-public:
external: true
46 changes: 39 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,62 @@
services:
backend:
image: backend:dev
restart: always
networks:
- traefik-public
- default
build:
context: ./backend
container_name: backend
depends_on:
- db
- valkey
ports:
- "8000:8000"
env_file:
- backend/.env
- .env
environment:
- POSTGRES_HOST=db
- VALKEY_HOST=valkey
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public

- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=8000

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=Host(`api.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=le

# Enable redirection for HTTP and HTTPS
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=https-redirect

db:
image: postgres:17-alpine
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
expose:
- 5432
ports:
- 5432:5432
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "test_password"
POSTGRES_DB: "scan"
POSTGRES_USER: postgres
POSTGRES_PASSWORD: test_password
POSTGRES_DB: scan
volumes:
- db-data:/var/lib/postgresql/data

valkey:
image: valkey/valkey:8-alpine
restart: always
expose:
- 6379
ports:
Expand All @@ -38,4 +67,7 @@ volumes:
db-data:

networks:
scan-network:
traefik-public:
name: traefik-public
# Allow setting it to false for testing
external: true
1 change: 1 addition & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
uv sync --frozen --all-extras

@backend-server:
docker compose down backend && \
cd backend && \
uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Expand Down
Loading