We use puppet for managing packages and configuration on our systems. At some point I'd like to take a look at Chef, too -- having Ruby as the configuration language seems like it'd be nicer than puppet's config file format. It took some work to get set up, but it's so nice being able to keep track of what's on each machine in version controlled source files.
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.