Live-Reload Dev Environment with Docker and Go

by Marko

For people coming from scripting languages (like JavaScript, Python, Ruby) to Go, it’s usually weird in the beginning how they need to recompile applications each time when they change a piece of code. That’s even more amplified when they run their code inside of a Docker container which adds one more hassle to the problem - rebuilding images.

So, in this tutorial, I’ll show one easy way to create your Docker image once and have it reload on each code change just as you are used to in node.js let’s say, with the nodemon package.

We will have a simple Go web server implemented using a small and compact Express-like framework that you should definitely check out, called - Fiber. So, let’s write a simple hello world code. Here is the code.

1 2 3 4 5 6 7 8 9 10 11 12 13 package main import "github.com/gofiber/fiber" func main() { app := fiber.New() app.Get("/", func(c *fiber.Ctx) { c.Send("Hello, World!") }) app.Listen(3000) }

Now when we have code in place we are ready to launch an application, but not just with a local Go binary but rather inside of a Docker container. So, here is the Dockerfile.

1 2 3 4 5 6 7 FROM golang:alpine RUN mkdir /app ADD . /app/ WORKDIR /app RUN go get -v github.com/gofiber/fiber RUN go build -o main . CMD ["./main"]

As you can see it’s fairly small and compact, but with this approach, we would need to do a rebuild of the image every time we change code, and in development, we don’t want that, of course. So, here is an updated version of Dockerfile that will just by adding these two lines to do all the magic for you.

1 2 3 4 5 6 7 FROM golang:alpine RUN mkdir /app ADD . /app/ WORKDIR /app RUN go get -v github.com/gofiber/fiber RUN go get -v github.com/cosmtrek/air ENTRYPOINT ["air"]

We use the Air package present here on GitHub. What we do first is install Air executable in our container with go get, then we set ENTRYPOINT to ["air"] which will basically run the script that will wrap go build command for you and start watching your files and folders for any change and react to those changes accordingly.

Air supports quite a few configuration options that you can check in the example file on the repo. Here for simplicity, I didn’t want to include any of that stuff, but usually what people do is change at least the entry file for generating executable. Here we have used just plain old main.go.

That’s it, neat and simple, happy live reloading.