Deploying LAMP websites with git and gitosis
Requirement of the day: I’m providing a LAMP environment to some other developers elsewhere in the organisation. They’ll do all the PHP programming, but I’ll look after the server, keep it patched, upgrade it when necessary, and so on.
At some point in the future, we’ll doubtless need to rebuild the server (new OS version, hardware disaster, need to clone it for 10 other developers to each have their own, etc…), so we want as little configuration as possible on the server. Everything should be built from configuration that lives somewhere else.
So, the developers basically need to be able to do 3 things:
– update apache content – PHP code, CSS/JS/HTML, etc.
– update apache VHost config – a rewrite here, a location there. They don’t need to touch the “main” apache config (modules, MPM settings, etc)
– do stuff (load data, run queries, monkey about) with mysql.
Everything else (installation of packages, config files, cron jobs, yada yada) is mine, and is managed by puppet.
So, we decided to use git and gitosis to accomplish this. We’re running on Ubuntu Lucid, but this approach should translate pretty easily to any unix-ish server.
1: Install git and gitosis. Push two repositories – apache-config and apache-htdocs
2: As the gitosis user, clone the apache-config repository into /etc/apache2/git-apache-conf, and the apache-htdocs repository into /usr/share/apache/htdocs/git-apache-htdocs
3: Define a pair of post-receive hooks to update the checkouts when updates are pushed to gitosis.
The htdocs one is simple:
cd /usr/share/apache2/git-apache-htdocs && env -i git pull --rebase
the only gotcha here is that because the GIT_DIR environment variable is set in a post-receive hook, you must unset it with “env -i” before trying to pull, else you’ll get the “fatal: Not a git repository: ’.’” error.
The apache config one is a bit longer but hopefully self-explanatory:
cd /etc/apache2/git-apache-conf && env -i git pull --rebase && sudo /usr/sbin/apache2ctl configtest && sudo /usr/sbin/apache2ctl graceful"
Add a file into /etc/apache/conf.d with the text “Include /etc/apache2/git-apache-conf/*” so that apache picks up the new config.
We run a configtest before restarting apache to get more verbose errors in the event of an invalid config. Unfortunately if the config is broken, then the broken config will stay checked-out – it would be nice (but much more complex) to copy the rest of the config somewhere else, check out the changes in a commit hook, and reject the commit if the syntax is invalid.
And that’s it! make sure that the gitosis user has rights to sudo apachectl, and everything’s taken care of. Except,of course, mysql – developers will still need to furtle in the database, and there’s not much we can do about that except for making sure we have good backups.
You might be wondering why we chose to involve gitosis at all, and why we didn’t just let the developers push directly to the clone repositories in /etc/apache2 and /usr/share/apache2/htdocs. That would have been a perfectly workable approach, but my experience is that in team-based (as opposed to truly decentralised) development, it’s helpful to have a canonical version of each repository somewhere, and it’s helpful if that isn’t on someone’s desktop PC. Gitosis provides that canonical source
Otherwise, one person pushes some changes to test, some more to live, and then goes on holiday for a week. Their team-mate is left trying to understand and merge together test and live with their own, divergent, repo before they can push a two-line fix.
More experienced git users than I might be quite comfortable with this kind of workflow, but to me it still seems a bit scary. My years of CVS abuse mean I like to have a repo I can point to and say “this is the truth, and the whole truth, and nothing but the truth” :-)