Go and Alpine Linux

June 6, 2015

linux

Alpine Linux is the small Linux OS everybody is using for Docker images. It is super small and has a sh*tload of packages. It’s libc is musl libc, which is different than glibc most other Linux distros are using. When deploying Go on such a image you want a truly static binary.

Building a static binary can be done with the following command (this is for SkyDNS):

% go build -ldflags "-linkmode external -extldflags -static"
# github.com/miekg/skydns
/var/tmp/go-link-FI6Ox0/000000.o: In function `_cgo_632c88804cec_C2func_getaddrinfo':
/home/miek/upstream/go/src/net/cgo_unix.go:55: warning: Using 'getaddrinfo' in
statically linked applications requires at runtime the shared libraries from the
glibc version used for linking

That ugly warning is because glibc uses nss(5) “Nameserver Service Switch” which uses dlopen(3) to dynamically load the correct resolver library. The end result is that the Go binary can’t resolve any DNS records!

Static compiling with glibc is completely broken.

They even consider this a feature.

Now a little known feature is that Go ships with a fully featured pure Go implementation for resolving DNS records. The magic to enable it is the following command line:

% go build -a -tags netgo -installsuffix netgo

No warnings and still a static binary!

This is true with go version 1.4.2 but might change in go 1.5+.

Linux  Docker  Golang  Static  Binary