Skip to content

Instantly share code, notes, and snippets.

@chakrit
Last active July 18, 2018 20:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chakrit/8501582 to your computer and use it in GitHub Desktop.
Save chakrit/8501582 to your computer and use it in GitHub Desktop.
On Go binary deploys.

Talked with @anthonybouch and @scomma the other day and told them that I don't do source-deploys with Go programs. It was sort of a gut reaction and also because I havn't quite worked out all the details at that time as I was not at the stage to be thinking about deployments just yet.

Cons

@scomma made note that you could still do git deploys with source and compile on the server and that's right that you can do that but there are some complications:

  • Go requires GOPATH to function. You have to take care of that in your deploy scripts (with the right permissions etc.)
  • All dependencies needs to separately downloaded.
  • All dependencies then needs to be separately compiled before it's linked into the main program. This is sometimes slow (2-3 seconds per library in some case that I observe). The compilation speed go boasts depends a lot on caching--that is--not having to recompile dependencies to recompile your main program.
  • No explicit versioning support for import paths. Whatever on master on github is the version that you must use. Couple this with caching and you can have your own mini dependency hell on production servers if you are not careful.

Pros

Binary deploys eliminate almost all of those issues by resolving them on your local machines first:

  • No needs to setup GOPATH, just one folder to store your binary and related files. Could be as simple as one scp -r or an rsync call.
  • Dependencies are already compiled into the binary. No dependency waits, no extra downloads.
  • No compile delays, already compiled on the much faster dev workstation.
  • No version hell on production. Whoever deployed the code, it's the version on that person's machine.
  • Service restarts are near-instant as it's simply restarting one executable without any extra help (i.e. no build step, no bundle step, no custom server script, just need to start 1 program).
  • You no longer leave your app's source code on production machine. I'd say this might be more secure.

So that's why I think with compiled programs like Go, it's much easier to just deploy the binary. Machines are then easier to setup as well.

Caveats

There are some downsides/caveats however as I see it:

  • You need to setup go with cross-compilation support. This is not hard, as it is an officially supported feature and many people have already experimented with it. There are scripts for automating this. But this is also a thing you must do that's extra from standard installation.

  • You need to compile and deploy the right architecture for your servers. Not a big downside, but a little annoying maybe.

  • No live-editing on production servers. A little inconvenient during the early stages but not a big problem down the road.

@58bits
Copy link

58bits commented Jan 19, 2014

Have you looked at Capistrano? Whether binary or source deployed - the Capistrano deploy/rollback model is a nice way to do deployments. When everything is ready on the target server, the symlink to 'current' is updated and you've switched over to the new deployment. Rolling back in an emergency is also nice and easy, and can include tasks for migration scripts as well (both deploy and rollback). I started using Capistrano for Ruby apps - and I'm now using it for pretty much everything - even Drupal sites - http://www.58bits.com/blog/2013/03/23/deploying-drupal-with-capistrano

:-)

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

@58bits yes I have played a very tiny bit with each of the popular ones. I'm no pro at it though as I don't have much Ruby experience. I know Chef and Capistrano is also pretty cool. Will definitely look into it.

Right now I'm into Ansible though. I like the simple format and raw speed for everything. But if I have a chance to study Capistrano in depth, I just might : )

Yeah I havn't think about versioning that much, but you definitely lose that if you don't git-deploy the source. But I think that's not hard to work around. It might just be a new thing that I need to give some thought to. Don't think it'll be hard, though.

@58bits
Copy link

58bits commented Jan 19, 2014

I think you can version deploy with the binary method as well. How big is a 'cross-compilation' binary?

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

-rwxr-xr-x   1 chakrit  staff  2250552 Jan 19 16:52 go-dummy*

That was a print "Hello, World!\n" equivalent for linux/amd64 compiled on my mac. Tested on a linux and working.

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

About same for a mac binary.

-rwxr-xr-x   1 chakrit  staff  2200656 Jan 19 19:16 go-dummy*

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

I'll try with a larger app and let's see : ) gonna grab dinner for now.

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

Damn, the thing I want isn't building right now Y.Y

Anyway I tried with a revel (web framework) binary:

-rwxr-xr-x  1 chakrit  staff  13222204 Jan 18 04:17 /Users/chakrit/Documents/gopath/bin/revel

13MB

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

@58bits so you are using golang anywhere?

@chakrit
Copy link
Author

chakrit commented Jan 19, 2014

Tried with http://robfig.github.io/revel/

-rwxr-xr-x  1 chakrit  staff  13355224 Jan 19 20:25 linux_amd64/revel*
-rwxr-xr-x  1 chakrit  staff  13222204 Jan 19 20:25 revel*
-rwxr-xr-x  1 chakrit  staff  12398080 Jan 19 20:24 windows_amd64/revel.exe*

@scomma
Copy link

scomma commented Jan 20, 2014

I haven't dabbled in Go so I'm not really qualified to comment here... although a lot of what you listed make it sound like this could go either way. Setting up dependency resolution can't be harder on the production server than on a dev machine? With capistrano, it's easy enough to deploy a specific commit rather than HEAD, and also version the releases so the current symlink always points to the latest binary that's finished compiling, minimizing downtime.

Maybe you could have an intermediate server that's configured to the correct architecture and handles compilation so you get the best of both worlds?

@chakrit
Copy link
Author

chakrit commented Jan 21, 2014

I think the dependency thing stems from the fact that the Go people think that everyone should have their master branch super stable at all times. A very idealized worldview. There's no way to even tag the exact commit to use when you use go get, not even version number so I think that makes it a problem on its own.

So in practice, you can actually have everything looks the same but different commits being compiled into the binary (depending on which machine does go get when) which is totally crazy.

Having a single source of truth is definitely a nice idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment