Doing Production Deploys with git
At Yieldbot we follow a schedule of daily (or more) releases per day, coordinated by Chef with git smack in the middle.
To start, like many we’re happy users of GitHub for coordinating our code repositories across our development team, and our use is pretty straightforward for that. Developers change code, pull down everyone else’s changes, merge, push up their changes, etc. It’s like a “hub” for our “git” usage (whoah!).
git != GitHub
It’s important to remember though that GitHub, while making a certain usage pattern convenient, is not synonymous with “git”; a fact that we make use of heavily.
Using git’s ability to set up multiple remotes or have default remotes not up on GitHub provides for some powerful options in how code can be moved around and managed. Something we take advantage of every day both in production (which we’ll talk about in this post) and in our development environments (covered in a later blog post).
git + Chef == a tasty treat
For this post the important thing to understand about Chef is that we have a central Chef server that serves as the coordination point for deployment. The servers throughout the platform run chef-client to find out from the Chef server what they should be running and Chef and its cookbooks make it so.
To control what version of our code is deployed we have a git repo on the Chef server cloned from the repo up on GitHub. The core of our deploy procedure is to pull the latest on “master” branch from GitHub into the repo on Chef server, tag it with the name of the release, and also tag it with a special tag that moves called “production” (ie. “git tag -f production”).
Using a Chef recipe, each of the servers in our platform are also set up with the git repo but with the repo on the Chef server as their origin. During a deploy these repos fetch from the Chef server remote and sync to the “production” tag.
Once the repo on Chef server set up with the “production” tag in place where desired for the deploy, the actual deploy is triggered by poking the servers in the platform to run chef-client.
Note in the diagram above that in addition to the usual usage of git between developers Erik and Sean, the Chef server is also set up with GitHub as the remote. Below the Chef server are two examples of servers (UI and DB) that are set up with the Chef server as their remote. Note that UI and DB really only pull from the Chef server repo. The Chef server in turn mostly pulls from GitHub, although it does push back to GitHub the state of tags as manipulated during the deploy.
You can easily change the location of the “production” tag on the Chef server repo and then resync the servers in the platform to deploy any level of code desired.
During a deploy, our servers are not dependent on contacting GitHub. To start a deploy we sync the Chef server’s repo with GitHub, but we could just as easily push to the Chef server’s repo from somewhere else, or even add a different remote to the Chef server’s repo to pull from another location instead.
If any changes are made to a system to make it deviate from what was last deployed, a “git diff” in the repo on that server can expose exactly what those changes were made on that specific server (if you’ve worked with deployed code before you know this concept is huge).
In a follow-on blog post we’ll cover some more advanced uses of multiple git remotes that we leverage in our development environments.