Skip to content

Docker & Docker Compose

The repository includes a production-ready multi-stage Dockerfile:

# Stage 1: Build Rust CLI binary and Python wheel
FROM rust:1.75-bookworm AS builder
RUN apt-get update && apt-get install -y \
libssl-dev pkg-config python3 python3-pip python3-venv
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/
COPY python/ python/
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install maturin
RUN cargo build --release -p justapi-cli --features tls,compression
RUN maturin build -m crates/justapi-py/Cargo.toml --release -o wheels/
# Stage 2: Minimal runtime
FROM python:3.12-slim-bookworm
RUN apt-get update && apt-get install -y ca-certificates libssl3
WORKDIR /app
COPY --from=builder /app/target/release/justapi /usr/local/bin/justapi
COPY --from=builder /app/wheels /tmp/wheels
RUN pip install --no-cache-dir /tmp/wheels/*.whl
COPY . .
EXPOSE 8080
CMD ["python", "app.py"]
Terminal window
docker build -t my-justapi-app .
docker run -p 8080:8080 my-justapi-app
version: "3.9"
services:
justapi:
build: .
ports:
- "8080:8080"
environment:
- RUST_LOG=info
- DATABASE_URL=postgres://justapi:justapi@db:5432/justapi
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: justapi
POSTGRES_PASSWORD: justapi
POSTGRES_DB: justapi
healthcheck:
test: ["CMD-SHELL", "pg_isready -U justapi"]
interval: 5s
timeout: 5s
retries: 5
Terminal window
docker compose up -d

Generated projects include docker-compose.otel.yml:

services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # UI
- "4318:4318" # OTLP HTTP

Using uv in Docker (Smaller & Faster Builds)

Section titled “Using uv in Docker (Smaller & Faster Builds)”

For smaller Docker images and faster builds, replace pip with uv in your Dockerfile:

FROM python:3.12-slim-bookworm AS builder
RUN pip install uv
COPY --from=builder /app/wheels /tmp/wheels
RUN uv pip install --system --no-cache /tmp/wheels/*.whl

This reduces layer size and install time significantly.

  1. Use python:3.12-slim — Small image (~120 MB)
  2. Set panic = "abort" — Already configured in Cargo.toml
  3. Run as non-root — Use USER nobody or create an app user
  4. Add HEALTHCHECK — Use /health endpoint
  5. Use .dockerignore — Exclude target/, .git/, pycache/
FROM python:3.12-slim-bookworm
RUN adduser --disabled-password --gecos '' appuser
WORKDIR /app
COPY --from=builder /app/target/release/justapi /usr/local/bin/justapi
COPY --from=builder /app/wheels /tmp/wheels
RUN pip install --no-cache-dir /tmp/wheels/*.whl && rm -rf /tmp/wheels
COPY app.py .
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
CMD ["python", "app.py"]