build: add dependency caching for bundle builds

Cache pip/npm dependency downloads via BuildKit cache mounts and skip
the postgres pull when the image is already present locally, so a
repeat ./build.sh bundle run does not download dependencies twice.
This commit is contained in:
2026-08-03 17:37:57 +07:00
parent a733bc15db
commit 1e0dacaf1b
5 changed files with 35 additions and 12 deletions

View File

@@ -41,6 +41,8 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
export DOCKER_BUILDKIT=1
BACKEND_ENV_FILE="$SCRIPT_DIR/backend/.env" BACKEND_ENV_FILE="$SCRIPT_DIR/backend/.env"
DIST_ROOT="$SCRIPT_DIR/dist/docker" DIST_ROOT="$SCRIPT_DIR/dist/docker"
@@ -158,6 +160,17 @@ get_repo_digest() {
fi fi
} }
# Pull an image only if it is not already present locally.
ensure_image_present() {
local source="$1"
if docker image inspect "$source" >/dev/null 2>&1; then
echo "[bundle] Image ${source} already present, skipping pull"
return 0
fi
docker pull "$source"
}
resolve_app_version() { resolve_app_version() {
local tag="$1" local tag="$1"
local git_commit local git_commit
@@ -719,8 +732,8 @@ bundle_release() {
build_agent "${tag}" build_agent "${tag}"
# Pull and tag postgres image # Pull and tag postgres image
echo "[bundle] Pulling postgres image ${postgres_source}..." echo "[bundle] Ensuring postgres image ${postgres_source}..."
docker pull "${postgres_source}" ensure_image_present "${postgres_source}"
docker tag "${postgres_source}" "${postgres_tag}" docker tag "${postgres_source}" "${postgres_tag}"
# Release gate: fresh PostgreSQL migration + backend boot + restart must pass. # Release gate: fresh PostgreSQL migration + backend boot + restart must pass.
@@ -905,8 +918,8 @@ bundle_embeddings() {
build_agent_embeddings "${tag}${suffix}" build_agent_embeddings "${tag}${suffix}"
# Pull and tag postgres image # Pull and tag postgres image
echo "[bundle:embeddings] Pulling postgres image ${postgres_source}..." echo "[bundle:embeddings] Ensuring postgres image ${postgres_source}..."
docker pull "${postgres_source}" ensure_image_present "${postgres_source}"
docker tag "${postgres_source}" "${postgres_tag}" docker tag "${postgres_source}" "${postgres_tag}"
# Release gate: fresh PostgreSQL migration + backend boot + restart must pass. # Release gate: fresh PostgreSQL migration + backend boot + restart must pass.
@@ -1023,6 +1036,9 @@ Notes:
- Bundle commands (bundle, bundle:embeddings) now include postgres:16-alpine - Bundle commands (bundle, bundle:embeddings) now include postgres:16-alpine
as superset-tools-postgres:<tag> — loaded together with other images as superset-tools-postgres:<tag> — loaded together with other images
via 'xz -dc ... | docker load'. No external PostgreSQL required. via 'xz -dc ... | docker load'. No external PostgreSQL required.
- pip/npm dependency downloads are cached via BuildKit cache mounts and the
postgres pull is skipped when the image is already present locally.
Clear the dependency cache with: docker buildx prune
HELP HELP
} }

View File

@@ -26,12 +26,14 @@ RUN pip install --no-cache-dir -e /app/shared/
# Install agent requirements # Install agent requirements
COPY agent/requirements.txt /app/agent/requirements.txt COPY agent/requirements.txt /app/agent/requirements.txt
RUN pip install --no-cache-dir -r /app/agent/requirements.txt RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r /app/agent/requirements.txt
# Optional: semantic embedding routing # Optional: semantic embedding routing
COPY agent/requirements-embeddings.txt /app/agent/requirements-embeddings.txt COPY agent/requirements-embeddings.txt /app/agent/requirements-embeddings.txt
RUN if [ "$WITH_EMBEDDINGS" = "true" ]; then \ RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir -r /app/agent/requirements-embeddings.txt; \ if [ "$WITH_EMBEDDINGS" = "true" ]; then \
pip install -r /app/agent/requirements-embeddings.txt; \
fi fi
# Agent source code # Agent source code

View File

@@ -18,7 +18,8 @@ WORKDIR /app/frontend
# Install deps (layer cache when package.json unchanged) # Install deps (layer cache when package.json unchanged)
COPY frontend/package.json frontend/package-lock.json* ./ COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci --prefer-offline --no-audit --no-fund --legacy-peer-deps RUN --mount=type=cache,target=/root/.npm \
npm ci --prefer-offline --no-audit --no-fund --legacy-peer-deps
# Build frontend # Build frontend
COPY frontend/ ./ COPY frontend/ ./
@@ -43,7 +44,8 @@ RUN apt-get update \
# Python deps (NO playwright — saves ~350MB) # Python deps (NO playwright — saves ~350MB)
COPY backend/requirements-backend.txt /app/backend/requirements-backend.txt COPY backend/requirements-backend.txt /app/backend/requirements-backend.txt
RUN pip install --no-cache-dir -r /app/backend/requirements-backend.txt RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r /app/backend/requirements-backend.txt
# Backend source # Backend source
COPY backend/ /app/backend/ COPY backend/ /app/backend/

View File

@@ -25,14 +25,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# Python зависимости — backend runtime # Python зависимости — backend runtime
COPY backend/requirements-backend.txt /app/backend/requirements-backend.txt COPY backend/requirements-backend.txt /app/backend/requirements-backend.txt
RUN pip install --no-cache-dir -r /app/backend/requirements-backend.txt RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r /app/backend/requirements-backend.txt
# Install shared package (LLM health, SSL, cot_logger) # Install shared package (LLM health, SSL, cot_logger)
COPY shared/ /app/shared/ COPY shared/ /app/shared/
RUN pip install --no-cache-dir -e /app/shared/ RUN pip install --no-cache-dir -e /app/shared/
# Install shared LLM deps (openai, httpx for _llm_health) # Install shared LLM deps (openai, httpx for _llm_health)
RUN pip install --no-cache-dir "openai>=1.0.0" "httpx>=0.28.1" RUN --mount=type=cache,target=/root/.cache/pip \
pip install "openai>=1.0.0" "httpx>=0.28.1"
# Browser binaries are required only by screenshot-capable deployments. API-only E2E # Browser binaries are required only by screenshot-capable deployments. API-only E2E
# stacks can opt out through INSTALL_PLAYWRIGHT_BROWSERS=0 to reduce image build pressure. # stacks can opt out through INSTALL_PLAYWRIGHT_BROWSERS=0 to reduce image build pressure.

View File

@@ -15,7 +15,8 @@ ENV APP_VERSION=${APP_VERSION}
WORKDIR /app/frontend WORKDIR /app/frontend
COPY frontend/package*.json ./ COPY frontend/package*.json ./
RUN npm ci --legacy-peer-deps RUN --mount=type=cache,target=/root/.npm \
npm ci --legacy-peer-deps
COPY frontend/ ./ COPY frontend/ ./
RUN npm run build RUN npm run build