plugin-barman-cloud/containers/Dockerfile.sidecar
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

121 lines
4.0 KiB
Docker

# Sidecar
# The container needs to provide and build two components:
# * barman-cloud
# * instance plugin
# Both components are built before going into a distroless container
# Build the manager binary
FROM --platform=$BUILDPLATFORM golang:1.25.6 AS gobuilder
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
# and so that source changes don't invalidate our downloaded layer
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.
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 Python virtualenv with all dependencies
# Using virtualenv ensures bytecode is compiled with correct timestamps
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
# After pgdg repo setup, this ensures we get updated versions from apt.postgresql.org
RUN apt-get update && \
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 .
# Create virtualenv and install dependencies
# Compileall ensures all bytecode is freshly compiled with correct timestamps
RUN python3 -m venv /venv && \
/venv/bin/pip install --upgrade pip setuptools wheel && \
/venv/bin/pip install --no-cache-dir -r sidecar-requirements.txt && \
/venv/bin/python -m compileall -q /venv
# Download and extract runtime library packages
# Using apt-get download + dpkg -x ensures we get all files from packages
# Note: libcrypto is part of libssl3t64, and liblber is part of libldap2
RUN mkdir -p /dependencies /build/downloads && \
cd /build/downloads && \
apt-get download \
libpq5 \
liblz4-1 \
libsnappy1v5 \
libssl3t64 \
libgssapi-krb5-2 \
libkrb5-3 \
libk5crypto3 \
libcom-err2 \
libkrb5support0 \
libldap2 \
libsasl2-2 \
libkeyutils1 \
libzstd1 && \
for deb in *.deb; do \
dpkg -x "$deb" /dependencies; \
done
# Final sidecar image
# Using distroless base for minimal attack surface (no shell, no package manager)
FROM gcr.io/distroless/python3-debian13:nonroot
ENV SUMMARY="CloudNativePG Barman plugin" \
DESCRIPTION="Container image that provides the barman-cloud sidecar" \
PATH="/venv/bin:$PATH"
LABEL summary="$SUMMARY" \
description="$DESCRIPTION" \
io.k8s.display-name="$SUMMARY" \
io.k8s.description="$DESCRIPTION" \
name="CloudNativePG Barman plugin sidecar" \
vendor="CloudNativePG Contributors" \
url="https://cloudnative-pg.io/" \
version="" \
release="1"
# Copy virtualenv with pre-compiled bytecode
COPY --from=pythonbuilder /venv /venv
# Copy runtime libraries from extracted packages
# All libraries are in /usr/lib/x86_64-linux-gnu
COPY --from=pythonbuilder /dependencies/usr/lib /usr/lib
# Copy Go manager binary
COPY --from=gobuilder /workspace/manager /manager
USER 26:26
ENTRYPOINT ["/manager"]