Deploy Go with Capistrano

I’ve been using Capistrano for a while now, even for non-Rails projects, and I honestly think it’s too tightly coupled with Rails. But, anyway, I’ve always managed to deploy my projects, be it through really ugly hacks or simply sticking to the “Capistrano-way”.

In this post I’d like to cover how I successfully managed to deploy a Go/Gin web-service sticking to Capistrano as much as possible. This approach is quite general purpose but it all started trying to stick with the following 2 requirements:

  • Check out the code locally, rather than on the target machine
  • Build the code locally, for the target machine, and then only push the binary

As you may or may not know, Capistrano handles version-controlled code rather well but assumes you want to download your source on the target machine. In my particular case I didn’t really fancy the idea of setting up a Go environment on my target machine. I didn’t want that, mostly for laziness. But setting up a whole Golang environment on the target machine would also have implied more security vulnerability for my machine.

The code

Last time I checked, this feature wasn’t really documented on the Capistrano docs but turns out you can override the default Git Strategy that by default handles your code checkout on the target machine.
To be honest, the strategy itself doesn’t really enforce the checkout on the target machine, but Capistrano wraps every method of the strategy in an on block.
In order to bypass this behaviour I simply copied the Git strategy from the Capistrano sources and wrapped back each method in a run_locally block.

Copy the script in where you keep your deployment code. Be sure to load it. A good place can be your Capfile. After loading it, make sure to set the appropriate strategy in your recipe:

 

As you can see from the snippet, the repository will be cloned into repo_path, so be sure to specify a valid path. Now that we have instructed Capistrano on how to checkout the code on our local machine we have to instruct it on how to build and then push our Go project. The following snippet exposes a couple of Rake tasks to perform such things. This script assumes that you’re a deploying linking the log and pid directories. The pid is going to hold the pid file of your binary after executing it. This is gonna be useful across deployments to be able to automatically shut your process down and restart with the new version.

This rake task handles 3 useful options that you can specify using the set method provided by Capistrano:

  • go_build_env
  • go_run_env
  • go_run_args

go_build_env has to be used to specify the target machine operating system in order for Go to be able to cross-compile your code. In my case, for example, I want to deploy to a linux x64 architecture:

You can check for more environments here.

Use go_run_env to specify environment variables to be set upon starting your executable. Use go_run_args to provide your executable with the startup arguments it needs. As you can see, this rake file already hooks into the right Capistrano tasks to makes sure it builds and uploads after fetching the right repository revision.

Wrapping up

If you’ve correctly included the previous snippets, configuring your deployment should be straightforward. We have managed to deploy our Go code without having to setup another Go environment on the target machine. I think this is great since the cross-compilation produces a static executable that has 0 dependencies to be run on our target machine.

As I said, already, I think the guys over at Capistrano could do a little more to make the tool really general purpose and be more helpful for such integrations. But overall, this integration hasn’t really required too much code after all.

I hope you enjoyed this quick overview on how to deploy your Go code with Capistrano.