Dockerize Go Application

These days Docker is so popular. It's so good to build your go applications in docker. Here I show you how to build a go application in docker without even installing golang on your machine.

Write the application

I use previous post application: Here 😄

Write Dockerfile

First of all, we use Go 1.11 image:

FROM golang:1.11

Go 1.11 have been used because we use go modules for dependency injection.

Then, select the working directory:

WORKDIR /src

Now, copy source to working directory:

COPY . .

We copied the project source to /src directory in the image. The first dot means current directory in your system, and the second one means working directory in the image.

Let's build the binary

RUN go build -o hello-world

Now, set default command to run the application:

CMD ["/src/hello-world"]

It's time to build the image.

docker build --tag user/hello-world .

Replace user/hello-world with your image name.

Sending build context to Docker daemon  4.096kB
Step 1/5 : FROM golang:1.11
 ---> 2422e4d43e15
Step 2/5 : WORKDIR /src
 ---> Running in 84e1bdb9d413
Removing intermediate container 84e1bdb9d413
 ---> 72ebb156c493
Step 3/5 : COPY . .
 ---> a1b6a5f2d48b
Step 4/5 : RUN go build
 ---> Running in adf1a7785c09
go: finding github.com/gin-gonic/gin v1.3.0
go: downloading github.com/gin-gonic/gin v1.3.0
go: finding github.com/mattn/go-isatty v0.0.4
go: finding github.com/gin-contrib/sse latest
go: finding github.com/ugorji/go/codec latest
go: finding github.com/golang/protobuf/proto latest
go: finding gopkg.in/go-playground/validator.v8 v8.18.2
go: downloading github.com/mattn/go-isatty v0.0.4
go: finding gopkg.in/yaml.v2 v2.2.2
go: downloading github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7
go: downloading gopkg.in/go-playground/validator.v8 v8.18.2
go: downloading gopkg.in/yaml.v2 v2.2.2
go: downloading github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2
go: finding github.com/golang/protobuf v1.2.0
go: downloading github.com/golang/protobuf v1.2.0
go: finding gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
Removing intermediate container adf1a7785c09
 ---> ff0c7547ca25
Step 5/5 : CMD ["/src/hello-world"]
 ---> Running in 07ee96627074
Removing intermediate container 07ee96627074
 ---> ddb80abe9fb5
Successfully built ddb80abe9fb5
Successfully tagged user/hello-world:latest

Image build from source. Now you can run your image:

docker run -p 8080:8080 user/hello-world

Then test your app:

curl http://127.0.0.1:8080/ping

Output:

{"message":"pong"}

Reduce image size

Separate compile and run images

Golang 1.11 image is 775MB. You can only use this image as the compiler image. Edit Dockerfile:

FROM golang:1.11 AS compile

WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o hello-world

FROM alpine
COPY --from=compile /src/hello-world /

CMD ["/hello-world"]

First, we built binary in golang:1.11.

Then have copied binary in the second container.

Note: you must set CGO_ENABLED=0 on build binary, because, you can't run it in the alpine with cgo enabled.

Now image size decreased to 19.2MB.

Strip the binary

We can use the -s and -w linker flags to strip the debugging information. Edit Dockerfile and change build line:





 






FROM golang:1.11 AS compile

WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o hello-world -ldflags="-s -w"

FROM alpine
COPY --from=compile /src/hello-world /

CMD ["/hello-world"]

Now check the image size. it's 15.6MB.

Conclusion

By using docker images we can develop and build applications faster in an OS independent environment. So, it's useful to build you go (and all other languages) applications in Docker containers.

Good development! 😉