This article covers the step-by-step instruction on packaging a golang binary in a container
Pre-requisites
A Linux OS (x86) with docker
Logon to your github account and create a new repository called “my-web-app”.
Create a staging area to store your code
mkdir my-web-app
Create a simple go program called
main.go
/* Sample Web Application Author : Ansil H Email: ansilh@gmail.com */ package main import ( "fmt" "net/http" "log" ) func demoDefault(w http.ResponseWriter, r *http.Request) { data := `<html><head></head><title></title><body><div> <h2>Hello World!</h2>` fmt.Fprintf(w, data+`</div></body></html>`) } func main() { http.HandleFunc("/", demoDefault) log.Printf("Starting web server on port 9090") err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
Multi-stage build
In a multistage build, the binary will be compiled using a container and then the resulting artifacts will be packaged in another container.
Create a file called
Dockerfile
and paste below content in it.FROM golang:1.21 as build COPY main.go ./main.go RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ go build -a -installsuffix cgo -ldflags="-w -s" \ -o /bin/my-web-app ./main.go FROM scratch COPY --from=build /bin/my-web-app /bin/my-web-app CMD ["/bin/my-web-app"]
Let’s examine this multi-stage build
The binary build is happening in container golang:1.21
and the container having an alias name build
. This is called naming a stage in multi-container build.
Once the
build
stage completes, the next stage will run which will usescratch
image; means no base image.COPY --from=build /bin/my-web-app /bin/my-web-app
The binary built in the build
phase will be copied to scratch
container.
Building the container
Run below command to build the application container
docker build . -t my-web-app:v0.1
Check the resulting image
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-web-app v0.1 27ba7779b327 52 seconds ago 4.58MB
Start the application using docker
To start the app in the terminal, you can run below;
docker run --name my-web-app -p 9090:9090 my-web-app:v0.1
Open your browser and access the URL
http://localhost:9090
Push the Dockerfile and the code to git
echo "# my-web-app" >> README.md
git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:<user>/my-web-app.git # Replace <user> with your github user name
git push -u origin main
Congratulations!!
Now you have the basic understanding of how a multi-stage container build works and how the code is organized in git.
This example can be expanded further by adding a GitHub action that can build the container and push to docker-hub if you want.
Let’s keep that exercise for a future date.
About the Author
Ansil Hameed Kunju
Ansil has more than a decade of experience in different IT domains. He is an expert in DevOps.His skill set includes Linux, GCP, AWS, VMware, Nutanix, Rancher, Docker, Git, Python, Golang, Kubernetes, Istio, Prometheus, Grafana, ArgoCD, Jenkins, StackStorm and other CNCF projects.