Sep 28

Go executables are statically linked, except when they are not.

Generally GO executables are advertised as statically linked.

And they are, mostly, except for those times where they aren’t.

This is about one of those times, and what I discovered in the process.

For a bit of background, I was attempting to make a docker container for the discovery.etcd.io server. Rather than be dependant on external network connections, I’d modified so it could be used locally. Believing that executables produced by go are always statically compiled I chose the busybox container as the base in order to make as small a container as possible. Container built, I discovered to my chagrin that I got a “file not found”. Upon further investigation (read google), I discovered that the executable was not statically linked but was, indeed dynamically linked.

It turns out that certain go libraries such as net/http do not have a pure go implementation at this point.  The cgo tool allows for go programs to link c-code into go programs. Generally, --ldflags '-extldflags "-static"' can be added to the compile command and it will output a proper static executable.

It couldn’t be so easy for me. It turns out that I needed to statically compile go and the language libraries as well. In order to do so, go needs to be compiled without cgo support.

  1. Verify that all the dependencies for compiling have been installed.
  2. Download the source for the Go language by cloning the go repository: hg clone -u release https://code.google.com/p/go
  3. Disable cgo: export CGO_ENABLED=0
  4. Change the working directory to where go was extracted. To compile, then invoke ./all.bash. Windows® folk would use ./all.bat. On my laptop (quad core, 12gb ram) it takes ~11 min for this process.
  5. Configure PATH to pick up the static go.
  6. Clone discovery.etcd.io from Github:
    git clone http://github.com/nimblestratus/discovery.etcd.io
  7. Build the discovery service with:

Once I had a statically built discovery service container; I went ahead and built a dynamic one — the only difference is that the static version uses busybox as the base and the dynamic uses ubuntu.

That is a rather large difference!

In either case, using the discovery service as a docker container requires using the host’s network stack (--net=host because the code connects to etcd on the loopback address.

A third option is to run the discovery service in CoreOS as a systemd service. In the discovery service’s github repo, there are systemd service and socket files for doing so.

1 comment

  1. Dieter Reuter (@Quintus23M)

    Matt, I think since GO 1.4 your infos are a little bit outdated. They’ve changed some settings to get real static binaries…

Leave a Reply

%d bloggers like this: