Why isn't the go executable compiled statically?


(Alex Athanasopoulos) #1

I use compiled go programs on Alpine Linux by compiling them statically, so that they do not depend on external libraries (which are different on Alpine).
But when I recently tried to run a go “script” directly on an Alpine Linux system, the standard distributed go executable does not run (go 1.13.1). Couldn’t go be compiled statically, so it does not depend on external libraries?

I know there is a go package on Alpine, but I don’t want to install it. I would rather use the go executable from a directory that is shared among several alpine systems (which are actually containers).


(Sebastien Binet) #2

Go binaries are statically compiled by default.
but if you are using net or os/user, you will get a dynamically compiled executable (linked against libc)

you will have to provide the netgo and usergo build tags to use the Go-based dns resolver (instead of libc's) and the Go-based function to query the Unix user “database” (instead of libc's).


(Alex Athanasopoulos) #3

So the “go” executable is linked against libc becauses it uses the system’s dns resolver and user database?

I have a go program that uses net/http (it downloads urls, so it uses the dns resolver), and when I link it statically, it runs fine on Alpine. I compile it with this alias:
alias goinstall=‘CGO_ENABLED=0 go install -ldflags ‘’’-extldflags -static’’’’


(Sebastien Binet) #4

that works.
but as I said, netgo should accomplish the same:

package main
import _ "net/http"
func main() {}
$> go build -o exe-1 ./main.go
$> go build -o exe-2 -tags netgo ./main.go

$> ldd ./exe-1
	linux-vdso.so.1 (0x00007ffe3abae000)
	libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f4afcdcf000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007f4afcc08000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f4afce22000)

$> ldd ./exe-2
	not a dynamic executable

(Alex Athanasopoulos) #5

Thank you. I didn’t know about -tags netgo, neither about ldd.

I wanted “go”, the Go compiler, to be statically compiled.

I use LXD containers on a host, and I want to use Go on several of them, without installing Go on each one of them. So I unpacked the Go distribution on the host in a directory that is shared with all containers. I then use the same copy of go on all containers. But this only works with containers that have libc (such as ubuntu). It doesn’t work with alpine containers.

I figured out a workaround for alpine linux:

  • Install the alpine version of Go on a temporary alpine/edge container (which has the latest version of go): apk add go
  • Copy /usr/lib/go/ to the host, and share it with all other alpine containers.
  • Delete the container that I originally installed Go to.

I now have one copy of Go for all alpine containers, and one copy of Go for all ubuntu containers (and others with libc).