How to Dockerize your Go (golang) App

Golang on Docker

Turning your apps into a Docker image is a great way to distribute and deploy your applications. I won’t get into why to use Docker, but I will show you the easiest way to Dockerize your apps. This is the second of many of these I will do for various languages.

There are two ways to do this, one is arguably easier, but you end up with a bigger image than you need. The other has an extra step, but you end up with a much smaller image. The choice is yours (I prefer the latter though).

Start with the app

Here’s a simple Hello World app:

It has a single external dependency, gorilla/mux. Go doesn’t have a dependency management tool built in so we’ll briefly cover it here. If you have a dependency tool that you like, go ahead and use it. If you don’t, just run the following two commands:

docker run --rm -it -v $PWD:/go/src/github.com/treeder/dockergo -w /go/src/github.com/treeder/dockergo treeder/glide init
# Say No to the question it asks, then:
docker run --rm -it -v $PWD:/go/src/github.com/treeder/dockergo -w /go/src/github.com/treeder/dockergo treeder/glide update

Now you’ll have your dependencies in the /vendor directory, which is where the go tools will look for dependencies. Those commands will work as is in any directory, but as you start to build our your code, you’ll want to replace treeder/dockergo with the name of your repository.

Way 1: Build Inside your Dockerfile

This first way is the more traditional Docker way where we do the complete build instructions in the Dockerfile. but it’s really not the best way as it will create a bloated image where most of the extra size is not needed.

Copy the following into a file called Dockerfile.

# iron/go:dev is the alpine image with the go tools added
FROM iron/go:dev
WORKDIR /app
# Set an env var that matches your github repo name, replace treeder/dockergo here with your repo name
ENV SRC_DIR=/go/src/github.com/treeder/dockergo/
# Add the source code:
ADD . $SRC_DIR
# Build it:
RUN cd $SRC_DIR; go build -o myapp; cp myapp /app/
ENTRYPOINT ["./myapp"]

Now let’s build it:

docker build -t treeder/dockergo .

And now we can run it and test it:

docker run --rm -p 8080:8080 treeder/dockergo

Surf to http://localhost:8080/ to see it running.

Way 2: Build Outside your Dockerfile

This requires one extra step, but it’s worth it, it will save you hundreds of MB. The trick is to build first, then just add resulting binary to a small base image via your Dockerfile.

Run the following command to build:

docker run --rm -v "$PWD":/go/src/github.com/treeder/dockergo -w /go/src/github.com/treeder/dockergo iron/go:dev go build -o myapp
docker build -t $USERNAME/$IMAGE:latest .

Now the built binary called myapp will be in your current directory.

Copy over your Dockerfile with this now:

# iron/go is the alpine image with only ca-certificates added
FROM iron/go
WORKDIR /app
# Now just add the binary
ADD myapp /app/
ENTRYPOINT ["./myapp"]

Now let’s build it:

docker build -t treeder/dockergo .

And run it and test it:

docker run --rm -p 8080:8080 treeder/dockergo

Surf to http://localhost:8080/ to see it running.

Multiple Ways to Skin an Image

As you can see, we built our image two different ways with the exact same program inside. But one way is better than the other due to ending with a much smaller image. How much smaller? ~300 MB smaller.

I’d say that’s worth it.

Now What?

Ok, so you turned your app into a Docker image, now what?

Well the next thing you’ll probably want to do is push it to a Docker Registry. Docker Hub is the default so try that first.

docker push YOUR_USERNAME/dockergo

Now go ask a friend to try your app by running this command:

docker run --rm -it -p 8080:8080 YOUR_USERNAME/dockergo

If your your friend can run your app that easily, you can also deploy software to your servers just as easily. All your friend and your servers need are Docker installed… which is a beautiful thing.

Show your support

Clapping shows how much you appreciated Travis Reeder’s story.