Linux Deployment Scripts

A common issue in web development is getting new code to production environments. Nobody wants their site down for long, and depending on who you are a long time could be seconds or less. If you’re production environment is running a versioned instance of your code, updating that environment is as simple as using your version control. If your moving to a new location however, this isn’t the case.

So if you’re moving your production environment, or even just adding another server to your production environment, bash scripts will be of great help to you. The reason for scripting out your deployment is simple: reproducibility. Don’t take chances migrating a live environment manually. Deployment scripts are testable and version-able.

WARNING: This isn’t a tutorial on bash-scripting. I presume you already know at least some of the basics.

The strategy of this script is simple: Setup all of the variables up front, then execute the following:

  1. Checkout all code into a holding folder (servername.hold)
  2. Switch to the appropriate version of code (git checkout tags/release-0.1)
  3. Create any necessary folders that are not versioned (like cache and log folders)
  4. Apply any necessary ownership/permissions (apache, 0700)
  5. Move the folder from the holding location, to the operating location

The strategy is simple enough in fact, that you could have multiple site deployment scripts that merely setup the variables for use with the same operational script. Anyways, here’s an example of how to get this done.

#!/bin/bash

###########################################################
# Setup section of code. Setup necessary values for use in operational section of code
###########################################################

#establish some base values for what the server name is and where to check it out at
SERVER="awesome.com"
PROD_LOCATION="/var/www/html/$SERVER"
HOLD_LOCATION="/var/www/html/$SERVER.hold"

#establish base values for app and lib git repositories
GIT_REPO_URL="git@awesome.com"
GIT_APP_REPO="awesome.git"
GIT_LIB_REPO="awesome-library.git"
GIT_APP_BRANCH="tags/release-1.0"
GIT_LIB_BRANCH="tags/releases-1.0"

# create a list of folders that will be used for apache access
FOLDERS="$HOLD_LOCATION/app/var/log
$HOLD_LOCATION/app/var/cache
$HOLD_LOCATION/app/var/backup"

###########################################################
# Operational section of code. Modify at your own risk
###########################################################

# echo some information for the user to see what's going on
echo
echo "DEPLOYMENT SCRIPT: $0"
echo

# if the folder already exists, then stop. We won't be able to checkout if the folder already exists
if [ -e $HOLD_LOCATION ];
then
echo "Folder already exists"
exit
fi

# echo the results of checking out the application code, and switching to the release tag
echo `git clone $GIT_REPO_URL:$GIT_APP_REPO $HOLD_LOCATION`
cd $HOLD_LOCATION
echo `git checkout $GIT_APP_BRANCH`
echo

# echo the results of checking out the library code, and switching to it's release tag
echo `git clone $GIT_REPO_URL:$GIT_LIB_REPO $HOLD_LOCATION/lib`
cd $HOLD_LOCATION"/lib"
echo `git checkout $GIT_LIB_BRANCH`
echo

# iterate over the folders creating them, then assigning them to apache
for folder in $FOLDERS;
do
# output what directory is currently being operated upon
echo "$folder"
mkdir "$folder"
chown -R apache: "$folder"
chmod -R 0700 "$folder"
echo
done

#move the files from the holding area, to the actual area
echo `mv $HOLD_LOCATION $PROD_LOCATION`

As you can see, everything from the operational section down is basically plug and play. The variables are set, and it’s off to the races. Note that the library repository is just something that’s common for what I typically deal with. That may not apply to your situation. This script shouldn’t serve as the definition of what a production deployment script should be. Rather, this is just an example of one that’s been quite helpful to me.

Keep Your SSH Identity

So, I’ve been doing a ton of stuff lately on a ton of servers. Almost all of this involves using git to clone repositories into a multitude of servers. The problem with this, is that I’m limited to a single SSH key for all of my git clones. This is tricky, since shelling into a remote box doesn’t give you access to your remote key by default. But you can still keep your SSH identity …

There’s two ways to go about keeping the identity you require through multiple single-level-deep connections. That basically means, you can keep your SSH identity from one box to another. If you hop from one box to another and another, I can’t help you. There’s probably a way to do it. I don’t know it.

Anyways: TWO ways to do this. Both of these options assume you’ve got ssh-agent running on the machine you wish to transfer your identity from. To get this running, do the following:
eval `ssh-agent`
ssh-add

This ensures the ssh-agent daemon is running, to provide an identity when you request it to be forwarded. This also assumes you’ve created a public key to transfer your identity.

So, the ways to do this are:
1. Use the -A flag when you shell into a box.
This basically means whenever you shell into somewhere, you add -A to your ssh command. An example would be:
ssh -A username@awesome.server.com

2. Set the ForwardAgent flag to “yes” in your ~/.ssh/config file.
This is a synonym for the -A flag in an ssh command

Both of these options allow you to transfer the key you hold on one machine, to another. Don’t try to use ssh-agent on the machine you connect into though. If you do, you’ll lose your original identity.

So, all together now:

eval `ssh-agent`
ssh-add
ssh -A username@awesome.server.com

Questions are always welcome ;)