1. buildx
buildx is a plugin for docker. The docker buildx subcommand executes the buildx binary. This article analyzes how to compile buildx yourself.
2. Standard Build
The official documentation provides the standard build method: https://github.com/docker/buildx#building
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# Buildx 0.6+
$ docker buildx bake "https://github.com/docker/buildx.git"
$ mkdir -p ~/.docker/cli-plugins
$ mv ./bin/build/buildx ~/.docker/cli-plugins/docker-buildx
# Docker 19.03+
$ DOCKER_BUILDKIT=1 docker build --platform=local -o . "https://github.com/docker/buildx.git"
$ mkdir -p ~/.docker/cli-plugins
$ mv buildx ~/.docker/cli-plugins/docker-buildx
# Local
$ git clone https://github.com/docker/buildx.git && cd buildx
$ make install
|
3. Compilation flow analysis
The following is an analysis of the compilation process using the make binaries
command as an entry point.
Execute docker buildx bake binaries to compile.
https://github.com/docker/buildx/blob/v0.10.2/Makefile#L22-L24
1
2
3
4
5
6
7
|
...
export BUILDX_CMD ?= docker buildx
...
.PHONY: binaries
binaries:
$(BUILDX_CMD) bake binaries
...
|
The configuration of bake is as follows, setting the target to the binaries stage and outputting the compiled file to the ./bin/build
directory.
https://github.com/docker/buildx/blob/v0.10.2/docker-bake.hcl#L101-L106
1
2
3
4
5
6
7
8
9
10
11
12
|
...
variable "DESTDIR" {
default = "./bin"
}
...
target "binaries" {
inherits = ["_common"]
target = "binaries"
output = ["${DESTDIR}/build"]
platforms = ["local"]
}
...
|
Call hack/build
compilation in the buildx-build phase.
https://github.com/docker/buildx/blob/v0.10.2/Dockerfile#L60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# syntax=docker/dockerfile-upstream:1.5.0
ARG GO_VERSION=1.19
ARG XX_VERSION=1.1.2
ARG DOCKERD_VERSION=20.10.14
FROM docker:$DOCKERD_VERSION AS dockerd-release
# xx is a helper for cross-compilation
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS golatest
FROM golatest AS gobase
COPY --from=xx / /
RUN apk add --no-cache file git
ENV GOFLAGS=-mod=vendor
ENV CGO_ENABLED=0
WORKDIR /src
FROM gobase AS buildx-version
RUN --mount=type=bind,target=. <<EOT
set -e
mkdir /buildx-version
echo -n "$(./hack/git-meta version)" | tee /buildx-version/version
echo -n "$(./hack/git-meta revision)" | tee /buildx-version/revision
EOT
FROM gobase AS buildx-build
ARG TARGETPLATFORM
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=bind,from=buildx-version,source=/buildx-version,target=/buildx-version <<EOT
set -e
xx-go --wrap
DESTDIR=/usr/bin VERSION=$(cat /buildx-version/version) REVISION=$(cat /buildx-version/revision) GO_EXTRA_LDFLAGS="-s -w" ./hack/build
xx-verify --static /usr/bin/docker-buildx
EOT
...
FROM scratch AS binaries-unix
COPY --link --from=buildx-build /usr/bin/docker-buildx /buildx
...
FROM binaries-unix AS binaries-linux
...
FROM binaries-$TARGETOS AS binaries
# enable scanning for this stage
ARG BUILDKIT_SBOM_SCAN_STAGE=true
...
|
hack/build calls go build
.
https://github.com/docker/buildx/blob/v0.10.2/hack/build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#!/usr/bin/env sh
set -e
: "${DESTDIR=./bin/build}"
: "${PACKAGE=github.com/docker/buildx}"
: "${VERSION=$(./hack/git-meta version)}"
: "${REVISION=$(./hack/git-meta revision)}"
: "${CGO_ENABLED=0}"
: "${GO_PKG=github.com/docker/buildx}"
: "${GO_LDFLAGS=-X ${GO_PKG}/version.Version=${VERSION} -X ${GO_PKG}/version.Revision=${REVISION} -X ${GO_PKG}/version.Package=${PACKAGE}}"
: "${GO_EXTRA_LDFLAGS=}"
set -x
CGO_ENABLED=$CGO_ENABLED go build -mod vendor -trimpath -ldflags "${GO_LDFLAGS} ${GO_EXTRA_LDFLAGS}" -o "${DESTDIR}/docker-buildx" ./cmd/buildx
|
4. Custom
The final build command is located in the hack/build
file.
https://github.com/docker/buildx/blob/v0.10.2/hack/build#L16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#!/usr/bin/env sh
set -e
: "${DESTDIR=./bin/build}"
: "${PACKAGE=github.com/docker/buildx}"
: "${VERSION=$(./hack/git-meta version)}"
: "${REVISION=$(./hack/git-meta revision)}"
: "${CGO_ENABLED=0}"
: "${GO_PKG=github.com/docker/buildx}"
: "${GO_LDFLAGS=-X ${GO_PKG}/version.Version=${VERSION} -X ${GO_PKG}/version.Revision=${REVISION} -X ${GO_PKG}/version.Package=${PACKAGE}}"
: "${GO_EXTRA_LDFLAGS=}"
set -x
CGO_ENABLED=$CGO_ENABLED go build -mod vendor -trimpath -ldflags "${GO_LDFLAGS} ${GO_EXTRA_LDFLAGS}" -o "${DESTDIR}/docker-buildx" ./cmd/buildx
|
4. Disable compilation optimization and inlining
1
2
3
4
5
6
7
8
9
|
$ sed -i 's/go build/go build -gcflags="all=-N -l"/g' hack/build
$ sed -i 's/${GO_EXTRA_LDFLAGS}//g' hack/build
$ make binaries
docker buildx bake binaries
[+] Building 7.3s (21/21) FINISHED
...
=> => copying files 76.04MB
$ ls -lah bin/build/buildx
-rwxr-xr-x 1 root root 73M Feb 14 12:52 bin/build/buildx
|