We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Imagine you want to compile a Go application, but you cannot do it locally. It might be that you want to cross-compile but you need CGO. Maybe you just want to test a new version of Go for compiling before taking the jump?
In this post, we'll show a way how to do this by using a Docker container.
The first step is to build a base image to start from. This base image can contain all the packages you need in addition to Go itself. For doing so, we start from the golang:1.11-alpine3.8 base image and build upon that. If prefer the Alpine version of the golang image as that's a lot smaller than the golang:1.11 image.
The Dockerfile.base
looks as follows:
FROM golang:1.11-alpine3.8
RUN apk update && apk add gcc libc-dev make git
This uses Go 1.11 and additionally installs gcc
, the libc
headers, make
and git
. If you want to build starting from this image (to avoid that you always have to rebuild the image from scratch), you can build it using the following command:
$ docker build --rm -t custom-go1.11:latest -f Docker.base .
This will output the following:
Sending build context to Docker daemon 335.2MB
Step 1/2 : FROM golang:1.11-alpine3.8
---> 20ff4d6283c0
Step 2/2 : RUN apk update && apk add gcc libc-dev make git
---> Running in a2a95ff75ab6
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
v3.8.0-94-gdea4c10014 [http://dl-cdn.alpinelinux.org/alpine/v3.8/main]
v3.8.0-92-g87a3f3ec11 [http://dl-cdn.alpinelinux.org/alpine/v3.8/community]
OK: 9542 distinct packages available
(1/20) Installing binutils (2.30-r5)
(2/20) Installing gmp (6.1.2-r1)
(3/20) Installing isl (0.18-r0)
(4/20) Installing libgomp (6.4.0-r8)
(5/20) Installing libatomic (6.4.0-r8)
(6/20) Installing pkgconf (1.5.3-r0)
(7/20) Installing libgcc (6.4.0-r8)
(8/20) Installing mpfr3 (3.1.5-r1)
(9/20) Installing mpc1 (1.0.3-r1)
(10/20) Installing libstdc++ (6.4.0-r8)
(11/20) Installing gcc (6.4.0-r8)
(12/20) Installing nghttp2-libs (1.32.0-r0)
(13/20) Installing libssh2 (1.8.0-r3)
(14/20) Installing libcurl (7.61.0-r0)
(15/20) Installing expat (2.2.5-r0)
(16/20) Installing pcre2 (10.31-r0)
(17/20) Installing git (2.18.0-r0)
(18/20) Installing musl-dev (1.1.19-r10)
(19/20) Installing libc-dev (0.7.1-r0)
(20/20) Installing make (4.2.1-r2)
Executing busybox-1.28.4-r0.trigger
OK: 114 MiB in 34 packages
Removing intermediate container a2a95ff75ab6
---> 15cde1650813
Successfully built 15cde1650813
Successfully tagged custom-go1.11:latest
You can then use the following command to verify that the image was built:
$ docker images list
REPOSITORY TAG IMAGE ID CREATED SIZE
custom-go1.11 latest 15cde1650813 14 minutes ago 423MB
Now that the image is built, you can use that for compiling your Go app. Instead of creating a separate Dockerfile
which is then also used to run the app, we are going to use the docker run
command instead:
$ docker run --rm -v `pwd`:/go -w="/go" --ldflags '-extldflags "-static"' -e GOARCH=amd64 -e GOOS=linux custom-go1.11 make build
Let's decompose the command and see what each argument does:
docker run
: tells docker you want to run something inside a container--rm
: causes the container to be removed automatically after it exits-v `pwd`:/go
: this maps the current directory to the/go
path inside the container. This should be your$GOPATH
if possible or at least contain asrc
folder.-w="/go"
: sets the working directory in the container to/go
--ldflags '-extldflags "-static"'
: compiles the app as a static binary, avoiding problems with whichlibc
library is linked (the one on Alpine is different than the one on Ubuntu for example)-e GOARCH=amd64
: sets theGOARCH
environment variable toamd64
-e GOOS=linux
: sets theGOOS
environment variable tolinux
custom-go1.11
: we are using thecustom-go1.11
image to run the command inmake build
: in the/go
path, themake
target calledbuild
will be run.
This will build the binary using the container and depending on where you place the binary, it will be on the host machine.
You can also use this technique if you don't want to install Go on your machine itself, but that's not really the advised way of working.
Inspired by the DOCKER + GOLANG = ❤️ post on the Docker blog.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.