Compare commits

...

5 Commits

Author SHA1 Message Date
Marco Nenciarini
b89152646e
docs: clean up Dockerfile comments for clarity and accuracy
Remove obvious comments that restate what code does, fix misleading
cross-compilation explanation, and improve grammar.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 15:50:50 +01:00
Marco Nenciarini
2f1ca8ab19
fix: use sysconfig for Python stdlib path and remove x86_64 comment
Use sysconfig.get_path('stdlib') to dynamically determine the Python
standard library path instead of hardcoding python3.13. Also remove
architecture-specific comment since this is a multiarch image.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 15:41:03 +01:00
Marco Nenciarini
4cab8f826b
fix: compile all Python bytecode in final stage as root
Move compileall to the final distroless stage and run it as root
to ensure all Python files are pre-compiled, including the system
standard library. This avoids runtime compilation errors when the
filesystem is read-only.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 14:32:00 +01:00
Marco Nenciarini
c8220fb3a9
fix: automate library dependency detection using distroless package list
Replace the manual library exclusion list with automated dependency
resolution using apt-cache. The approach queries the dependency tree
of packages in the distroless base image (from GoogleContainerTools
distroless configs) and excludes them from our requirements.

This reduces the image to 260MB (down from 270MB) by avoiding
duplicate libraries already present in the distroless base. Only 7
packages are now downloaded instead of manually maintaining a list
of 13 exclusions.

The package list is sourced from distroless upstream configs and
documented with URLs, making it maintainable as distroless evolves.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 13:39:48 +01:00
Marco Nenciarini
a29726e0ee
fix: use distroless base image to reduce size and attack surface
Switch from python:3.13-slim-trixie to distroless/python3-debian13
for the sidecar container. The virtualenv approach now extracts
runtime libraries from Debian packages using dpkg, eliminating the
need for apt and package management tools in the final image.

The image is 44% smaller (260MB vs 463MB on main, or 31% vs 377MB
from the previous commit) with 70% fewer packages (35 vs 115) while
maintaining zero HIGH/CRITICAL vulnerabilities. There is no shell
or package manager in the final image, reducing the attack surface
significantly.

Based on Google's distroless best practices.

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 13:39:48 +01:00

View File

@ -2,7 +2,7 @@
# The container needs to provide and build two components:
# * barman-cloud
# * instance plugin
# Both components are built before going into the final container
# Both components are built before going into a distroless container
# Build the manager binary
FROM --platform=$BUILDPLATFORM golang:1.25.6 AS gobuilder
@ -10,7 +10,7 @@ ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
# Copy the Go Modules manifests
COPY ../go.mod go.mod
COPY ../go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
@ -20,46 +20,73 @@ RUN go mod download
ENV GOCACHE=/root/.cache/go-build
ENV GOMODCACHE=/go/pkg/mod
# Copy the go source
COPY ../cmd/manager/main.go cmd/manager/main.go
COPY ../api/ api/
COPY ../internal/ internal/
# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
# Build Go binary for target platform (TARGETOS/TARGETARCH)
# Docker BuildKit sets these based on --platform flag or defaults to the build host platform
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/manager/main.go
# Build wheel files for Python dependencies
FROM python:3.13-slim-trixie AS pythonbuilder
# Build Python virtualenv with all dependencies
FROM debian:trixie-slim AS pythonbuilder
WORKDIR /build
# Install postgresql-common and setup pgdg repository first
RUN apt-get update && \
apt-get install -y --no-install-recommends postgresql-common && \
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
# Install build dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
postgresql-common \
build-essential && \
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
apt-get install -y --no-install-recommends \
python3 \
python3-venv \
python3-dev \
build-essential \
libpq-dev \
liblz4-dev \
libsnappy-dev
# Copy requirements
COPY containers/sidecar-requirements.txt .
# Build wheels with pip cache mount
RUN --mount=type=cache,target=/root/.cache/pip \
pip wheel --wheel-dir=/wheels -r sidecar-requirements.txt
# Create virtualenv and install dependencies
RUN python3 -m venv /venv && \
/venv/bin/pip install --upgrade pip setuptools wheel && \
/venv/bin/pip install --no-cache-dir -r sidecar-requirements.txt
# Final sidecar image
FROM python:3.13-slim-trixie
# Download and extract runtime library packages and their dependencies
# Using apt-cache to automatically resolve dependencies, filtering out packages
# already present in the distroless base image.
# Distroless package list from: https://github.com/GoogleContainerTools/distroless/blob/main/base/config.bzl
# and https://github.com/GoogleContainerTools/distroless/blob/main/python3/config.bzl
RUN mkdir -p /dependencies /build/downloads && \
cd /build/downloads && \
DISTROLESS_PACKAGES="libc6 libssl3t64 libzstd1 zlib1g libgcc-s1 libstdc++6 \
libbz2-1.0 libdb5.3t64 libexpat1 liblzma5 libsqlite3-0 libuuid1 \
libncursesw6 libtinfo6 libcom-err2 libcrypt1 libgssapi-krb5-2 \
libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libnsl2 \
libreadline8t64 libtirpc3t64 libffi8 libpython3.13-minimal \
libpython3.13-stdlib python3.13-minimal python3.13-venv" && \
apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
$DISTROLESS_PACKAGES 2>/dev/null | grep "^\w" | sort -u > /tmp/distroless.txt && \
apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
libpq5 liblz4-1 libsnappy1v5 2>/dev/null | grep "^\w" | sort -u | \
grep -v -F -x -f /tmp/distroless.txt > /tmp/packages.txt && \
apt-get download $(cat /tmp/packages.txt) && \
for deb in *.deb; do \
dpkg -x "$deb" /dependencies; \
done
# Final sidecar image using distroless base for minimal size and fewer packages
FROM gcr.io/distroless/python3-debian13:nonroot
ENV SUMMARY="CloudNativePG Barman plugin" \
DESCRIPTION="Container image that provides the barman-cloud sidecar"
DESCRIPTION="Container image that provides the barman-cloud sidecar" \
PATH="/venv/bin:$PATH"
LABEL summary="$SUMMARY" \
description="$DESCRIPTION" \
@ -71,26 +98,13 @@ LABEL summary="$SUMMARY" \
version="" \
release="1"
# Install runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
postgresql-common && \
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
apt-get install -y --no-install-recommends \
libpq5 \
liblz4-1 \
libsnappy1v5 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install wheels using bind mount (wheels not included in final layers)
# and ensure all Python bytecode is freshly compiled with correct timestamps
RUN --mount=type=bind,from=pythonbuilder,source=/wheels,target=/wheels \
pip install --no-cache-dir /wheels/*.whl && \
python -m compileall -q
# Copy Go manager binary
COPY --from=pythonbuilder /venv /venv
COPY --from=pythonbuilder /dependencies/usr/lib /usr/lib
COPY --from=gobuilder /workspace/manager /manager
# Compile all Python bytecode as root to avoid runtime compilation
USER 0:0
RUN ["/venv/bin/python3", "-c", "import sysconfig, compileall; compileall.compile_dir(sysconfig.get_path('stdlib'), quiet=1); compileall.compile_dir('/venv', quiet=1)"]
USER 26:26
ENTRYPOINT ["/manager"]