Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Statically build using musl toolchain and target alpine #558

Merged
merged 1 commit into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 34 additions & 63 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,55 +1,15 @@
ARG BASE_VARIANT=bullseye
ARG BASE_VARIANT=alpine
ARG GO_VERSION=1.17
ARG XX_VERSION=1.1.0

ARG LIBGIT2_IMG=ghcr.io/fluxcd/golang-with-libgit2
ARG LIBGIT2_TAG=libgit2-1.1.1-3
ARG LIBGIT2_TAG=libgit2-1.1.1-4

FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM ${LIBGIT2_IMG}:${LIBGIT2_TAG} as libgit2
FROM --platform=linux/amd64 ${LIBGIT2_IMG}:${LIBGIT2_TAG} as build-amd64
FROM --platform=linux/arm64 ${LIBGIT2_IMG}:${LIBGIT2_TAG} as build-arm64
FROM --platform=linux/arm/v7 ${LIBGIT2_IMG}:${LIBGIT2_TAG} as build-armv7

FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-${BASE_VARIANT} as gostable

FROM gostable AS go-linux

FROM go-${TARGETOS} AS build-base-bullseye

# Copy the build utilities
COPY --from=xx / /

# Align golang base image with bookworm.
# TODO: Replace this with a golang bookworm variant, once that is released.
RUN echo "deb http://deb.debian.org/debian bookworm main" > /etc/apt/sources.list.d/bookworm.list \
&& echo "deb-src http://deb.debian.org/debian bookworm main" /etc/apt/sources.list.d/bookworm.list \
&& xx-apt update \
&& xx-apt -t bookworm upgrade -y \
&& xx-apt -t bookworm install -y curl

COPY --from=libgit2 /Makefile /libgit2/

# Install the libgit2 build dependencies
RUN make -C /libgit2 cmake

ARG TARGETPLATFORM
RUN make -C /libgit2 dependencies

FROM build-base-${BASE_VARIANT} as libgit2-bullseye

ARG TARGETPLATFORM

# First build libgit2 statically, this ensures that all its dependencies
# will be statically available as well.
ARG BUILD_SHARED_LIBS=OFF
RUN FLAGS=$(xx-clang --print-cmake-defines) make -C /libgit2 libgit2

# Rebuild libgit2 this time to generate the shared libraries.
ARG BUILD_SHARED_LIBS=ON
RUN FLAGS=$(xx-clang --print-cmake-defines) make -C /libgit2 libgit2
# Logs glibc version used at built time. The final image must be compatible with it.
RUN ldd --version ldd > /libgit2/built-on-glibc-version


FROM libgit2-${BASE_VARIANT} as build
FROM --platform=$BUILDPLATFORM build-$TARGETARCH$TARGETVARIANT AS build

# Configure workspace
WORKDIR /workspace
Expand All @@ -64,35 +24,46 @@ COPY go.sum go.sum
# Cache modules
RUN go mod download

# Copy source code
COPY main.go main.go
COPY controllers/ controllers/
COPY pkg/ pkg/
COPY internal/ internal/
RUN apk add clang lld pkgconfig ca-certificates

# Build the binary
ENV CGO_ENABLED=1
ARG TARGETPLATFORM

# The dependencies being statically built are: libgit2, libssh2, libssl, libcrypto and libz.
# Others (such as libc, librt, libdl and libpthread) are resolved at run-time.
# To decrease the likelihood of such dependencies being out of sync, the base build image
# should be aligned with the target (i.e. same debian variant).
RUN FLAGS=$(pkg-config --static --libs --cflags libssh2 libgit2 libssl libcrypto zlib openssl) \
RUN xx-apk add --no-cache \
musl-dev gcc lld binutils-gold

# Performance related changes:
# - Use read-only bind instead of copying go source files.
# - Cache go packages.
RUN --mount=target=. \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
export LIBRARY_PATH="/usr/local/$(xx-info triple)/lib:/usr/local/$(xx-info triple)/lib64:${LIBRARY_PATH}" && \
export PKG_CONFIG_PATH="/usr/local/$(xx-info triple)/lib/pkgconfig:/usr/local/$(xx-info triple)/lib64/pkgconfig" && \
export FLAGS="$(pkg-config --static --libs --cflags libssh2 openssl libgit2)" && \
CGO_LDFLAGS="${FLAGS} -static" \
xx-go build \
-ldflags "-s -w -extldflags \"/usr/lib/$(xx-info triple)/libssh2.a /usr/lib/$(xx-info triple)/libssl.a /usr/lib/$(xx-info triple)/libcrypto.a /usr/lib/$(xx-info triple)/libz.a -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-allow-shlib-undefined ${FLAGS} -static\"" \
-ldflags "-s -w" \
-tags 'netgo,osusergo,static_build' \
-o source-controller -trimpath main.go;
-o /source-controller -trimpath main.go;

# Ensure that the binary was cross-compiled correctly to the target platform.
RUN xx-verify --static /source-controller

# The target image must aligned with apt sources used for libgit2.
FROM debian:bookworm-slim as controller

FROM alpine

stefanprodan marked this conversation as resolved.
Show resolved Hide resolved
ARG TARGETPLATFORM
RUN apt update && apt install -y ca-certificates
RUN apk --no-cache add ca-certificates \
&& update-ca-certificates

# Create minimal nsswitch.conf file to prioritize the usage of /etc/hosts over DNS queries.
# https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-354316460
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf

# Copy over binary from build
COPY --from=build /workspace/source-controller /usr/local/bin/
COPY --from=libgit2-bullseye /libgit2/built-on-glibc-version /
COPY --from=build /source-controller /usr/local/bin/
COPY ATTRIBUTIONS.md /

USER 65534:65534
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ TAG ?= latest

# Base image used to build the Go binary
LIBGIT2_IMG ?= ghcr.io/fluxcd/golang-with-libgit2
LIBGIT2_TAG ?= libgit2-1.1.1-3
LIBGIT2_TAG ?= libgit2-1.1.1-4

# Allows for defining additional Docker buildx arguments,
# e.g. '--push'.
Expand Down