Dockerize Golang Apps for Development

Hendra Huang 黃漢忠
Kongkow IT Medan
Published in
3 min readNov 5, 2017
dockerize golang app

This blog post writes about my journey in dockerizing golang apps for development purpose. Everything is based on my experience and will be opinionated. Feel free to drop any comments or suggestions.

My goal is to create an isolated environment where everyone can run the code in their machine without having problem with dependencies and data.

How about the dependencies

My app depends on postgresql and redis. I used the official image for postgresql and redis. For development data, we can mount them to “/docker-entrypoint-initdb.d” directory. Postgresql image will execute all sql files inside that directory when creating the container.

Build and run the app inside a container

My app is written in golang and I used dep for the dependency management. To build the app, I created a golang based image with dep and git installed. I used alpine based image to run the binary. To slimmed-down the image size, I used docker multi-stage builds. Now everyone can build and run the app without go installed on their machines. This is the dockerfile.

Note: I need the postgres to be ready to serve database connection before my app run. To handle this problem, I used a script to check the connection before running the app. This might be only happens in my case.

Wrapping up the containers

I used docker-compose in order to manage the containers easier. This is the compose file.

Result

Now everyone can run my app easily just by running “docker-compose up --build -d”. Frontend engineer can run the app and use the endpoint to help them building the UI. They don’t need to care about installing all of the backend dependencies. They only need to install docker and docker-compose. Any updates from the backend side won’t bother the frontend engineer because all they need to do is just running “docker-compose up --build -d” and they will get the latest code running with the latest environment.

The bad parts

The compose file created before is not friendly for backend engineers. Everytime a backend engineer changes the code, they need to destroy and build the containers in order to see the result. Moreover, every changes will create a new image for the app. And of course it ends up taking a longer time for running the app with the latest code. This is quite annoying because previously we can rebuild the app in a few milliseconds time because go compiles pretty fast. In the end, this compose file will slow down backend engineers to develop features or fix bugs.

More friendly compose file for backend engineers

I created another version of compose file that will be used by backend engineer. Let’s assume that every backend engineers will have go installed on their machines. Instead of creating a container for building the binary inside the container, it is faster if we build the binary on our machine. Later on, the container will mount the binary and run it as container foreground process.

There is one more thing that we can do. A docker container will exit if the foreground process stopped. So if we run the binary and attached it as container foreground process, when we want to rebuild the binary, we have to stop the binary and container will exit. After stopping the binary, we rebuild the binary and we have to create the container again, run the binary and attach the process to container. This step might takes some time. My quick workaround was attaching the container with “tail -f /dev/null” as a foreground process and run the binary from my machines with “docker exec -it myappserver /usr/local/bin/myapp” command. With this approach, stopping the binary won’t stop the container, so we can rebuild the code and run the binary directly. This is the compose file.

Note: I choosed ubuntu image instead of alpine because building go binary for ubuntu is faster compare to building binary for alpine.

Tips: I created a Makefile to simplify the command for starting and stopping the container, and also for running the app binary.

This might not be the best practice, but I hope this post can give you some insights or problems that you will face when you want to dockerize your app for development purpose.

--

--

Hendra Huang 黃漢忠
Kongkow IT Medan

Still writing the story of my life through code. In automated-testing we trust.