From 6423da8dcd076433b2629cfababa0fde9965b389 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 2 Mar 2021 23:03:02 -0800 Subject: [PATCH] dockerfile based binary building Using cross compilation toolchains that work from any platform Adds darwin/arm64 support and bake targets. Static and dynamic binary targets are available, both with glibc and musl. Signed-off-by: Tonis Tiigi --- .dockerignore | 1 - Dockerfile | 55 ++++++++++++++++++++++++++++++++++ docker-bake.hcl | 45 ++++++++++++++++++++++++++++ scripts/build/.variables | 14 +++++---- scripts/build/binary | 64 +++++++++++++++++++++++++++++++++++----- scripts/build/cross | 33 --------------------- scripts/build/dynbinary | 24 --------------- scripts/build/osx | 22 -------------- 8 files changed, 165 insertions(+), 93 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-bake.hcl delete mode 100755 scripts/build/cross delete mode 100755 scripts/build/dynbinary delete mode 100755 scripts/build/osx diff --git a/.dockerignore b/.dockerignore index 80d9bd96dd..1718dd67c2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ .circleci .dockerignore -.git .github .gitignore appveyor.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..3dfb8f7e3f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +#syntax=docker/dockerfile:1.2 + +ARG BASE_VARIANT=alpine +ARG GO_VERSION=1.13.15 + +FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-${BASE_VARIANT} AS gostable +FROM --platform=$BUILDPLATFORM golang:1.16-${BASE_VARIANT} AS golatest + +FROM gostable AS go-linux +FROM gostable AS go-windows +FROM golatest AS go-darwin + +FROM --platform=$BUILDPLATFORM tonistiigi/xx@sha256:810dc54d5144f133a218e88e319184bf8b9ce01d37d46ddb37573e90decd9eef AS xx + +FROM go-${TARGETOS} AS build-base-alpine +COPY --from=xx / / +RUN apk add --no-cache clang lld file +WORKDIR /go/src/github.com/docker/cli + +FROM build-base-alpine AS build-alpine +ARG TARGETPLATFORM +# gcc is installed for libgcc only +RUN xx-apk add --no-cache musl-dev gcc + +FROM go-${TARGETOS} AS build-base-buster +COPY --from=xx / / +RUN apt-get update && apt-get install --no-install-recommends -y clang lld file +WORKDIR /go/src/github.com/docker/cli + +FROM build-base-buster AS build-buster +ARG TARGETPLATFORM +RUN xx-apt install --no-install-recommends -y libc6-dev libgcc-8-dev + +FROM build-${BASE_VARIANT} AS build +# GO_LINKMODE defines if static or dynamic binary should be produced +ARG GO_LINKMODE=static +# GO_BUILDTAGS defines additional build tags +ARG GO_BUILDTAGS +# GO_STRIP strips debugging symbols if set +ARG GO_STRIP +# CGO_ENABLED manually sets if cgo is used +ARG CGO_ENABLED +# VERSION sets the version for the produced binary +ARG VERSION +RUN --mount=ro --mount=type=cache,target=/root/.cache \ + --mount=from=dockercore/golang-cross:xx-sdk-extras,target=/xx-sdk,src=/xx-sdk \ + xx-go --wrap && \ + # export GOCACHE=$(go env GOCACHE)/$(xx-info)$([ -f /etc/alpine-release ] && echo "alpine") && \ + TARGET=/out ./scripts/build/binary && \ + xx-verify $([ "$GO_LINKMODE" = "static" ] && echo "--static") /out/docker + +FROM build-base-${BASE_VARIANT} AS dev + +FROM scratch AS binary +COPY --from=build /out . diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000000..0fb3fe2bec --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,45 @@ +variable "VERSION" { + default = "" +} + +variable "USE_GLIBC" { + default = "" +} + +variable "STRIP_TARGET" { + default = "" +} + +group "default" { + targets = ["binary"] +} + +target "binary" { + target = "binary" + platforms = ["local"] + output = ["build"] + args = { + BASE_VARIANT = USE_GLIBC != "" ? "buster" : "alpine" + VERSION = VERSION + GO_STRIP = STRIP_TARGET + } +} + +target "dynbinary" { + inherits = ["binary"] + args = { + GO_LINKMODE = "dynamic" + } +} + +target "_all_platforms" { + platforms = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64", "windows/arm", "windows/386"] +} + +target "cross" { + inherits = ["binary", "_all_platforms"] +} + +target "dynbinary-cross" { + inherits = ["dynbinary", "_all_platforms"] +} diff --git a/scripts/build/.variables b/scripts/build/.variables index 094209cd50..ea0e952d29 100755 --- a/scripts/build/.variables +++ b/scripts/build/.variables @@ -1,6 +1,8 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh set -eu +TARGET=${TARGET:-"build"} + PLATFORM=${PLATFORM:-} VERSION=${VERSION:-"unknown-version"} GITCOMMIT=${GITCOMMIT:-$(git rev-parse --short HEAD 2> /dev/null || true)} @@ -20,15 +22,15 @@ export LDFLAGS="\ ${LDFLAGS:-} \ " -GOOS="${GOOS:-$(go env GOHOSTOS)}" -GOARCH="${GOARCH:-$(go env GOHOSTARCH)}" +GOOS="$(go env GOOS)" +GOARCH="$(go env GOARCH)" if [ "${GOARCH}" = "arm" ]; then - GOARM="${GOARM:-$(go env GOHOSTARM)}" + GOARM="$(go env GOARM)" fi -TARGET="build/docker-$GOOS-$GOARCH" +TARGET="$TARGET/docker-${GOOS}-${GOARCH}" if [ "${GOARCH}" = "arm" ] && [ -n "${GOARM}" ]; then - TARGET="${TARGET}-v${GOARM}" + TARGET="${TARGET}-v${GOARM}" fi if [ "${GOOS}" = "windows" ]; then diff --git a/scripts/build/binary b/scripts/build/binary index 41c4196cc8..d03262b2a8 100755 --- a/scripts/build/binary +++ b/scripts/build/binary @@ -1,14 +1,64 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # # Build a static binary for the host OS/ARCH # -set -eu -o pipefail +set -eu -source ./scripts/build/.variables +: "${CGO_ENABLED=}" +: "${GO_LINKMODE=static}" +: "${GO_BUILDMODE=}" +: "${GO_BUILDTAGS=}" +: "${GO_STRIP=}" -echo "Building statically linked $TARGET" -export CGO_ENABLED=0 -go build -o "${TARGET}" --ldflags "${LDFLAGS}" "${SOURCE}" +set -x +. ./scripts/build/.variables -ln -sf "$(basename "${TARGET}")" build/docker +if [ -z "$CGO_ENABLED" ]; then + case "$(go env GOOS)" in + linux) + case "$(go env GOARCH)" in + amd64|arm64|arm|s390x) + CGO_ENABLED=1 + ;; + *) + CGO_ENABLED=0 + ;; + esac + ;; + darwin|windows) + CGO_ENABLED=1 + ;; + *) + CGO_ENABLED=0 + ;; + esac +fi +export CGO_ENABLED +if [ "$CGO_ENABLED" = "1" ] && [ "$(go env GOOS)" != "windows" ]; then + case "$(go env GOARCH)" in + mips*|ppc64) + # pie build mode is not supported on mips architectures + ;; + *) + GO_BUILDMODE="-buildmode=pie" + ;; + esac + GO_BUILDTAGS="$GO_BUILDTAGS pkcs11" +fi + +if [ "$CGO_ENABLED" = "1" ] && [ "$GO_LINKMODE" = "static" ] && [ "$(go env GOOS)" = "linux" ]; then + LDFLAGS="$LDFLAGS -extldflags -static" +fi + +if [ -n "$GO_STRIP" ]; then + LDFLAGS="$LDFLAGS -s -w" +fi + +echo "Building $GO_LINKMODE $(basename "${TARGET}")" + +export GO111MODULE=auto + +go build -o "${TARGET}" -tags "${GO_BUILDTAGS}" --ldflags "${LDFLAGS}" ${GO_BUILDMODE} "${SOURCE}" + +ln -sf "$(basename "${TARGET}")" "$(dirname "${TARGET}")/docker" diff --git a/scripts/build/cross b/scripts/build/cross deleted file mode 100755 index 51c22c3607..0000000000 --- a/scripts/build/cross +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# -# Build a binary for all supported platforms -# - -set -eu -o pipefail - -BUILDDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export SHELL=bash - -jobs=( - "$BUILDDIR/windows" \ - "$BUILDDIR/osx" \ - "GOOS=linux GOARCH=amd64 $BUILDDIR/binary" \ - "GOOS=linux GOARCH=arm $BUILDDIR/binary" \ - "GOOS=linux GOARCH=ppc64le $BUILDDIR/binary" \ - "GOOS=linux GOARCH=s390x $BUILDDIR/binary" \ -) - -# Outside of circleCI run all at once. On circleCI run two at a time because -# each container has access to two cores. -group=${CROSS_GROUP-"all"} - -if [ "$group" = "all" ]; then - - echo "Building binaries for all platforms" - parallel ::: "${jobs[@]}" - exit 0 - -fi - -declare -i start="$group*2" -parallel ::: "${jobs[@]:$start:2}" diff --git a/scripts/build/dynbinary b/scripts/build/dynbinary deleted file mode 100755 index 67bc785dae..0000000000 --- a/scripts/build/dynbinary +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# -# Build a dynamically linked binary for the host OS/ARCH -# - -set -eu -o pipefail - -source ./scripts/build/.variables - -echo "Building dynamically linked $TARGET" -export CGO_ENABLED=1 -case "$(go env GOARCH)" in - mips*|ppc64) - # pie build mode is not supported on mips architectures - GO_BUILDMODE="" - ;; - *) - GO_BUILDMODE="-buildmode=pie" - ;; -esac - -go build -o "${TARGET}" -tags pkcs11 --ldflags "${LDFLAGS}" ${GO_BUILDMODE} "${SOURCE}" - -ln -sf "$(basename "${TARGET}")" build/docker diff --git a/scripts/build/osx b/scripts/build/osx deleted file mode 100755 index a075ede412..0000000000 --- a/scripts/build/osx +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# -# Build an osx binary from linux -# - -set -eu -o pipefail - -source ./scripts/build/.variables - -export CGO_ENABLED=1 -export GOOS=darwin -export GOARCH=amd64 -export CC=o64-clang -export CXX=o64-clang++ -export LDFLAGS="$LDFLAGS -linkmode external -s" -export LDFLAGS_STATIC_DOCKER='-extld='${CC} - -# Override TARGET -TARGET="build/docker-$GOOS-$GOARCH" - -echo "Building $TARGET" -go build -o "${TARGET}" -tags pkcs11 --ldflags "${LDFLAGS}" "${SOURCE}"