A RESTFul Go living in docker

Avatar of Rakesh Mothukuri

Rakesh Mothukuri

| Reading Time : 4 minutes

Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri

Go compiler can produce a binary file which is can natively on any machine(given its built for that). However, there are times it is more convenient to containerize your application and this tutorial will help you to build a basic RESTFul API built-in go and containerize it.

Building a Web Server in Go

We will write a simple Go application which exposes a simple greeting when a call is made to URI http:localhost:8080. In order to build this first, we will create a folder, and let’s say we call it as Go-App and inside it we will create a folder called server which is the home for all the back-end code we are going to write. The final folder structure will look like this

Next, we will create a Go Module which is a collection of Go packages stored in a file tree with a go.mod file at its root but running the command inside the server folder

cd server
go mod init go-app

Now here we will create a very simple server that can handle HTTP requests. To do this we’ll create a new file called main.go and include the below code snippet into the file

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", hello)
	fmt.Println("Server started")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func hello(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(`{"message":"hello world!"}`))
}

Now if we read through this file

main() function

The main() function acts as the entry point of the executable programs. It does not take any argument nor return anything and Go automatically calls the function when you execute to run the program

In main() function, the HandleFunc call tells the HTTP package to handle all requests to the webroot ("/") with our hello function. And when program control reached http.ListenAndServe, specifies that our code should listen on port 8080

If we now run the command go run main.go and navigate to localhost:8080 on our web browser, we should see something like this.

Now we have a basic Go application that serves response on URL http://localhost:8080 now next task is to build a docker image and run our application in a container. To do this create a file called Dockerfile in the project root directory and paste the below content

FROM golang:1.15-alpine AS GO_BUILD
COPY . /server
WORKDIR /server/server
RUN go build -o /go/bin/server/server

FROM alpine:3.10
WORKDIR app
COPY --from=GO_BUILD /go/bin/server/ ./
EXPOSE 8080
CMD ./server    

The reasoning behind each line inside the docker file

Two important things in this Dockerfile:

  1. This file uses Docker multi-stage build in Docker, which is just a way of saying that we can build multiple Docker images defined in the same file. Here in this scenario, we use one image to build our Go application and another for running it.
  2. The next one is about caching. For a faster build process, Docker caches the result of each line of a Dockerfile. Order of lines is important inside the Dockerfile, and you should generally perform actions that don’t change very often earlier in the Dockerfile than things that do change more often.
FROM golang:1.15-alpine AS GO_BUILD` ensures Docker pulls the [offical Go image](https://hub.docker.com/_/golang/) as a base image n this case, we use the tag `1.15-alpine` .We mark the resulting image as `GO_BUILD

WORKDIR /server/server sets the working directory.

COPY . /server copies content over

RUN go build -o /go/bin/server/server builds your app into a binary located at /bin/server.

FROM alpine:3.10 uses alpine as our runner image in which our GO application will run

COPY --from=GO_BUILD /go/bin/server/ ./ copies the binary built earlier into the image

EXPOSE 8080 exposes application over port 8080

CMD ./server sets the default command to run when the container is run

To build the docker image execute the below command on the project root directory

docker build -t api .

This builds a docker image with a name as api and to run this image execute the below command

docker run -it -p 8080:8080 api

Conclusion

You now know how to create a Restful Go API and containerize your application into a production-ready image.