From 4e73900969eff2dea1484781bdd7af94ef1c9256 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 17 Aug 2025 13:32:57 +0300 Subject: [PATCH] feat: add Docker support with Dockerfile, docker-compose, and startup scripts --- Dockerfile | 33 ++++++++++++++-- build-docker.sh | 2 + docker-compose.yml | 94 ++++++++++++++++++++++++++++++++++++++++++++++ main.py | 1 + start_fastapi.sh | 1 + start_taskiq.sh | 46 ----------------------- 6 files changed, 128 insertions(+), 49 deletions(-) create mode 100755 build-docker.sh create mode 100644 docker-compose.yml create mode 100755 start_fastapi.sh diff --git a/Dockerfile b/Dockerfile index 9fd6682..073a3f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,31 @@ -FROM ubuntu:latest -LABEL authors="admin" +FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder +ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy -ENTRYPOINT ["top", "-b"] \ No newline at end of file +# Disable Python downloads, because we want to use the system interpreter +# across both images. If using a managed Python version, it needs to be +# copied from the build image into the final image; see `standalone.Dockerfile` +# for an example. +ENV UV_PYTHON_DOWNLOADS=0 + +# Install git +RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --locked --no-install-project --no-dev +COPY . /app +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --locked --no-dev + +# Then, use a final image without uv +FROM python:3.13-slim-bookworm +# It is important to use the image that matches the builder, as the path to the +# Python executable must be the same, e.g., using `python:3.11-slim-bookworm` +# will fail. + +# Copy the application from the builder +COPY --from=builder --chown=app:app /app /app +ENV PATH="/app/.venv/bin:$PATH" +WORKDIR /app diff --git a/build-docker.sh b/build-docker.sh new file mode 100755 index 0000000..95d46ed --- /dev/null +++ b/build-docker.sh @@ -0,0 +1,2 @@ +docker build -t git.denco.store/fakz9/sipro-stocks:latest . +docker push git.denco.store/fakz9/sipro-stocks:latest \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..28cf9ec --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,94 @@ +services: + taskiq_worker: + image: git.denco.store/fakz9/sipro-stocks:latest + container_name: stocks_worker + restart: unless-stopped + env_file: .env + command: [ "sh", "./start_taskiq.sh" ] + volumes_from: + - tmp + volumes: + - pg-socket:/run/postgresql + networks: + - appnet + depends_on: + redis: + condition: service_healthy + rabbitmq: + condition: service_healthy + taskiq_scheduler: + image: git.denco.store/fakz9/sipro-stocks:latest + container_name: stocks_scheduler + restart: unless-stopped + env_file: .env + command: [ "sh", "./start_scheduler.sh" ] + volumes_from: + - tmp + volumes: + - pg-socket:/run/postgresql + networks: + - appnet + depends_on: + - fastapi + fastapi: + image: git.denco.store/fakz9/sipro-stocks:latest + container_name: stocks_fastapi + restart: unless-stopped + env_file: .env + command: [ "sh", "./start_fastapi.sh" ] + volumes_from: + - tmp + volumes: + - pg-socket:/run/postgresql + networks: + - appnet + depends_on: + - taskiq_worker + ports: + - "8000:8000" + tmp: + image: busybox:latest + command: [ "chmod", "-R","777", "/tmp/docker" ] + volumes: + - /tmp/docker/ + rabbitmq: + image: rabbitmq:latest + container_name: stocks_rabbitmq + restart: unless-stopped + environment: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + RABBITMQ_DEFAULT_VHOST: stocks_vhost + networks: + - appnet + healthcheck: + test: [ "CMD", "rabbitmqctl", "status" ] + interval: 10s + timeout: 5s + retries: 5 + redis: + image: redis:latest + container_name: stocks_redis + restart: unless-stopped + volumes_from: + - tmp + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD} + command: [ "redis-server", "--unixsocket","/tmp/docker/redis.sock", "--unixsocketperm", "777", "--requirepass", "${REDIS_PASSWORD}" ] + networks: + - appnet + healthcheck: + test: [ "CMD" ,"redis-cli", "ping" ] + interval: 5s + timeout: 2s + retries: 5 + +networks: + appnet: +volumes: + pg-socket: + driver: local + driver_opts: + type: none + device: /run/postgresql + o: bind diff --git a/main.py b/main.py index 5690603..a45bc48 100644 --- a/main.py +++ b/main.py @@ -131,3 +131,4 @@ async def get_marketplace_stocks( ): updater = StocksUpdater(session) return await updater.get_all_stocks_for_marketplace(int(marketplace_id), only_available) + diff --git a/start_fastapi.sh b/start_fastapi.sh new file mode 100755 index 0000000..ecb451a --- /dev/null +++ b/start_fastapi.sh @@ -0,0 +1 @@ +gunicorn -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 main:app \ No newline at end of file diff --git a/start_taskiq.sh b/start_taskiq.sh index ca7cc55..337d486 100755 --- a/start_taskiq.sh +++ b/start_taskiq.sh @@ -1,57 +1,11 @@ #!/bin/bash ulimit -n 97816 -# Load Redis password from .env file -export REDIS_PASSWORD=$(grep -m 1 'REDIS_PASSWORD' .env | cut -d '=' -f2) - -# Color definitions for log messages GREEN='\033[0;32m' -YELLOW='\033[0;33m' -RED='\033[0;31m' -NC='\033[0m' # No Color -# Function to print log messages with colors log_info() { echo -e "${GREEN}[INFO] $1${NC}" } - -log_warning() { - echo -e "${YELLOW}[WARNING] $1${NC}" -} - -log_error() { - echo -e "${RED}[ERROR] $1${NC}" -} - -# Start clearing Redis locks -log_info "Clearing Redis locks..." - -# Check if Redis password was set correctly -if [ -z "$REDIS_PASSWORD" ]; then - log_error "REDIS_PASSWORD not set. Please check your .env file." - exit 1 -fi - -# Deleting keys and getting the total deleted count -TOTAL_DELETED_KEYS=$(redis-cli -a "$REDIS_PASSWORD" --scan --pattern '*_lock' 2>/dev/null | \ - xargs -I {} redis-cli -a "$REDIS_PASSWORD" del {} 2>/dev/null | wc -l) - -# Log the result -if [ "$TOTAL_DELETED_KEYS" -gt 0 ]; then - log_info "Total deleted keys: $TOTAL_DELETED_KEYS" -else - log_warning "No keys matched the pattern '*_lock'." -fi - -# Clear RabbitMQ queue -log_info "Purging RabbitMQ queue 'taskiq' in vhost 'stocks_vhost'..." -rabbitmqctl purge_queue -p stocks_vhost taskiq -if [ $? -eq 0 ]; then - log_info "RabbitMQ queue purged successfully." -else - log_error "Failed to purge RabbitMQ queue. Please check your RabbitMQ setup." -fi - # Start the Taskiq worker log_info "Starting Taskiq worker..." taskiq worker background:taskiq_broker background.tasks --max-async-task 1000 --max-threadpool-threads 8 --max-prefetch 10000 --workers 1