Skip to content

Commit 86698d9

Browse files
committed
feat: подготовить docker-инфраструктуру для локального запуска
Что сделано: - добавлен многостадийный Dockerfile с uv и non-root runtime - добавлен entrypoint с автоматическим alembic upgrade перед стартом API - добавлен docker-compose стек: api, postgres, redis, prometheus, grafana - добавлены конфиги Prometheus и provisioning datasource для Grafana
1 parent c28d8cc commit 86698d9

5 files changed

Lines changed: 177 additions & 0 deletions

File tree

Dockerfile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
ARG UV_VERSION=0.10.4
2+
3+
FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uvbin
4+
5+
FROM python:3.12-slim AS builder
6+
7+
ENV PYTHONDONTWRITEBYTECODE=1 \
8+
PYTHONUNBUFFERED=1 \
9+
UV_NO_PROGRESS=1 \
10+
UV_PROJECT_ENVIRONMENT=/opt/venv
11+
12+
WORKDIR /app
13+
14+
COPY --from=uvbin /uv /usr/local/bin/uv
15+
16+
# Dependency layer: changes only when lockfile/project metadata changes.
17+
COPY pyproject.toml uv.lock ./
18+
RUN uv sync --frozen --no-dev --no-install-project
19+
20+
21+
FROM python:3.12-slim AS runtime
22+
23+
ENV PYTHONDONTWRITEBYTECODE=1 \
24+
PYTHONUNBUFFERED=1 \
25+
PATH="/opt/venv/bin:${PATH}" \
26+
WEB_CONCURRENCY=4
27+
28+
WORKDIR /app
29+
30+
RUN useradd --create-home --uid 10001 appuser
31+
32+
# Copy prebuilt virtual environment from builder stage.
33+
COPY --from=builder /opt/venv /opt/venv
34+
35+
# Application code and migration files.
36+
COPY app ./app
37+
COPY alembic ./alembic
38+
COPY alembic.ini ./alembic.ini
39+
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
40+
41+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
42+
43+
USER appuser
44+
45+
EXPOSE 8000
46+
47+
ENTRYPOINT ["docker-entrypoint.sh"]

docker-compose.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
services:
2+
postgres:
3+
image: postgres:16-alpine
4+
container_name: task-manager-postgres
5+
environment:
6+
POSTGRES_DB: task_manager
7+
POSTGRES_USER: task_user
8+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
9+
ports:
10+
- "5432:5432"
11+
volumes:
12+
- postgres_data:/var/lib/postgresql/data
13+
healthcheck:
14+
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-task_user} -d ${POSTGRES_DB:-task_manager}"]
15+
interval: 5s
16+
timeout: 5s
17+
retries: 10
18+
start_period: 5s
19+
restart: unless-stopped
20+
21+
redis:
22+
image: redis:7-alpine
23+
container_name: task-manager-redis
24+
command: ["redis-server", "--appendonly", "yes"]
25+
ports:
26+
- "6379:6379"
27+
volumes:
28+
- redis_data:/data
29+
healthcheck:
30+
test: ["CMD", "redis-cli", "ping"]
31+
interval: 5s
32+
timeout: 3s
33+
retries: 10
34+
start_period: 3s
35+
restart: unless-stopped
36+
37+
api:
38+
build:
39+
context: .
40+
dockerfile: Dockerfile
41+
container_name: task-manager-api
42+
env_file:
43+
- .env
44+
environment:
45+
DATABASE_URL: postgresql+asyncpg://task_user:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@postgres:5432/task_manager
46+
REDIS_URL: redis://redis:6379/0
47+
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required}
48+
ALGORITHM: HS256
49+
ACCESS_TOKEN_EXPIRE_MINUTES: 10
50+
REFRESH_TOKEN_EXPIRE_DAYS: 7
51+
WEB_CONCURRENCY: 4
52+
ports:
53+
- "8000:8000"
54+
depends_on:
55+
postgres:
56+
condition: service_healthy
57+
redis:
58+
condition: service_healthy
59+
restart: unless-stopped
60+
61+
prometheus:
62+
image: prom/prometheus:v2.54.1
63+
container_name: task-manager-prometheus
64+
command:
65+
- "--config.file=/etc/prometheus/prometheus.yml"
66+
- "--storage.tsdb.path=/prometheus"
67+
- "--web.enable-lifecycle"
68+
ports:
69+
- "9090:9090"
70+
volumes:
71+
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
72+
- prometheus_data:/prometheus
73+
depends_on:
74+
api:
75+
condition: service_started
76+
restart: unless-stopped
77+
78+
grafana:
79+
image: grafana/grafana:11.2.0
80+
container_name: task-manager-grafana
81+
ports:
82+
- "3000:3000"
83+
environment:
84+
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
85+
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin}
86+
GF_USERS_ALLOW_SIGN_UP: "false"
87+
volumes:
88+
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro
89+
- grafana_data:/var/lib/grafana
90+
depends_on:
91+
prometheus:
92+
condition: service_started
93+
restart: unless-stopped
94+
95+
volumes:
96+
postgres_data:
97+
redis_data:
98+
prometheus_data:
99+
grafana_data:

docker-entrypoint.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
if [ "$#" -eq 0 ]; then
5+
set -- uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers "${WEB_CONCURRENCY:-4}"
6+
fi
7+
8+
alembic upgrade head
9+
exec "$@"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: 1
2+
3+
datasources:
4+
- name: Prometheus
5+
type: prometheus
6+
access: proxy
7+
url: http://prometheus:9090
8+
isDefault: true
9+
editable: false

monitoring/prometheus.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
global:
2+
scrape_interval: 5s
3+
evaluation_interval: 5s
4+
5+
scrape_configs:
6+
- job_name: "prometheus"
7+
static_configs:
8+
- targets: ["localhost:9090"]
9+
10+
- job_name: "task-manager-api"
11+
metrics_path: /metrics
12+
static_configs:
13+
- targets: ["api:8000"]

0 commit comments

Comments
 (0)