The problems
1. Distributing code to autoscaled EC2 instances without user interaction .
2. Launching new instances with the current code release.
(Please do not use any code in this article without proper testing in a non-production environment!)
Solution
An architecture based upon EBS snapshots, rsync, the EC2 and Autoscaling api tools.
Overview
Problem 1. Publishing code to existing instances
Application code is stored on release server, on a dedicated EBS volume.
The deployment script performs the following operations:
1. Obtain list of instances in Autoscaling group(s)
2. Push application code from /release autoscaled instances.
3. Snapshot the underlying EBS volume and save the snapshot id for instances launched later.
Problem 2: Launching instances with the correct code
UNIX system init script running on the new instance performs the following steps:
If /release is not already configured:
- Query http://releasesrvr/snap.txt for the latest snapshot id
- Create a new EBS volume based upon this snapshot
- Mount the new volume at /release
- Continue with boot process
Examples
Release server setup
1. Configure EC2, Autoscaling tools. Open HTTP port 80. Install and enable apache.
iptables -I INPUT -m tcp -p tcp --dport 80 -j ACCEPT
service iptables save
yum -y install httpd
chkconfig httpd on
service httpd start
2. Create volume
ec2-create-volume --region us-east-1 -z us-east-1b -s 40
3. Attach volume
ec2-attach-volume --region us-east-1 -d /dev/sdk1 --instance i-12345678 vol-12345678
4. Format volume
mkfs.ext3 -L code_release /dev/sdk1
5. Mount volume
echo "" >>/etc/fstab
echo "LABEL=code_release /release ext3 defaults 0 0" >>/etc/fstab
mount /release
6. Copy code
rsync -az stagecode:/release /release
7. Snapshot the volume
ec2-create-snapshot -d latestrelease vol-12345678 | awk '{print $2}' >/var/www/html/snap.txt
Deployment pseudocode
#!/bin/bash
# push code to autoscaled instances
SRC=/release/
DEST=/release/
KEY=/root/test.pem
LIST=instances.txt
>$LIST
sync;sync;sync;sleep 2 # flush buffers to disk
for i in `as-describe-auto-scaling-instances |awk '{print $2}'`; do
ec2-describe-instances $i |grep INSTANCE|awk '{print $12}' >>$LIST;
done
for i in `cat $LIST`; do
echo "Syncing from $SRC to $i:$DEST";
rsync -av --delete -e "ssh -i$KEY" $SRC www@$i:$DEST;
done
Boot pseudocode
#!/bin/bash
# create release filesystem at boot
DEV=/dev/sdk1
if ! grep “/release” /etc/fstab ; then
VOL=`curl http://releasesrvr/snap.txt`
VOL_ID=`ec2-create-volume --snapshot $VOL | awk '{print $2'}`
ec2-attach-volume $VOL -i $myinstance -d $DEV
while [ ! -e $DEV ]; do
sleep 5;
let i++
if [ $i -gt 10 ]; then
echo "exceeded attempts waiting for device $DEV"
exit 1
fi
fi
Caveats
You must configure both the ec2 and autoscaling api tools as a prerequisite.
This process may not be well suited for publishing data that changes frequently.
In an ideal world, the /release volume on the deployment host would be unmounted before snapshotting.
There is a potential race condition here if code is being published during an autoscale event.
Programming examples have been simplified for clarity. An implementation of this architecture will require a non-trivial amount of code and operating system knowledge..
Please remember that most ec2/autoscaling commands accept --region REGION .