For actually deploying our code, we use Capistrano, which we also use to run one-off tasks across machines. This pulls from our code repsitory, and each of our dev/staging/production environments know which version control branch to pull and deploy in that environment.
I've found the dpkg method to be very effective. You can sign the packages, mirror the repositories, and set up servers to automatically upgrade some/all of the packages via cron jobs.
Packages can be automatically generated by your continual integration system, which also has the nice effect of creating a fully-trusted and centralized deployment path, making it difficult to sneak in uncommitted changes and non-managed files, etc.
The packages themselves support complex dependencies, start/stop scripts, etc, and dpkg/apt-get themselves have been ported to non-Linux platforms.
Personally, I'd still like a more comprehensive centrally managed solution based around the packaging model (ie, each server runs a management agent that can install/remove/update packages, etc).
http://github.com/sunkencity/apt_fu/tree/master
it's really a quick hack, but it get's the job done.
Oh, and dependencies are great.
(#) Link has gone now, but available at http://web.archive.org/web/20060925094756/http://www.kclee.d...
You should spend time understanding all of the given capistrano recipes before you should start building any of your own since many things are already done for you.
I wasn't able to do this without staring at the capistrano code for a significant amount of time, but it was worth the effort IMHO.
$ hg pull ; hg updateThhe builds themselves go into a package repository and on a machine we just run hg pull packages/<tool>; hg merx <machine name>; hg update;
(hg merx pulls customised machine configuration files from the repository or defaults if non-existant).
It takes a bit of initial setup but then works well for ongoing deployment (we add 10-15 commodity servers to our pool each week = easy to do now - dd the debian image and run those three commands. sorted).
So far it meets my needs well. The only issue I had was getting my SSH key working, but I was eventually able to iron that out.
I think chef has a lot of potential. However, I found the learning curve rather high. If you end up using it, you'll definitely want to use a VM with snapshots.
So my deployment looks like:
git push live darcs push
which sends patches to the test repo and ssh remote darcs --repo=live pull ../test
which is in a makefile so we can just do: make release
Let me add here that darcs' inherent cherry picking abilities are a wonderful match for web development. Being able to fast track changes to the live site with no hassle is heavenly. git push && ssh wherever 'cd /wherever; git pull; [touch or restart something]'In general, I recommend against "git pull" unless you are intentionally trying to merge something. (Fast-forwards are a special case of merging.)
Its pretty close to this: http://www.netfort.gr.jp/~dancer/software/dsh.html.en
Also a few custom tweaks to restart the Puppet daemons when they die, which they do frequently.