docker: Parellize CLI builds (#6708)

We currently build all of our CLI binaries serially, but if we have a
docker stage for each platform, we can parellize builds for each
platform, reducing build times significantly.

This change renames `cli/Dockerfile-bin` to `cli/Dockerfile` (so
that we get syntax highlighting in editors, etc) and restructures the
Dockerfile to have a docker stage for each platform. Then, there are
two final stages: 'basic' and 'multi-arch'. The `bin/docker-build-cli-bin`
utility typically only builds the `basic` target; when
`DOCKER_MULTIARCH` is set, it also builds the target that includes
arm binaries.
This commit is contained in:
Oliver Gould 2021-08-19 16:27:56 -07:00 committed by GitHub
parent 9da7226fdf
commit 35a9e8b4fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 69 deletions

View File

@ -15,15 +15,17 @@ rootdir=$( cd "$bindir"/.. && pwd )
# shellcheck source=_tag.sh
. "$bindir"/_tag.sh
dockerfile=$rootdir/cli/Dockerfile
tag=$(head_root_tag)
get_multiarch_argument() {
if [ -n "$DOCKER_MULTIARCH" ]; then
echo "--build-arg BUILD_STAGE=multi-arch"
echo "--target=multi-arch"
else
echo "--target=basic"
fi
}
dockerfile=$rootdir/cli/Dockerfile-bin
tag=$(head_root_tag)
# shellcheck disable=SC2046
docker_build cli-bin "$tag" "$dockerfile" \
--build-arg LINKERD_VERSION="$tag" \

84
cli/Dockerfile Normal file
View File

@ -0,0 +1,84 @@
ARG BUILDPLATFORM=linux/amd64
# Precompile key slow-to-build dependencies
FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
WORKDIR /linkerd-build
COPY go.mod go.sum ./
COPY bin/install-deps bin/
RUN go mod download
RUN ./bin/install-deps
## compile binaries
FROM go-deps as go-gen
WORKDIR /linkerd-build
COPY cli cli
COPY charts charts
COPY jaeger jaeger
COPY multicluster multicluster
COPY viz viz
COPY controller/k8s controller/k8s
COPY controller/api controller/api
COPY controller/gen controller/gen
COPY pkg pkg
# Generate static templates
# TODO: `go generate` does not honor -mod=readonly
RUN go generate -mod=readonly ./pkg/charts/static
RUN go generate -mod=readonly ./jaeger/static
RUN go generate -mod=readonly ./multicluster/static
RUN go generate -mod=readonly ./viz/static
RUN mkdir -p /out
FROM go-gen as linux-amd64
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM go-gen as linux-arm64
RUN ./bin/install-deps arm64
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM go-gen as linux-arm
RUN ./bin/install-deps arm
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM go-gen as darwin
RUN CGO_ENABLED=0 GOOS=darwin go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=darwin go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM go-gen as darwin-arm64
RUN CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM go-gen as windows
RUN CGO_ENABLED=0 GOOS=windows go build -o /out/linkerd -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=windows go build -o /out/linkerd -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM scratch as basic
COPY LICENSE /linkerd/LICENSE
COPY --from=linux-amd64 /out/linkerd /out/linkerd-linux-amd64
COPY --from=darwin /out/linkerd /out/linkerd-darwin
COPY --from=darwin-arm64 /out/linkerd /out/linkerd-darwin-arm64
COPY --from=windows /out/linkerd /out/linkerd-windows
# `ENTRYPOINT` prevents `docker build` from otherwise failing with "Error
# response from daemon: No command specified."
ENTRYPOINT ["/out/linkerd-linux-amd64"]
FROM basic as multi-arch
COPY --from=linux-arm64 /out/linkerd /out/linkerd-linux-arm64
COPY --from=linux-arm /out/linkerd /out/linkerd-linux-arm

View File

@ -1,65 +0,0 @@
ARG BUILDPLATFORM=linux/amd64
ARG BUILD_STAGE=single-arch
# Precompile key slow-to-build dependencies
FROM --platform=$BUILDPLATFORM golang:1.16.4-alpine as go-deps
WORKDIR /linkerd-build
COPY go.mod go.sum ./
COPY bin/install-deps bin/
RUN go mod download
RUN ./bin/install-deps
## compile binaries
FROM go-deps as golang-single-arch
WORKDIR /linkerd-build
COPY cli cli
COPY charts charts
COPY jaeger jaeger
COPY multicluster multicluster
COPY viz viz
COPY controller/k8s controller/k8s
COPY controller/api controller/api
COPY controller/gen controller/gen
COPY pkg pkg
RUN mkdir -p /out
# Generate static templates
# TODO: `go generate` does not honor -mod=readonly
RUN go generate -mod=readonly ./pkg/charts/static
RUN go generate -mod=readonly ./jaeger/static
RUN go generate -mod=readonly ./multicluster/static
RUN go generate -mod=readonly ./viz/static
# Cache builds without version info
RUN CGO_ENABLED=0 GOOS=darwin go build -o /out/linkerd-darwin -tags prod -mod=readonly -ldflags "-s -w" ./cli
RUN CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o /out/linkerd-darwin-arm64 -tags prod -mod=readonly -ldflags "-s -w" ./cli
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/linkerd-linux-amd64 -tags prod -mod=readonly -ldflags "-s -w" ./cli
RUN CGO_ENABLED=0 GOOS=windows go build -o /out/linkerd-windows -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=darwin go build -o /out/linkerd-darwin -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
RUN CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o /out/linkerd-darwin-arm64 -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/linkerd-linux-amd64 -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
RUN CGO_ENABLED=0 GOOS=windows go build -o /out/linkerd-windows -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM golang-single-arch as golang-multi-arch
RUN ./bin/install-deps arm64
RUN ./bin/install-deps arm
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /out/linkerd-linux-arm64 -tags prod -mod=readonly -ldflags "-s -w" ./cli
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o /out/linkerd-linux-arm -tags prod -mod=readonly -ldflags "-s -w" ./cli
ARG LINKERD_VERSION
ENV GO_LDFLAGS="-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=${LINKERD_VERSION}"
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /out/linkerd-linux-arm64 -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o /out/linkerd-linux-arm -tags prod -mod=readonly -ldflags "${GO_LDFLAGS}" ./cli
FROM golang-${BUILD_STAGE} as golang
## export without sources & dependencies
FROM scratch
COPY LICENSE /linkerd/LICENSE
COPY --from=golang /out /out
# `ENTRYPOINT` prevents `docker build` from otherwise failing with "Error
# response from daemon: No command specified."
ENTRYPOINT ["/out/linkerd-linux-amd64"]