Beauty And The Beast :)
“Golang” the language created by Google that provides impeccable performance over application that demands concurrency has grabbed a separate spot in the tech community, few well known Inc’s that adopted the language include Facebook, Netflix , Dropbox etc. When Go API’s are dockerized it gives more flexibility and control over the applications being deployed on cloud. Even the Docker software is written on Go that manifest its emerging prominence in the industry
We will walkthrough on building an alpine image holding a Go API and the steps to get it achievable is split into several fragments as below
Name the file as main.go that contains dependencies — echo, logrus and net/http. We have multiple third party frameworks like Gradle, Martini ,Revel etc that gives customized features for building RESTful API’s. Its absolutely your choice to choose one that satisfies your needs and you can also only rely on golang lib “net/http” to create one RESTful service.
Code Snippet
package main
import ("fmt""github.com/labstack/echo""github.com/labstack/echo/middleware""github.com/sirupsen/logrus""net/http")var log =logrus.New()
func init() {log.Formatter = new(logrus.JSONFormatter)log.Formatter = new(logrus.TextFormatter) // defaultlog.Level = logrus._DebugLevel_}
func main() {fmt.Println("Main function :")e := echo.New()e.Use(middleware.Logger())e.Use(middleware.Recover())// Routese.GET("/go-docker", goWithDocker)e.Logger.Fatal(e.Start(":8080"))}
func goWithDocker(c echo.Context)error{return c.JSON(http.StatusOK, "Go with Docker Container")}
The service is available through a HTTP end point
http://localhost:8080/go-docker
There are multiple IDE’s available in market a few are Sublime, Atom, Gogland etc. I have been using Gogland as it has multiple features and there is early build, give it a try!!
Now lets talk about the program, we have exposed a simple GET operation that has Routes configured /go-docker exposed on a HTTP protocol**.** Logs are written using logrus framework for tracking the request and response.
For build management you could use Jenkins with Docker plugin installed to make it interactive with Docker CLI.
Use any of the golang images available in docker hub as per your need https://hub.docker.com/_/golang/ , we will be using golang:1.8 in this blog
Ref A: Image containing the go binary
Pull the image from docker hub and create a folder structure pattern /go/src (as expected by Go) to compile the files. Line 5–7 clubs multiple commands, pulling the required source code and vendor dependencies in your Github repo(assuming your repo has 3rd party in /vendor dir). Line 6 & 7 specifies the generated build will be specific to linux environments. The best practice is to always combine multiple RUN statements into one in order to avoid creating multiple layers during image creation.
The resulting Docker build will have a binary go_docker.exe under your /bin folder
Let’s pull the alpine 3.6 base in this demo as it is pretty light weight image which comes with minimal prerequisites to serve as a linux base.
Ref B : Alpine built with binary
Install bash inside the image to make it interactive once the container is up and running via docker. In line 14 we use the feature of multi-stage builds released in the newer versions of docker. The — from tag will allow you to fetch and refer its contents from previously created image by mentioning the source and destination dir. Refer the previous Ref A image Line 1 that specifies goimage which helps in line 14 to reference it
The ENTRYPOINT command instructs container start up should execute the .exe file i.e. go_docker file
All the above contents to be put in one single file named as Dockerfile to get executed in one shot. Build docker image and tag it under a version using the tag -t to avoid conflicts in future builds or else docker will assign a tag “latest” by default
Code Snippet
FROM golang:1.8 as goimageENV SRC=/go/src/RUN mkdir -p /go/src/WORKDIR /go/src/go_dockerRUN git clone -b <Specify-branchname> — single-branch <Github HTTP Url> /go/src/go_docker/ \&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \go build -o bin/go_docker
FROM alpine:3.6 as baseimagealpRUN apk add — no-cache bashENV WORK_DIR=/docker/binWORKDIR $WORK_DIRCOPY — from=goimage /go/src/go_docker/bin/ ./ENTRYPOINT /docker/bin/go_dockerEXPOSE 8080
Note : — indicates double hyphens
The image can be built and viewed by issuing the following commands.
docker build -t go_docker:1.0 .
docker images
Is there anything that we missed!! Containers ? We are covering it in the next section
Create container from the image and expose it by mentioning a port. You could specify your desired port range and expose the container to outside world. In AWS you could push the images to EC2 Service via ECS as tasks.
docker run — rm -p 8080:8080 go_docker
Note : — indicates double hyphens
Once the container is started you could see something similar as below on your terminal
Images can be pushed to a docker repo by mentioning the desired URL.The steps for image creation and push can be automated via Shell
docker login -u=<UserName> -p=<PWD> <Docker REPO URL>
docker push -t <Imagename>:<Version>
Choosing Go is a wise decision that gives scalability and concurrency for your application and selecting a light weight image like alpine will make the push and pull of the image to registries faster, also small size base gives you minimal operating features to build functional container where you can add/install necessary dependencies in future. Using Docker has gained wider acceptance as it makes use of disk space efficiently with at most use of its resources efficiently.