From 0a017f52cb8cfce7346c184ca957cdea531b25cb Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Wed, 25 Feb 2026 22:55:58 +0000 Subject: [PATCH] perf: switch to uv for faster dependency installation - Replace pip with uv in Dockerfile.service builder stage (~5-10x faster) - Replace pip with uv in CI test step - Separate pyproject.toml copy from source copy in Dockerfile for better Docker layer caching (deps only reinstalled when pyproject.toml changes) - Add cache_from for buildx to reuse layers from previous builds - Remove pip cache workaround from test step (not persisted in K8s) --- .woodpecker.yml | 24 ++++++++---------------- docker/Dockerfile.service | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index e55faf3..30f483f 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -11,23 +11,13 @@ clone: steps: - name: test - image: python:3.12-slim + image: docker.io/library/python:3.12-slim commands: - - | - if [ -d /woodpecker/pip-cache ]; then - echo "Restoring pip cache..." - cp -r /woodpecker/pip-cache .pip-cache - fi - - python -m venv .venv + - pip install uv - >- - .venv/bin/pip install --quiet --upgrade pip - - >- - .venv/bin/pip install --quiet --cache-dir .pip-cache + uv pip install --system --quiet ".[api,news,sentiment,trading,backtester,dev]" - - .venv/bin/pytest tests/ -v --tb=short -m "not integration" - - | - echo "Saving pip cache..." - cp -r .pip-cache /woodpecker/pip-cache 2>/dev/null || true + - python -m pytest tests/ -v --tb=short -m "not integration" - name: build-service-image image: woodpeckerci/plugin-docker-buildx @@ -42,6 +32,7 @@ steps: context: . build_args: - SERVICE_MODULE=api_gateway + cache_from: viktorbarzin/trading-bot-service:latest tags: - "${CI_PIPELINE_NUMBER}" - latest @@ -59,12 +50,13 @@ steps: context: . build_args: - NGINX_CONF=docker/nginx-k8s.conf + cache_from: viktorbarzin/trading-bot-dashboard:latest tags: - "${CI_PIPELINE_NUMBER}" - latest - name: update-deployment - image: alpine + image: docker.io/library/alpine depends_on: - build-service-image - build-dashboard-image @@ -118,7 +110,7 @@ steps: }" | jq '{name: .metadata.name, generation: .metadata.generation}' - name: verify-deploy - image: alpine + image: docker.io/library/alpine depends_on: - update-deployment commands: diff --git a/docker/Dockerfile.service b/docker/Dockerfile.service index 365c768..60f8c19 100644 --- a/docker/Dockerfile.service +++ b/docker/Dockerfile.service @@ -1,6 +1,5 @@ # Multi-stage Dockerfile for all Python microservices. # Build args: -# EXTRAS — pip optional-dependency groups (e.g. "news", "sentiment,trading") # SERVICE_MODULE — Python module name under services/ (e.g. "news_fetcher") # --------------------------------------------------------------------------- @@ -10,16 +9,28 @@ FROM python:3.12-slim AS builder WORKDIR /app -# Copy project metadata and source so pip can resolve the local package +# Install uv for fast dependency resolution +RUN pip install uv + +# Copy ONLY dependency metadata first — this layer is cached until +# pyproject.toml changes, so dependency install is skipped on pure code changes. COPY pyproject.toml . + +# Create minimal package stubs so uv can resolve the local editable install +# without copying all source (which would bust the cache on every commit). +RUN mkdir -p shared services backtester && \ + uv pip install --system --no-cache-dir ".[api,news,sentiment,trading,backtester]" && \ + uv pip install --system --no-cache-dir curl_cffi 2>/dev/null || true + +# NOW copy the actual source code (changes here don't re-trigger dep install) COPY shared/ shared/ COPY services/ services/ COPY backtester/ backtester/ COPY alembic/ alembic/ COPY alembic.ini . -# Install all service dependencies (hardcoded to avoid build-arg comma parsing issues) -RUN pip install --no-cache-dir ".[api,news,sentiment,trading,backtester]" && pip install --no-cache-dir curl_cffi 2>/dev/null || true +# Re-install in-place so the package metadata points to actual source +RUN uv pip install --system --no-cache-dir --no-deps -e . # --------------------------------------------------------------------------- # Stage 2: slim runtime image