Developing with Golang with Docker
During some of my adventures learning Go, I’ve found it very cumbersome to be installing dependencies, working on different workspaces, integrating my go projects with different build systems (whether enterprise, or building my own), using some of Go’s best practices.
First of all:
Prerequisite
Docker - Seriously just docker, you don’t even need Go installed on your host.
Why Use Makefiles?
I remember during college that Makefiles were really useful at building the thing, running the thing, testing the thing, and cleaning up the thing for my C/C++ projects. I figured instead of using go build all the time, and having a script to deploy to linux, mac, or windows, I can do it all in a Makefile.
To get a feel of what my typical workspace is like, see below:
├── MyApp
├── bin
├── src
│ ├── MyAppExecution
│ │ ├── main.go
│ ├── Private
│ │ ├── privateExecutions.go
│ └── Gopkg.toml
├── .gitignore
├── Jenkinsfile
├── README.md
├── Makefile
├── build-go-binaries.bash
Some Code
One of the things that really irks me with a lot of examples online is that even with Makefiles, I still have to worry about go dependencies on the host, I still have to assume whatever build system that I am using has go installed, and I have to assume that these build systems have access to the internet or not.
Before we move to our Makefile, let’s get some house keeping done first. Let’s just write a super bare bone Golang application that imports a nice logger library, and have it print Hello World.
├── makefile_example
├── src
│ ├── makefile_example
│ │ ├── main.go
│ ├── Gopkg.toml
├── Makefile
├── Dockerfile
In main.go, I have the following code:
In Gopkg.toml, I have the following configuration:
Nothing too special, but this will enforce two things for this article:
Using external libraries
Setting up our project to be built using Makefiles
Note: Even though I did say all you need is Docker, you could (or maybe should) have Go installed on your development environment to do your quick testing and local development. Having to use docker all the time does require more time, despite it’s benefits.
Dockerfile
We’ll now need to write a Dockerfile to build our docker image.
Basically a rough summary of what this does is:
Installs a tiny golang image
Updates and installs packages
Sets the bin directory for the go binary
Adds everything in your directory to the working directory
Gathers dependencies
Sets the working directory
To test this, you can run sudo docker build . to create your docker image. Below is a sample execution of my docker build:
Finally, the Makefile
Build the thing
Let’s just start with a bare bone makefile that will just build the thing.
Cool! Now we can just run make or make build, and our code will now build our go code.
Run the thing
But what about actually running our code? We can simply add a run rule, and tell it to run that file
And now, when you run make run, you get something like:
Nice! I would also add a rule to prevent building, if you just want to run the same image:
Compile the thing!
Finally, we’ll want a way to compile our executable to any operating system. Thankfully, we have an awesome developer over at https://www.digitalocean.com/community/tutorials/how-to-build-go-executables-for-multiple-platforms-on-ubuntu-16-04 to help us.
I’m going to have a slightly modified version (changing the destination OS from windows to linux , and moved the binaries to the bin/ directory) below:
Save this file as build-go-binaries.bash in your top level workspace. Now let’s modify our Makefile to add a compile rule.
make compile will run build, and then compile the binaries
Now we can run the binary, since we mounted the bin/ folder to our compilation command.
We can even run this on our linux box!
Congratulations! Hopefully you reached to the end of this and found this article useful!