Ayende @ Rahien

Refunds available at head office

Primitive Git Auto Deploy

Following my post yesterday, I decided that for now, we will have the following system:

  • A github hosted repository with the binaries
  • A github hook to post on notification
  • A server side listener that would get that notification

On push, we will simply call git pull in the website directory. We use git ignores for the logs & data files, but that is about it.

It is primitive in the extreme, and it likely have many failure scenarios, but for now, it works. And very nicely, too.

Comments

SHODAN
05/08/2011 09:47 AM by
SHODAN

Sounds like what I used for a small website when I was trying out Ruby on Rails.

Paul Cowan
05/08/2011 12:37 PM by
Paul Cowan

Deployment is a good extension of a package manager. Perhaps openwrap or maybe less so nuget might be a good mechanism for deployment.

Wih openwarp at least the hooks are in place during the build process.

Dave
05/09/2011 07:47 AM by
Dave

But how deal you with the loadbalancer? Or don't you have loadbalanced websites? Is git also making changes to the configuration files (web.config)? That could be problematic with service bus addresses..

How is git going to revert the operation when something goes wrong? But to be honest, I don't want to think about the possibility that I have a new release on 6 webservers and than have to find out something went wrong.

Usually I get one server from the pool and make that my live test server. I copy the current database run the update scripts on the new database. Than I update the connectionstring from my testserver to use the new database. On that webserver I also run a full regression test suite. If nothing is wrong, I copy back the old config files and pull the second server from the pool and update that one as well. Than I pull all the other webservers from the pool, update the master database and put webserver 1 & 2 back in the pool. Than I monitor the release (error 500 messages, logs) for a minute of five and finally I update the rest of the webservers one by one and add them to the pool aswell..

In the past I have tried (in our test environment) several web deployment tools where a build system creates the release and copy the release files to a specified location. The deployment tools take up the deployment from there. But none of them are really suited for a busy production environment when something goes wrong.

Using transactions you can make a atomic update to your database. But at a certain point you have to commit the 'master' transaction. As soon the webservers are online again that will make database content updates (customer details, order (item) details, etc). So how are you going to revert a release without loosing the new data?

A production releases are a two man job at our company. Much like in an airplane cockpit we perform the several tasks and the other person have to confirm the action. We work in the financial sector (stock markets, loans, insurances, etc), so a release have to be 100% every time. And with a 99,999% uptime SLA (= less that 5.5 minutes of downtime per year) we also can't afford a release that did go wrong.

Software should make you life easier, not take you out of the loop. And manually update 6 webservers takes an average of 20 minutes. That 20 minutes includes several verification points.

Desktop release are a bit easier. I only need to send a message to a UDP broadcast address and all running clients will check for updates, download the new assemblies and restart the application (we don't use clickone, but have a similar update process).

Daniel Hoelbling
05/09/2011 03:53 PM by
Daniel Hoelbling

Ayende, there is a way to use a bare repository for what you do.

By using a post-receive-hook you can do a git checkout -f to your webapp-folder from the bare repo.

So you push to the repo, and once the push is received the repo runs the post-receive-hook script to deploy the app..

greetings

Remco
05/09/2011 06:19 PM by
Remco

I think what Oren wants here is a super simple deployment for a super simple site. No soa, no complex configuration or webfarms.

KISS applies here. why bother with a CI / deployment infrastructure when you have a simple personal site.

I've used this too with subversion for a personal/static site.

Remco

Ayende Rahien
05/11/2011 06:02 AM by
Ayende Rahien

Dave,

Did you see the title? I said primitive, and I meant primitive. This is for a simple site, no load balancing.

Git is also tracking the config changes, yes.

Reverting is as simple as doing something like: git checkout previous-version-hash

A more complete process would be something like:

  • Addresses are either static or calculated, the config file is shared among all servers.

  • You do one live test on one of the servers. When you are through, you basically do something like this (scripted, of course):

** loadBalancer.TakeOut(server1);

** execute on server1: git pull

** loadBalancer.Bring(server1);

In general, you don't do anything in the release manually, it has to be scripted. Otherwise it wouldn't work the same way all the time.

Ayende Rahien
05/11/2011 06:03 AM by
Ayende Rahien

Daniel,

Thanks for the info

There might be problems with that approach regarding versioning, conflict detections, etc.

I want the process to break if we locally modified something (stupid to do, but happens)

Daniel Hoelbling
05/11/2011 08:17 AM by
Daniel Hoelbling

Hi

Then you can use the pre-commit-hook (i think its called that way) to do that.

There is one before receive that can fail and one after that can only output messages.

You could try doing a dry-run if that's possible on a checkout.

I'd have to look up how to fail this early. But it should work..

Greeting Daniel.

Daniel Hoelbling
05/11/2011 08:24 AM by
Daniel Hoelbling

Ah found it:

pre-receive:

www.kernel.org/.../githooks.html#pre-receive

If your script returns anything besides 0 it will not update any refs in the remote repository.

Now you could use a non-bare repository in your inetPub folder (that's a clone of your bare repo you push to on the same server).

If you push to the bare-repo you run the pre-receive hook that runs a git status on your non-bare repo (that contains the app), if nothing changed it will allow you to proceed and receive the commits.

Afterwards you can run the post-receive hook that goes to your non-bare repo and does a git pull ..

But this is not really the most elegant way I can think of, and it's prone to errors once you do non-fast-forward pushes (eg. amending or rebasing) where you'd have to go to your server and re-clone the non-bare repo)..

I'd suggest using only one reop you push to that does a git checkout to a folder.. Since you can run scripts there you could even checkout to a new folder every time and use powershell to redirect IIS to that new folder, leaving the old site intact.. (Not really satisfactory either)

greetings Daniel

Comments have been closed on this topic.