|
1 | | -FROM python:3.12-slim |
| 1 | +# STAGE 1: Builder |
| 2 | +# We use a separate stage to compile dependencies and build artifacts. |
| 3 | +# This allows us to discard build tools and caches in the final image. |
| 4 | +FROM python:3.12-slim AS builder |
| 5 | + |
| 6 | +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv |
2 | 7 |
|
3 | | -# Set working directory |
4 | 8 | WORKDIR /app |
5 | 9 |
|
6 | | -# Install system dependencies including Docker CLI and Redis CLI |
| 10 | +# Set uv environment variables for optimization |
| 11 | +ENV UV_COMPILE_BYTECODE=1 |
| 12 | +ENV UV_LINK_MODE=copy |
| 13 | + |
| 14 | +# Install system dependencies required ONLY for building/fetching (like git) |
| 15 | +# We don't need Docker CLI here unless your build script relies on it. |
7 | 16 | RUN apt-get update && apt-get install -y \ |
8 | 17 | git \ |
| 18 | + curl \ |
| 19 | + && rm -rf /var/lib/apt/lists/* |
| 20 | + |
| 21 | +# Install dependencies |
| 22 | +# 1. Copy only dependency files first to leverage Docker layer caching |
| 23 | +COPY pyproject.toml uv.lock ./ |
| 24 | + |
| 25 | +# 2. Install dependencies using cache mount. |
| 26 | +# --mount=type=cache prevents the uv cache (~GBs) from being saved to the image layer, |
| 27 | +# directly solving your "ResourceExhausted" error. |
| 28 | +RUN --mount=type=cache,target=/root/.cache/uv \ |
| 29 | + uv sync --frozen --no-dev --no-install-project |
| 30 | + |
| 31 | +# 3. Copy application code |
| 32 | +COPY . . |
| 33 | + |
| 34 | +# 4. Install the project itself and generate artifacts |
| 35 | +RUN --mount=type=cache,target=/root/.cache/uv \ |
| 36 | + uv sync --frozen --no-dev && \ |
| 37 | + mkdir -p /app/artifacts && \ |
| 38 | + # Attempt to build artifacts, but don't fail build if it requires runtime services |
| 39 | + (uv run --no-sync redis-sre-agent pipeline prepare-sources \ |
| 40 | + --source-dir /app/source_documents \ |
| 41 | + --prepare-only \ |
| 42 | + --artifacts-path /app/artifacts || \ |
| 43 | + echo "Warning: Could not prepare source documents at build time") |
| 44 | + |
| 45 | + |
| 46 | +# STAGE 2: Runtime |
| 47 | +# This is the final image. It will be much smaller. |
| 48 | +FROM python:3.12-slim |
| 49 | + |
| 50 | +WORKDIR /app |
| 51 | + |
| 52 | +# Install ONLY runtime system dependencies |
| 53 | +# We repeat the Docker/Redis install here because they are needed at runtime. |
| 54 | +RUN apt-get update && apt-get install -y \ |
9 | 55 | curl \ |
10 | 56 | ca-certificates \ |
| 57 | + redis-tools \ |
11 | 58 | gnupg \ |
12 | 59 | lsb-release \ |
13 | | - redis-tools \ |
14 | 60 | && mkdir -p /etc/apt/keyrings \ |
15 | 61 | && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \ |
16 | 62 | && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ |
17 | 63 | && apt-get update \ |
18 | 64 | && apt-get install -y docker-ce-cli \ |
19 | | - && apt-get purge -y gnupg lsb-release git \ |
20 | | - && apt-get autoremove -y \ |
| 65 | + && apt-get clean \ |
21 | 66 | && rm -rf /var/lib/apt/lists/* |
22 | 67 |
|
23 | | -# Install uv |
24 | | -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv |
25 | | - |
26 | | -# Copy dependency files and project metadata required at build time |
27 | | - |
28 | | -COPY pyproject.toml uv.lock ./ |
29 | | -COPY README.md ./ |
30 | | - |
31 | | -# Install dependencies |
32 | | -RUN uv sync --frozen --no-dev |
33 | | - |
34 | | -# Copy application code |
35 | | -COPY . . |
| 68 | +# Copy the virtual environment from the builder stage |
| 69 | +COPY --from=builder /app/.venv /app/.venv |
| 70 | +COPY --from=builder /app/artifacts /app/artifacts |
| 71 | +COPY --from=builder /app /app |
36 | 72 |
|
| 73 | +# Add the virtual environment to PATH |
| 74 | +# This allows us to run "uvicorn" or "python" directly without "uv run" |
| 75 | +ENV PATH="/app/.venv/bin:$PATH" |
37 | 76 |
|
38 | | -# Pre-build knowledge base artifacts for faster production startup |
39 | | -# This prepares batch artifacts from source documents without requiring Redis at build time |
40 | | -RUN mkdir -p /app/artifacts && \ |
41 | | - uv run redis-sre-agent pipeline prepare-sources \ |
42 | | - --source-dir /app/source_documents \ |
43 | | - --prepare-only \ |
44 | | - --artifacts-path /app/artifacts || \ |
45 | | - echo "Warning: Could not prepare source documents at build time" |
46 | | - |
47 | | -# Copy and setup entrypoint script |
| 77 | +# Setup permissions |
48 | 78 | COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh |
49 | | -RUN chmod +x /usr/local/bin/docker-entrypoint.sh |
| 79 | +RUN chmod +x /usr/local/bin/docker-entrypoint.sh && \ |
| 80 | + useradd --create-home --shell /bin/bash app && \ |
| 81 | + groupadd -g 999 docker || true && \ |
| 82 | + usermod -aG docker app && \ |
| 83 | + chown -R app:app /app |
50 | 84 |
|
51 | | -# Create non-root user and add to docker group |
52 | | -RUN useradd --create-home --shell /bin/bash app \ |
53 | | - && groupadd -g 999 docker || true \ |
54 | | - && usermod -aG docker app \ |
55 | | - && chown -R app:app /app |
56 | 85 | USER app |
57 | 86 |
|
58 | | -# Health check |
59 | 87 | HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ |
60 | 88 | CMD curl -f http://localhost:8000/api/v1/health || exit 1 |
61 | 89 |
|
62 | | -# Use entrypoint for initialization |
63 | 90 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] |
64 | 91 |
|
65 | | -# Default command (can be overridden) |
66 | | -CMD ["uv", "run", "uvicorn", "redis_sre_agent.api.app:app", "--host", "0.0.0.0", "--port", "8000"] |
| 92 | +# Optimized CMD: Call uvicorn directly from the venv. |
| 93 | +# We don't need 'uv run' overhead in production. |
| 94 | +CMD ["uvicorn", "redis_sre_agent.api.app:app", "--host", "0.0.0.0", "--port", "8000"] |
0 commit comments