Packaging a Golang application

Published On: August 22, 2023

This article covers the step by step instruction on packaging a golang binary in a container

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 use scratch 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

    hello-world

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

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.