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

[20.10 backport] dockerfile based binary building #3042

Merged
merged 9 commits into from
Apr 9, 2021
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
24 changes: 9 additions & 15 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
docker: [{image: 'docker:19.03-git'}]
environment:
DOCKER_BUILDKIT: 1
BUILDX_VERSION: "v0.5.1"
parallelism: 3
steps:
- checkout
Expand All @@ -55,21 +56,14 @@ jobs:
- run:
name: "Docker info"
command: docker info
- run:
name: "Cross - build image"
command: |
docker build --progress=plain -f dockerfiles/Dockerfile.cross --tag cli-builder:$CIRCLE_BUILD_NUM .
- run:
name: "Cross"
command: |
name=cross-$CIRCLE_BUILD_NUM-$CIRCLE_NODE_INDEX
docker run \
-e CROSS_GROUP=$CIRCLE_NODE_INDEX \
--name $name cli-builder:$CIRCLE_BUILD_NUM \
make cross
docker cp \
$name:/go/src/github.com/docker/cli/build \
/work/build
- run: apk add make curl
- run: mkdir -vp ~/.docker/cli-plugins/
- run: curl -fsSL --output ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-amd64
- run: chmod a+x ~/.docker/cli-plugins/docker-buildx
- run: docker buildx version
- run: docker context create buildctx
- run: docker buildx create --use buildctx && docker buildx inspect --bootstrap
- run: GROUP_INDEX=$CIRCLE_NODE_INDEX GROUP_TOTAL=$CIRCLE_NODE_TOTAL docker buildx bake cross --progress=plain
- store_artifacts:
path: /work/build

Expand Down
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.circleci
.dockerignore
.git
.github
.gitignore
appveyor.yml
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
Thumbs.db
.editorconfig
/build/
cli/winresources/rsrc_386.syso
cli/winresources/rsrc_amd64.syso
cli/winresources/rsrc_*.syso
/man/man1/
/man/man5/
/man/man8/
Expand Down
61 changes: 61 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#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 golatest AS go-darwin
FROM golatest AS go-windows-amd64
FROM golatest AS go-windows-386
FROM golatest AS go-windows-arm
FROM --platform=$BUILDPLATFORM tonistiigi/golang:497feff1-${BASE_VARIANT} AS go-windows-arm64
FROM go-windows-${TARGETARCH} AS go-windows

FROM --platform=$BUILDPLATFORM tonistiigi/xx@sha256:620d36a9d7f1e3b102a5c7e8eff12081ac363828b3a44390f24fa8da2d49383d AS xx

FROM go-${TARGETOS} AS build-base-alpine
COPY --from=xx / /
RUN apk add --no-cache clang lld llvm file git
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 \
--mount=type=tmpfs,target=cli/winresources \
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
COPY . .

FROM scratch AS binary
COPY --from=build /out .
17 changes: 4 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,28 @@ lint: ## run all the lint tools
gometalinter --config gometalinter.json ./...

.PHONY: binary
binary: ## build executable for Linux
@echo "WARNING: binary creates a Linux executable. Use cross for macOS or Windows."
binary:
./scripts/build/binary

.PHONY: plugins
plugins: ## build example CLI plugins
./scripts/build/plugins

.PHONY: cross
cross: ## build executable for macOS and Windows
./scripts/build/cross

.PHONY: binary-windows
binary-windows: ## build executable for Windows
./scripts/build/windows
cross:
./scripts/build/binary

.PHONY: plugins-windows
plugins-windows: ## build example CLI plugins for Windows
./scripts/build/plugins-windows

.PHONY: binary-osx
binary-osx: ## build executable for macOS
./scripts/build/osx

.PHONY: plugins-osx
plugins-osx: ## build example CLI plugins for macOS
./scripts/build/plugins-osx

.PHONY: dynbinary
dynbinary: ## build dynamically linked binary
./scripts/build/dynbinary
GO_LINKMODE=dynamic ./scripts/build/binary

vendor: vendor.conf ## check that vendor matches vendor.conf
rm -rf vendor
Expand Down
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,31 @@ Development

`docker/cli` is developed using Docker.

Build a linux binary:
Build CLI from source:

```
$ make -f docker.Makefile binary
$ docker buildx bake
```

Build binaries for all supported platforms:

```
$ make -f docker.Makefile cross
$ docker buildx bake cross
```

Build for a specific platform:

```
$ docker buildx bake --set binary.platform=linux/arm64
```

Build dynamic binary for glibc or musl:

```
$ USE_GLIBC=1 docker buildx bake dynbinary
```


Run all linting:

```
Expand All @@ -44,12 +57,6 @@ Start an interactive development environment:
$ make -f docker.Makefile shell
```

In the development environment you can run many tasks, including build binaries:

```
$ make binary
```

Legal
=====
*Brought to you courtesy of our legal counsel. For more context,
Expand Down
4 changes: 1 addition & 3 deletions cli/winresources/res_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ These resources are used to provide
* An icon
* A Windows manifest declaring Windows version support

The resource object files are generated with go generate.
The resource object files are generated when building with scripts/build/binary .
The resource source files are located in scripts/winresources.
This occurs automatically when you run scripts/build/windows.

Expand All @@ -14,5 +14,3 @@ is included.

*/
package winresources

//go:generate ../../scripts/gen/windows-resources
63 changes: 63 additions & 0 deletions docker-bake.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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"
}
}

variable "GROUP_TOTAL" {
default = "1"
}

variable "GROUP_INDEX" {
default = "0"
}

function "platforms" {
params = []
result = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64"]
}

function "glen" {
params = [platforms, GROUP_TOTAL]
result = ceil(length(platforms)/GROUP_TOTAL)
}

target "_all_platforms" {
platforms = slice(platforms(), GROUP_INDEX*glen(platforms(), GROUP_TOTAL),min(length(platforms()), (GROUP_INDEX+1)*glen(platforms(), GROUP_TOTAL)))
}

target "cross" {
inherits = ["binary", "_all_platforms"]
}

target "dynbinary-cross" {
inherits = ["dynbinary", "_all_platforms"]
}
20 changes: 0 additions & 20 deletions docker.Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ build_linter_image:
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
cat ./dockerfiles/Dockerfile.lint | docker build ${DOCKER_BUILD_ARGS} --build-arg=GO_VERSION -t $(LINTER_IMAGE_NAME) -

.PHONY: build_cross_image
build_cross_image:
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
cat ./dockerfiles/Dockerfile.cross | docker build ${DOCKER_BUILD_ARGS} --build-arg=GO_VERSION -t $(CROSS_IMAGE_NAME) -

.PHONY: build_shell_validate_image
build_shell_validate_image:
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
Expand Down Expand Up @@ -80,22 +75,10 @@ test-unit: build_docker_image ## run unit tests (using go test)
.PHONY: test ## run unit and e2e tests
test: test-unit test-e2e

.PHONY: cross
cross: build_cross_image ## build the CLI for macOS and Windows
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make cross

.PHONY: binary-windows
binary-windows: build_cross_image ## build the CLI for Windows
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@

.PHONY: plugins-windows
plugins-windows: build_cross_image ## build the example CLI plugins for Windows
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@

.PHONY: binary-osx
binary-osx: build_cross_image ## build the CLI for macOS
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@

.PHONY: plugins-osx
plugins-osx: build_cross_image ## build the example CLI plugins for macOS
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@
Expand All @@ -120,9 +103,6 @@ fmt: ## run gofmt
vendor: build_docker_image vendor.conf ## download dependencies (vendor/) listed in vendor.conf
$(DOCKER_RUN) -it $(DEV_DOCKER_IMAGE_NAME) make vendor

dynbinary: build_cross_image ## build the CLI dynamically linked
$(DOCKER_RUN) -it $(CROSS_IMAGE_NAME) make dynbinary

.PHONY: authors
authors: ## generate AUTHORS file from git history
$(DOCKER_RUN) -it $(DEV_DOCKER_IMAGE_NAME) make authors
Expand Down
16 changes: 9 additions & 7 deletions scripts/build/.variables
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
set -eu

TARGET=${TARGET:-"build"}

PLATFORM=${PLATFORM:-}
VERSION=${VERSION:-"unknown-version"}
VERSION=${VERSION:-$(git describe --match 'v[0-9]*' --dirty='.m' --always --tags | sed 's/^v//' 2>/dev/null || echo "unknown-version" )}
GITCOMMIT=${GITCOMMIT:-$(git rev-parse --short HEAD 2> /dev/null || true)}
BUILDTIME=${BUILDTIME:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}

Expand All @@ -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
Expand Down
Loading