plugin-barman-cloud/containers/Dockerfile.sidecar
Marco Nenciarini 378c76a526
fix: resolve WAL archiving performance and memory issues (#746)
The barman-cloud plugin experienced significant performance degradation
and memory growth compared to the embedded solution. WAL archiving was
noticeably slower and memory consumption grew over time.

Root cause: The sidecar uses a read-only filesystem which prevents
Python from creating bytecode at runtime. When Python finds missing or
stale bytecode (.pyc files), it attempts to recompile on every
invocation, causing high CPU usage and memory consumption. The previous
approach pre-compiled bytecode in a separate base image, but the
bytecode was marked as stale when copied between Docker stages,
triggering runtime recompilation attempts.

This change eliminates bytecode staleness by ensuring all Python
bytecode is properly compiled in the final image before the sidecar
starts. The image is now fully distroless and based on trixie
(previously it was distroless-based but copied unnecessary files from
the build stage), reducing size from 463MB to 270MB and package count
from 188 to 35, while maintaining zero HIGH/CRITICAL vulnerabilities.

Closes #656 
Closes #711 
Closes #735

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
2026-01-29 16:43:55 +01:00

111 lines
4.3 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 ../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 ../cmd/manager/main.go cmd/manager/main.go
COPY ../api/ api/
COPY ../internal/ internal/
# 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 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 \
python3 \
python3-venv \
python3-dev \
build-essential \
libpq-dev \
liblz4-dev \
libsnappy-dev
COPY containers/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
# 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" \
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 --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"]