# syntax=docker/dockerfile:1 # ============================================================================= # pg_trickle GHCR image — PostgreSQL 18.3 + pg_trickle pre-installed. # # Published to: ghcr.io/grove/pg_trickle # # Suitable for: # - Quick local evaluation: docker run --rm -e POSTGRES_PASSWORD=pass ... # - CI/CD matrices: replace postgres:18 with this image # - Kubernetes base images: base for custom overlays # # NOT the same as the CNPG Image Volume Extension image (cnpg/Dockerfile.ext), # which is scratch-based and extension-files only. # # Build (from project root): # docker build \ # -t ghcr.io/grove/pg_trickle:0.13.0-pg18.3 \ # -f Dockerfile.ghcr . # # Run (getting started): # docker run --rm -e POSTGRES_PASSWORD=secret \ # ghcr.io/grove/pg_trickle:latest # # Scale up memory at runtime without rebuilding: # docker run --rm -e POSTGRES_PASSWORD=secret \ # ghcr.io/grove/pg_trickle:latest \ # -c shared_buffers=2GB -c work_mem=64MB -c effective_cache_size=6GB # # Default GUC settings are documented in docker/pg_trickle-defaults.conf. # ============================================================================= # ── Stage 1: Prepare build environment ────────────────────────────────────── FROM postgres:18.3-bookworm AS build-env ARG VERSION=0.13.0 # Install build dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ build-essential \ libreadline-dev \ zlib1g-dev \ pkg-config \ libssl-dev \ libclang-dev \ clang \ postgresql-server-dev-18 \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Install Rust stable toolchain RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --default-toolchain stable ENV PATH="/root/.cargo/bin:${PATH}" # Install cargo-pgrx (version must match Cargo.toml) RUN cargo install --locked cargo-pgrx --version 0.17.0 # Initialise pgrx for PostgreSQL 18 using the system pg_config RUN cargo pgrx init --pg18 /usr/bin/pg_config # ── Stage 2: Compile dependencies (cached layer) ───────────────────────────── FROM build-env AS build-deps WORKDIR /build COPY Cargo.toml Cargo.lock ./ COPY pgtrickle-tui/Cargo.toml pgtrickle-tui/Cargo.toml # Minimal stubs so cargo can compile deps without the full source tree. # These stubs will be replaced in the build stage below. RUN mkdir -p src/bin src/dvm/operators benches pgtrickle-tui/src && \ echo '#![allow(warnings)] fn main() {}' > src/bin/pgrx_embed.rs && \ echo '#![allow(warnings)]' > src/lib.rs && \ echo '' > src/dvm/mod.rs && \ echo '' > src/dvm/operators/mod.rs && \ echo '' > src/ivm.rs && \ echo 'fn main() {}' > benches/refresh_bench.rs && \ echo 'fn main() {}' > benches/diff_operators.rs && \ echo 'fn main() {}' > pgtrickle-tui/src/main.rs # Pre-fetch dependencies. Docker caches this layer independently. # If only src/ changes on the next build, this layer is skipped, saving 10–15 min. RUN --mount=type=cache,target=/root/.cargo/registry \ --mount=type=cache,target=/root/.cargo/git \ cargo fetch # ── Stage 3: Build the extension ───────────────────────────────────────────── FROM build-env AS builder WORKDIR /build # Copy source code and configuration COPY Cargo.toml Cargo.lock ./ COPY pgtrickle-tui/Cargo.toml pgtrickle-tui/Cargo.toml COPY src/ src/ COPY pg_trickle.control ./ # Create placeholder bench and workspace member files (required by Cargo.toml # but not needed for extension package) RUN mkdir -p benches pgtrickle-tui/src && \ echo 'fn main() {}' > benches/diff_operators.rs && \ echo 'fn main() {}' > benches/refresh_bench.rs && \ echo 'fn main() {}' > pgtrickle-tui/src/main.rs # Compile the extension. Cargo will automatically use cached dependencies # from the build-deps stage's `cargo fetch` (stored in /root/.cargo). RUN --mount=type=cache,target=/root/.cargo/registry \ --mount=type=cache,target=/root/.cargo/git \ cargo pgrx package --pg-config /usr/bin/pg_config && \ mkdir -p /artefacts && \ cp -r target/release/pg_trickle-pg18 /artefacts/ # ── Stage 4: Runtime image ─────────────────────────────────────────────────── FROM postgres:18.3-bookworm ARG VERSION=0.13.0 ARG REPO_URL=https://github.com/grove/pg-trickle LABEL org.opencontainers.image.title="pg_trickle" \ org.opencontainers.image.description="PostgreSQL 18.3 with pg_trickle streaming tables and IVM pre-installed" \ org.opencontainers.image.version="${VERSION}" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.source="${REPO_URL}" \ org.opencontainers.image.documentation="${REPO_URL}/blob/main/docs/GETTING_STARTED.md" \ org.opencontainers.image.vendor="grove" \ org.opencontainers.image.base.name="docker.io/library/postgres:18.3-bookworm" # Copy extension artifacts from builder COPY --from=builder \ /artefacts/pg_trickle-pg18/usr/share/postgresql/18/extension/ \ /usr/share/postgresql/18/extension/ COPY --from=builder \ /artefacts/pg_trickle-pg18/usr/lib/postgresql/18/lib/ \ /usr/lib/postgresql/18/lib/ # Configure pg_trickle in the default postgresql.conf template so any # cluster created from this image has the extension auto-loaded with # sensible defaults. The full set of defaults is documented in # docker/pg_trickle-defaults.conf (included in the build context). COPY docker/pg_trickle-defaults.conf /tmp/pg_trickle-defaults.conf RUN echo "" >> /usr/share/postgresql/postgresql.conf.sample && \ cat /tmp/pg_trickle-defaults.conf >> /usr/share/postgresql/postgresql.conf.sample && \ rm /tmp/pg_trickle-defaults.conf # Create the extension on the default 'postgres' database during initdb so # the background worker launcher finds it immediately on first startup. RUN mkdir -p /docker-entrypoint-initdb.d && \ echo "CREATE EXTENSION IF NOT EXISTS pg_trickle CASCADE;" \ > /docker-entrypoint-initdb.d/00-pg-trickle.sql # Verify artifacts are in place RUN ls -la /usr/share/postgresql/18/extension/pg_trickle* && \ ls -la /usr/lib/postgresql/18/lib/pg_trickle* EXPOSE 5432