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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various issues with the "make buildx" target #40089

Merged
merged 8 commits into from Oct 22, 2019

Conversation

thaJeztah
Copy link
Member

relates to #39340 (and slightly related to #40088)

See individual commit messages for a description 馃槄

@thaJeztah
Copy link
Member Author

ping @cpuguy83 ptal

@thaJeztah
Copy link
Member Author

Hm... interesting; am I dropping an env-var here, causing it to fall back to go env ?

 + make bundles/buildx
 mkdir bundles
 docker build -f ${BUILDX_DOCKERFILE:-Dockerfile.buildx} -t "moby-buildx:${BUILDX_COMMIT:-latest}" \
 	--build-arg BUILDX_COMMIT \
 	--build-arg BUILDX_REPO \
 	--build-arg GOOS=$(if [ -n "" ]; then echo ; else go env GOHOSTOS || uname | awk '{print tolower($0)}' || true; fi) \
 	--build-arg GOARCH=$(if [ -n "" ]; then echo ; else go env GOHOSTARCH || true; fi) \
 	. && \
 	id=$(docker create moby-buildx:${BUILDX_COMMIT:-latest}); \
 	if [ -n "${id}" ]; then docker cp ${id}:/usr/bin/buildx bundles/buildx && touch bundles/buildx; docker rm -f ${id}; fi \
 && bundles/buildx version
 /bin/sh: 4: go: not found
 /bin/sh: 5: go: not found

Makefile Show resolved Hide resolved
Makefile Outdated
@@ -35,6 +35,49 @@ export VALIDATE_REPO
export VALIDATE_BRANCH
export VALIDATE_ORIGIN_BRANCH

ifneq "$(strip $(shell command -v go 2>/dev/null))" ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all seems a bit overkill.
What are we trying to solve here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpuguy83 I ran into this problem;

 /bin/sh: 4: go: not found
 /bin/sh: 5: go: not found

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely because the GOOS and GOARCH make variables were not set

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but doesn't what we already have solve that? And in the case no go the user just needs to set GOOS and GOARCH themselves.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I just discovered what the actual problem was; we were now actually using buildx v0.3.0, so it tried to pull an image that doesn't exist for s390x/power. The go not found was (I think) just the output leaking from the go env GOHOSTOS || uname line; I'll remove that one commit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, actually.. (sleepy head); it's because s390x/power are now using buildkit to build the image 馃

@thaJeztah
Copy link
Member Author

thaJeztah commented Oct 14, 2019

Yo, Jenkins, where did you go?

edit: aaaaaaand he's back


FROM golang:${GO_VERSION}-stretch
COPY --from=build /usr/bin/buildx /usr/bin/buildx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! 馃挕 I know why it failed in this branch; before this, there was no COPY in the Dockerfile, and because the COPY was added, it started downloading the docker.io/tonistiigi/copy:v0.1.3 image. Apparently, that one is only available for amd64 ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup; that one is only amd64, and armv7

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning for doing this second image?
This only produces a runnable image if the specified GOOS/GOARCH == the daemon's GOOS/GOARCH

In effect this is creating a 2nd image and taking even more space since buildx is duplicated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first stage won't be tagged, so can be garbage collected, and only the second one is preserved; the final image is roughly 870MB whereas without that stage, we're tagging an image that's 1.71GB; see the commit message 39f1a4a

@thaJeztah
Copy link
Member Author

OK, this builds now, but I'll amend one commit message, and re-order commits (enabling BUILDX before the commit that adds the COPY)

RUN GOOS="${GOOS}" GOARCH="${GOARCH}" BUILDX_COMMIT="${BUILDX_COMMIT}" \
&& export version="$(git describe --tags)" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should not be && in here as what is before (var assignments) is not a command.

RUN GOOS="${GOOS}" GOARCH="${GOARCH}" BUILDX_COMMIT="${BUILDX_COMMIT}" \
&& export version="$(git describe --tags)" \
&& export commit="$(git rev-parse --short HEAD)" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 export allows for multiple var assignments
2 you don't need to export any variables as you're using them only here ("export" means make them available for child processes, and I don't see how it's necessary here)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see why you're using export... so you would use the vars later. Well, I still don't like the way it looks :(

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try again; I think I tried without export, and for some reason, things failed.

Makefile Show resolved Hide resolved
Makefile Outdated
--build-arg BUILDX_COMMIT \
--build-arg BUILDX_REPO \
--build-arg GOOS=$$(if [ -n "$(GOOS)" ]; then echo $(GOOS); else go env GOHOSTOS || uname | awk '{print tolower($$0)}' || true; fi) \
--build-arg GOARCH=$$(if [ -n "$(GOARCH)" ]; then echo $(GOARCH); else go env GOHOSTARCH || true; fi) \
. && \
id=$$(docker create moby-buildx:$(BUILDX_COMMIT)); \
if [ -n "$${id}" ]; then docker cp $${id}:/usr/bin/buildx $@ && touch $@; docker rm -f $${id}; fi
id=$$(docker create moby-buildx:$${BUILDX_COMMIT:-latest}); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so using && from makefile is redundant. If any command fails, make stops right there. I guess this practice comes from Dockerfile RUN use, but makefile is different and if we can make things simpler, let's do it.

In other words,

	docker build ....
	id=$$(docker ...); if [ -n "$${id}" ]; ....
	$@ version

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I rewrote it a bit; also put the if over a couple of lines, but let me know if that's too verbose.

buildx: bundles/buildx # build buildx cli tool
else
buildx:
buildx: bundles/buildx ## build buildx cli tool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #40091 buildx is a required pre-req for all builds.
What happens if we don't define buildx:?

Copy link
Member Author

@thaJeztah thaJeztah Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be covered by the .PHONY buildx

mkdir foo && cd foo

echo ".PHONY: buildx" > Makefile

make buildx
# make: Nothing to be done for `buildx'.

echo $?
# 0

make nonexistingtarget
# make: *** No rule to make target `nonexistingtarget'.  Stop.

echo $?
# 2

-X \"github.com/docker/buildx/version.Revision=$(git rev-parse --short HEAD)\" \
-X \"github.com/docker/buildx/version.Package=github.com/docker/buildx\"" \
&& go build -ldflags "${ldflags}" -o /usr/bin/buildx ./cmd/buildx
Copy link
Contributor

@kolyshkin kolyshkin Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& looks artificial here as we don't have any command to succeed before it.

I also see a repetition of github.com/docker/buildx string; why don't we do this

  pkg="github.com/docker/buildx"; \
  ldflags=" \
    -X \"${pkg}/version.Version=$(git describe --tags)\" \
    -X \"${pkg}/version.Revision=$(git rev-parse --short HEAD)\" \
    -X \"${pkg}/version.Package=${pkg}\" \
  "; \
  go build -ldflags "${ldflags}" -o /usr/bin/buildx ./cmd/buildx

I checked it works in both bash and dash, and even passes shellcheck

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& looks artificial here as we don't have any command to succeed before it.

arf. that's me messing up rebasing

I also see a repetition of github.com/docker/buildx string; why don't we do this

馃憤 yup, I like that

@thaJeztah
Copy link
Member Author

Updated with the suggested changes

Copy link
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Dockerfile.buildx Outdated Show resolved Hide resolved
Makefile Outdated Show resolved Hide resolved
@thaJeztah
Copy link
Member Author

@kolyshkin updated 馃憤

-X \"${pkg}/version.Version=$(git describe --tags)\" \
-X \"${pkg}/version.Revision=$(git rev-parse --short HEAD)\" \
-X \"${pkg}/version.Package=buildx\" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. shouldn't it be -X \"${pkg}/version.Package=${pkg}\" \?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #40089 (comment)

This way, it looks like

buildx version
buildx v0.3.0 c967f1d

instead of

buildx version
github.com/docker/buildx v0.3.0 c967f1d

Commit 1be2cc2 updated the
Makefile to force the use of BuildKit, if `USE_BUILDX` was
not set.

As a side-effect, Jenkins now started using BuildKit on
s390x and ppc64le as well, because it overwrote the
`DOCKER_BUILDKIT=0` that was set.

This commit forces the use of buildx on s390x and ppc64le.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The variables were not substituted, because single-quotes were used.
While at it; change the fixed version/commit to use the actual commit
and version, using git.

before this change:

    make buildx && ./bundles/buildx version
    github.com/docker/buildx ${BUILDX_COMMIT} ${BUILDX_COMMIT}

after this change:

    make buildx && ./bundles/buildx version
    buildx v0.3.0 c967f1d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The `BUILDX_COMMIT` variable was set as a Make variable,
which isn't exported, and thus not available in scripts,
unless referenced through `$(VAR)` (non-curly-brackets).
As a result `--build-arg BUILDX_COMMIT` did not set the
`BUILDX_COMMIT` build-arg, and the default from the Dockerfile
(`master`) was used instead.

This patch exports the default version that's set in the
Makefile, so that it can be used as a regular environment
variable. The script was also slighly modified to no longer
use the `Make` variable.

In addition, the `buildx` target now calls `buildx version`,
which is useful to confirm if the binary was successfully built
(and with the correct version).

Before:

    rm -f bundles/buildx && make buildx && ./bundles/buildx version
    # => => naming to docker.io/library/moby-buildx:v0.3.0
    github.com/docker/buildx v0.3.1 6db68d0

    # using a make variable:
    rm -f bundles/buildx && make BUILDX_COMMIT=v0.2.1 buildx && ./bundles/buildx version
    # => => naming to docker.io/library/moby-buildx:v0.2.1
    github.com/docker/buildx v0.3.1 6db68d0

    # using an environment variable:
    rm -f bundles/buildx && BUILDX_COMMIT=v0.2.2 make buildx && ./bundles/buildx version
    # => => naming to docker.io/library/moby-buildx:v0.2.2
    github.com/docker/buildx v0.3.1 6db68d0

After:

    # default
    rm -f bundles/buildx && make buildx
    # => => naming to docker.io/library/moby-buildx:v0.3.0
    github.com/docker/buildx v0.3.0 c967f1d

    # using a make variable:
    rm -f bundles/buildx && make BUILDX_COMMIT=v0.2.1 buildx
    # => => naming to docker.io/library/moby-buildx:v0.2.1
    github.com/docker/buildx v0.2.1 0eb2df5

    # using an environment variable:
    rm -f bundles/buildx && BUILDX_COMMIT=v0.2.2 make buildx
    # => => naming to docker.io/library/moby-buildx:v0.2.2
    github.com/docker/buildx v0.2.2 ab5fe3d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This patch removes the `BUILDX_COMMIT` make variable. With the
make variable removed, it no longer "masks" environment variables,
and there is no longer a need to export the variable.

A side effect of this change, is that (by default), the buildx
image is tagged as `moby-buildx:latest`. This likely isn't a
problem, because the build-cache would still be preserved in
intermediate images. Having the image tagged as `:latest` also
makes cleaning up easier (without having to remove the image
for each version tagged.

Otherwise, the behavior remains the same as before:

    # default
    rm -f bundles/buildx && make buildx
    # => => naming to docker.io/library/moby-buildx:latest
    github.com/docker/buildx v0.3.0 c967f1d

    # using a make variable:
    rm -f bundles/buildx && make BUILDX_COMMIT=v0.2.1 buildx
    # => => naming to docker.io/library/moby-buildx:v0.2.1
    github.com/docker/buildx v0.2.1 0eb2df5

    # using an environment variable:
    rm -f bundles/buildx && BUILDX_COMMIT=v0.2.2 make buildx
    # => => naming to docker.io/library/moby-buildx:v0.2.2
    github.com/docker/buildx v0.2.2 ab5fe3d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This simplifies the makefile a bit, while preserving
the functionality. Using a non-existing Dockerfile
to demonstrate:

    make buildx
    Successfully tagged moby-buildx:latest
    92059305df7371f8b5b3638d4d405d49ff909031a7bc6d2f515cb0a0df03c2f4
    github.com/docker/buildx v0.3.0 c967f1d

    make BUILDX_DOCKERFILE=foo buildx
    BUILDX_DOCKERFILE=foo buildx
    unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /Users/sebastiaan/go/src/github.com/docker/docker/foo: no such file or directory

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Un-indent the comment, so that it doesn't get printed by
the shell script (moved it above the target, as it looked
slightly less cluttered)

Also fixed the "help" comment, so that it shows up in
`make help`, and removed the un-needed dummy `buildx:` target.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The build-stage would still be in the local cache (and can
be cleaned up with `docker system prune`) but the tagged
image (which usually wouldn't be removed) will take up
less space now.

Note that

 - the binary is not statically linked, so we cannot use
   a "from scratch" image
 - in cases where the binary is cross-compiled (e.g.
   on a non-linux machine), the image itself is not
   really useful (we may want to consider not tagging
   the image in that situation)

Before:

    REPOSITORY      TAG     IMAGE ID      CREATED         SIZE
    moby-buildx     latest  c9b2af465baf  7 minutes ago   1.71GB

After:

    REPOSITORY      TAG     IMAGE ID      CREATED         SIZE
    moby-buildx     latest  345501e2df0a  2 minutes ago   820MB

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
@thaJeztah
Copy link
Member Author

rebased to kick CI (master was broken because of a linting issue)

Copy link
Contributor

@kolyshkin kolyshkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thaJeztah
Copy link
Member Author

argh; failing on a flaky test;

 === Failed
[2019-10-21T23:02:53.486Z] === FAIL: amd64.integration-cli TestDockerSwarmSuite/TestAPISwarmNodeDrainPause (72.72s)
[2019-10-21T23:02:53.486Z]     --- FAIL: TestDockerSwarmSuite/TestAPISwarmNodeDrainPause (72.72s)
[2019-10-21T23:02:53.486Z]         daemon.go:26: Creating a new daemon at: "/go/src/github.com/docker/docker/bundles/test-integration/TestDockerSwarmSuite/TestAPISwarmNodeDrainPause"
[2019-10-21T23:02:53.486Z]         daemon.go:26: Creating a new daemon at: "/go/src/github.com/docker/docker/bundles/test-integration/TestDockerSwarmSuite/TestAPISwarmNodeDrainPause"
[2019-10-21T23:02:53.486Z]         check_test.go:358: [d48494135b48e] joining swarm manager [d1822cb98a9bc]@0.0.0.0:2477, swarm listen addr 0.0.0.0:2478
[2019-10-21T23:02:53.486Z]         docker_api_swarm_node_test.go:106: timeout hit after 1m0s: output: "b99585122cdb\ncdbb41970aad\n"
[2019-10-21T23:02:53.486Z]         daemon.go:83: assertion failed: error is not nil: exit status 1

@thaJeztah thaJeztah merged commit 684d0ba into moby:master Oct 22, 2019
@thaJeztah thaJeztah deleted the fix_buildx_target branch October 22, 2019 00:07
@thaJeztah thaJeztah added this to the 20.03.0 milestone Apr 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants