Creating standalone Golang apps in Docker
28 February 2022 569 views
Most tutorials about dockerising Golang apps tell you to use the Golang image as the base so that you can compile it. Don't do that! Why would you want hundreds of megabytes of unnecessary cruft in your image, when you could just have a small standalone binary, running in a container by itself?
Build the binary on your development machine with a flag to statically link required libraries, and copy it directly into a scratch image. This will give you a wonderfully small, portable image with a minimal attack surface:
# Build a binary of your app.
CGO_ENABLED=0 go build -o yourappname *.go
# Make a tar archive of the binary and any other files it needs.
tar -cf yourappname.tar ./*
# Build a Docker image directly from the tar file.
docker import -c "ENTRYPOINT [\"/yourappname\"]" - yourappname < yourappname.tar
Automate build and Docker image creation with a makefile
But it's probably most convenient to automate the whole build and image creation process with a makefile. The command 'make container' will build the whole thing.
.DEFAULT_GOAL := build
fmt:
go fmt ./...
lint: fmt
golint ./...
vet: fmt
go vet ./...
shadow ./...
build: vet
CGO_ENABLED=0 go build -o yourappname *.go
tar: build
tar -cf yourappname.tar ./*
container: tar
docker import -c "ENTRYPOINT [\"/yourappname\"]" - yourappname < yourappname.tar
Solution for "exec user process caused: no such file or directory"
If you are trying to build a minimalist scratch Docker container for a Golang app you may encounter the following rather infuriating error:
standard_init_linux.go:228: exec user process caused: no such file or directory
The solution is to prepend the flag CGO_ENABLED=0 to the build line as described above, eg:
CGO_ENABLED=0 go build -o yourappname *.go
This flag tells Go to build a statically-linked binary, which doesn't have any external dependencies. That's exactly what you need in a scratch (empty) container.
Copyright, all rights reserved.