AMI web amb EC2, S3 i SimpleDB

Introducció

Avui vull parlar de com dissenyar un frontend per una plataforma web amb els serveis EC2, S3 i SimpleDB de Amazon Web Services.
El que farem serà crear una AMI que podrem utilitzar per aixecar instàncies EC2 web amb qualsevol aplicació web. Per això crearem un script d’arrancada que consultarà a SimpleDB les aplicacions que ha de configurar i el bucket de S3 d’on descarregar els codis font.
El disseny que explicaré és experimental i només ha estat provat en un entorn de proves. La idea és que la AMI resultant d’aquest tutorial es pugui fer servir com a plantilla per a que CloudWatch+AutoScaler aixequin automàticament instàncies darrera un ELB.

Requeriments i aclariments

Per seguir aquest tutorial necessitareu:

  • Coneixements d’administració de sistemes operatius Linux
  • Coneixements en enginyeria de software
  • Conèixer la terminologia de AWS
  • Un compte a AWS
  • Un client SSH (Si feis servir ubuntu, el que recomano, el client ja està instal·lat per defecte. Si feu servir Windows podeu fer servir PuTTy)
  • Una llibreta a ma per apuntar tots els passos que aneu fent. (Especialment recomanat!)

També és necessari que tingueu en compte que aquest disseny està pensat per plataformes web distribuïdes. Aquest frontend només servirà la capa lògica de la plataforma. En el cas de vancast webcasting studio fem servir RDS per la capa de dades i S3 per la capa de presentació.

Instància base

El primer pas és aixecar una instància base. En aquesta instància instal·larem tots els paquets que preveiem que faran servir les nostres aplicacions web i la configurarem adequadament.

Consell: Feu totes les proves que necessiteu sense por, amb la tranquil·litat que si cometeu un error irreversible sempre podeu apagar l’instància i tornar a començar. Per això recomano que aneu apuntant tots els passos que feu, així us serà més fàcil tornar a començar si us equivoqueu.

Escollir la instància base

Abans d’aixecar la instància haurem de triar una AMI. En el meu cas vaig triar la AMI ami-f60e3c82 amb Ubuntu Lucid 10.04 LTS 32bits i sistema de storage de tipus Internal Storage. Vaig triar aquesta perquè:

  • Estic més familiaritzat amb la distribució Ubuntu.
  • M’agrada més la implementació d’Apache que hi ha al repositori de paquets apt-get.
  • Els repositoris tenen més paquets (incloent les ec2 tools) que el yum de les AMIs Amazon Linux AMI no té
  • Vaig escollir la versió Lucid perquè és una Long Term Support
  • No vaig escollir sistema de storage EBS (més persistent) perquè amb aquest disseny les instàncies web no tindran bases de dades ni guardaran continguts dels usuaris, per tant no és necessari un EBS
  • 32 bits perquè ens permetrà escollir el tipus d’instànica m1.small. Si implementem bé CloudWatch i AutoScaler, no necessitem més màquina, ja que la idea és fer un escalament horitzontal automàtic

Posar en marxa la instància

Per arrencar la instància podeu fer-ho a través de la vostra consola fent click aquí. Si teniu instal·lat les APIs tools de EC2 (si no les teniu aquí teniu ajuda per fer-ho) ho podeu fer executant les següents comandes:

# create the key pair
$ ec2-add-keypair keypair

#create a security group called ‘web-group’
$ ec2-add-group web-group -d ‘Web public frontnd web’
$ ec2-authorize web-group -P tcp -p 22 -s 0.0.0.0/0
$ ec2-authorize web-group -P tcp -p 80 -s 0.0.0.0/0
$ ec2-authorize web-group -P tcp -p 81 -s 0.0.0.0/0
$ ec2-authorize web-group -P tcp -p 443 -s 0.0.0.0/0

#launch an instance
$ ec2-run-instances ami-f60e3c82 
			--region eu-west-1 
			--instance-count 1 
			--instance-type m1.small 
			--key keypair 
			--group web-group 

Configurar la instància

Quan la instància s’hagi carregat accediu-hi mitjançant ssh. Per exemple amb ubuntu podeu executar:

ssh -i keypair.pem ubuntu@[ip/dns instància]

Una vegada connectats a la instància instal·larem tots els paquets i llibreries que necessitaran les nostres aplicacions web, com per exemple Apache, PHP, mòduls, etc. I també haurem d’instal·lar els paquets i llibreires dels servies de AWS que farem servir al script d’arrencada.

A partir d’aquest moment, la resta d’accions que es descriuen en aquest tutorial es faran directament a la instància.

ec2-api-tools i ec2-ami-tools

Els paquets ec2-api-tools i ec2-ami-tools són les col·leccions de comandes necessàries per executar la API de EC2. Ho instal·lem executant les següents comandes:

sudo apt-add-repository ppa:awstools-dev/awstools
sudo apt-get update
sudo apt-get install ec2-api-tools

s3curl

s3crul és un script que es farà servir per descarregar fitxers dels buckets del compte de AWS. El podeu descarregar del portal de desenvolupadors de Amazon: http://aws.amazon.com/code/128 El script necessita el Account ID y el Account Secret Key per autentificar-se. Aquests paràmetres els obté cercant al home de l’usuari que executa el script un arxiu anomenat .s3curl. Exemple de l’arxiu .s3curl:

%awsSecretAccessKeys = (
    # personal account
    personal => {
        id => '1ME55KNV6SBTR7EXG0R2',
        key => 'zyMrlZUKeG9UcYpwzlPko/+Ciu0K2co0duRM3fhi',
    },

   # corporate account
   company => {
        id => '1ATXQ3HHA59CYF1CVS02',
        key => 'WQY4SrSS95pJUT95V6zWea01gBKBCL6PI0cdxeH8',
    },
);

Així doncs un exemple de com descarregar un arxiu amb s3curl podria ser aquest:

./s3curl --id company -- https:/s3.amazonaws.com/[bucket_name]/[file]

Però aquest mètode té un problema. Nosaltres voldrem fer servir aquesta comanda en un script d’arrencada; però els scripts d’arrencada no s’executen per cap usuari, són executats per el sistema i per tant, quan s3curl intenti cercar el directori HOME no trobarà res i per tant no podrà carregar les credencials. L’alternativa és executar s3curl d’aquesta manera:

.s3curl.pl --id 1ATXQ3HHA59CYF1CVS02
--key WQY4SrSS95pJUT95V6zWea01gBKBCL6PI0cdxeH8
-- https:/s3.amazonaws.com/[bucket_name]/[file]

SimpleDB Client

Per instal·lar el client SimpleDB podeu seguir les següents passes:

  1. Instal·lar llibreries ssl
    apt-get install libssl-dev
  2. Instal·lar les dependències PERL
    sudo perl -MCPAN -e ‘install Digest::SHA’
    sudo perl -MCPAN -e ‘install XML::Simple’
    sudo perl -MCPAN -e ‘install Bundle::LWP‘
    sudo perl -MCPAN -e ‘install Crypt::SSLeay
    sudo perl -MCPAN -e ‘install Getopt::Long’
    sudo perl -MCPAN -e ‘install Pod::Usage’
    sudo perl -MCPAN -e ‘install Digest::SHA1’
    sudo perl -MCPAN -e ‘install Digest::HMAC’
  3. Baixar la llibreria PERL
    wget http://aws-libraries.s3.amazonaws.com/perl/AmazonSimpleDB/2009-04-15/AmazonSimpleDB-2009-04-15-perl-library.zip
  4. Instal·lar la llibreria
    unzip AmazonSimpleDB-2009-04-15-perl-library.zip
    sitelib=$perl -MConfig -le ‘print $Config{sitelib}’)
    sudo scp -r AmazonSimpleDB-*-perl-library/src/Amazon $sitelib
    sudo curl -Lo /usr/local/bin/simpledb http://simpledb-cli.notlong.com
    sudo chmod +x /usr/local/bin/simpledb

Script

La clau d’aquest disseny és el script d’arrencada. Hem d’aconseguir que la instància quan s’arrenqui sigui capaç de configurar les aplicacions web que necessitem automàticament. Per fer això farem servir el tàndem SimpleDB i S3:

  • A S3 desarem els codis fonts de les nostres aplicacions en un arxiu comprimit.
  • A SimpleDB desarem els noms de domini que tindrà cada aplicaició i la URL al seu respectiu arxiu comprimit. L’estructura d’un script d’arrencada és la següent:
#!/bin/bash
### BEGIN INIT INFO
# Provides:             web-logic-layer
# Required-Start:       $network
# Required-Stop:        $apache2
# Should-Start:         $named
# Should-Stop:
# Short-Description:    ec2 web setup
# Description:          Download logical layer for webapp

#
# ec2-elastic - do som ec2 housekeeping (Dowlonad logic layer)
#
#

#start/stop functions for OS
start(){

}
stop(){

}
case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                sleep 5
                start
                ;;
        *)
                echo "Usage $SELF {start|stop|restart}"
                exit 1
                ;;
esac

Per tant, és molt senzill només hem d’implementar les funcions start i stop.

Variables d’entorn i constant de programa

Abans de començar a implementar les funcions anem a vuere quines variables necessitem inicialitzar al principi del script:

export JAVA_HOME=/usr/lib/jvm/java-6-openjdk/
export EC2_KEY_DIR=/home/ubuntu/.aws/x.509
export EC2_PRIVATE_KEY=${EC2_KEY_DIR}/pk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem
export EC2_CERT=${EC2_KEY_DIR}/cert-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem
export AWS_ACCESS_KEY_ID='XXXXXXXXXXXXXXXXXXXX'
export AWS_SECRET_ACCESS_KEY='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
export AWS_ACCOUNT_ID='xxxx-xxxx-xxxx'
export AWS_CANONICAL_USER_ID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
export S3CURL_PATH="/home/ubuntu/.aws/s3-curl"
export PATH="$S3CURL_PATH:$PATH"

prog=$(basename $0)
logger="logger -t $prog"
domains_folder="/home/ubuntu/domains"
curl="curl --retry 3 --silent --show-error --fail"
instance_data_url="http://169.254.169.254/latest"
apps_file="$domains_folder/.installedapps"
simpledb_domain="FrontendApps"

En el primer bloc declarem totes les variables d’entorn que necessitarem per executar les eines de EC2 i SimpleDB. Seguidament, s’inicialitzen les variables que necessitaran les funcions. Destacarem dues:

apps_file="$domains_folder/.installedapps"
simpledb_domain="FrontendApps"

La variable apps_file indica un arxiu anomenat .installedapps on desarem el llistat d’aplicacions que es carreguin. Com volem que el script carregui unes aplicacions determinades, també ens interessarà que aquest script sigui capaç de desintal·lar-les. Farem servir l’arxiu .instaleldapps per desar el llistat d’aplicacions instal·lades en el moment d’execució del script; així quan vulguem desinstal·lar de la instància les aplicacions farem servir la funció stop que llegirà l’arxiu i esborrarà les aplicacions registrades.
La variable simpledb_domain indica el nom del domini que hem de llegir del nostre compte de SimpleDB, més endavant veurem com donar d’alta el domini i com alimentar les dades.

Funció start

La funció start serà l’encarregada de consultar a simpleDB el llistat d’aplicacions i una a una, baixarà el seu codi font de S3 i la instal·larà a la instància. Veiem el codi:

start(){
	#Create domains folder
	mkdir -p $domains_folder
	apps=$(simpledb select "select id from $simpledb_domain")
        #Get instance id
        instance_id=$($curl $instance_data_url/meta-data/instance-id)
	#Create installed apps reg file
	now=$(date)
	echo "#Vancast Webcasting Studio Front-end instance: $instance_id" > $apps_file
	echo "#Creation date: $now" >> $apps_file
	#Stops apache service during de apps load process
	service apache2 stop | $logger
	#Loop apps list
        for app in $apps
        do
		#Get source url and sources file name
		temp_bucket=$(simpledb get $simpledb_domain $app bucket)
		temp_key=$(simpledb get $simpledb_domain $app key)
		src_bucket=`expr match "$sources" '.*sources=(.*)'`
		src_key=`expr match "$sources" '.*srcfile=(.*)'`
		#Construct app folder
                folder="$domains_folder/$app"
                #Create wep app folder
                mkdir -p $folder
                #Download logic layer
                cd $folder
                s3curl.pl --id AKIAJIYYTHE6ZJYGNG3A --key fCGgKyyz/fuy/8MuU94Sng1NOaosHGhC6161xCUa -- $src_bucket/$src_key > $src_key | $logger
                tar -xf $folder/$src_key | $logger
                rm $folder/$src_key | $logger
                chown -R ubuntu:www-data $folder | $logger
                chmod -R 775 $folder | $logger
                #Create virtual host file
                cp $folder/apache/$app /etc/apache2/sites-available | $logger
                #Change to apache enabled sites folder
 		cd /etc/apache2/sites-enabled/
                #Create site's symbolic link
                ln -s ../sites-available/$app $app | $logger
                #Execute app auto installer
                php $folder/public_html/autoinstaller.php
                #Remove auto installer
                rm $folder/public_html/autoinstaller.php
		#Registry app into apps file
		echo $app >> $apps_file
        done
        #Start apache service
        service apache2 start | $logger
}

Estudiem en detall les passes que realitza aquesta funció:

  1. Primer s’assegura que el directori on es copiaran tots els codis font existeixi
    mkdir -p $domains_folder
  2. Després, obté un array amb els noms de les aplicacions de SimpleDB
    apps=$(simpledb select "select id from $simpledb_domain")
  3. Obtenim el identificador de la instància mitjançant una crida a un servei que tenen totes les instàncies EC2. Per això fem servir la comanda curl.
    #Get instance id
    instance_id=$($curl $instance_data_url/meta-data/instance-id)
  4. Creem l’arxiu .installedapps. Hi escrivim uns comentaris i el identificador de la instància per facilitar el manteniment.
    #Create installed apps reg file
    now=$(date)
    echo "#Smart Front-end instance: $instance_id" > $apps_file
    echo "#Creation date: $now" >> $apps_file
  5. Per cada aplicació de la llista obtenim de SimpleDB la url del bucket de S3 i el nom de l’arxiu que conté els codis fonts.
    #Get source url and sources file name
    temp_bucket=$(simpledb get $simpledb_domain $app bucket)
    temp_key=$(simpledb get $simpledb_domain $app key)
    src_bucket=`expr match "$sources" '.*sources=(.*)'`
    src_key=`expr match "$sources" '.*srcfile=(.*)'`
  6. Creem el directori on instal·larem l’aplicaicó.
    #Construct app folder
    folder="$domains_folder/$app"
    #Create wep app folder
    mkdir -p $folder
  7. Baixem de S3 l’arxiu que conté la capa lògica de l’aplicació. Per això fem servir la comanda .s3curl. El descomprimim amb tar.
    #Download logic layer
    cd $folder
    s3curl.pl --id AKIAJIYYTHE6ZJYGNG3A --key fCGgKyyz/fuy/8MuU94Sng1NOaosHGhC6161xCUa -- $src_bucket/$src_key > $src_key | $logger
    tar -xf $folder/$src_key | $logger
    rm $folder/$src_key | $logger
  8. Canviem els permisos, l’usauri i el grup per a que apache pugui executar els arxius.
    chown -R ubuntu:www-data $folder | $logger
    chmod -R 775 $folder | $logger
  9. Creem el virtualhostde l’aplicació. Per això copiem un arxiu que prèviament hem afegit a l’arxiu de codis font.
    #Create virtual host file
    cp $folder/apache/$app /etc/apache2/sites-available | $logger
    #Change to apache enabled sites folder
    cd /etc/apache2/sites-enabled/
    #Create site's symbolic link
    ln -s ../sites-available/$app $app | $logger
  10. Dins del codi font podem incloure un arxiu que en ser executat realitza tasques d’instal·lació més vinculades amb la funcionalitat de l’aplicació. En aquest cas, fem servir PHP i l’arxiu s’anomena “autoinstaller.php”.
    #Execute app auto installer
    php $folder/public_html/autoinstaller.php
    #Remove auto installer
    rm $folder/public_html/autoinstaller.php
  11. Desem l’aplicació a l’arxiu .installedapps
    #Registry app into apps file
    echo $app >> $apps_file
  12. Quan ja s’han instal·lat totes les aplicacions iniciem el serveri apache.
    #Start apache service
    service apache2 start | $logger

Funció stop

#Stop apache service during the unload process
service apache2 stop | $logger
while read LINE
do
	comment=`expr match "$LINE" '(^#)'`
	if [ ! -n "$comment" ]; then
		rm /etc/apache2/sites-*/$LINE | $logger
	fi
done < $apps_file
rm -Rf $domains_folder
#Start apache service
service apache2 start | $logger

La funció stop és molt senzilla. L’únic que fa és llegir l’arxiu .installedApps i esborrar tots els directoris i fitxers de les aplicacions instal·lades, així com els seus respectius arxius de virtualhost.

Funció restart

La funció restart l’únic que fa és executar la funció stop e immediatament després la funció start. Pot ser útil per reinstal·lar o actualitzar les aplicacions d’una instància en funcionament.

Instal·lar script d’arrencada

Quan ja tenim el script acabat toca dir-li al sistema operatiu que aquest existeix i en quins moments del procés d’arrencada del sistema ha d’executar-se la funció start i en quin moment ha d’executar-se la funció stop.

Per això podem fer servir un programa anomeant update-rc.d. Si no el teniu instal·lat proveu de cercar al repositori.

El que primer farem és crear un enllaç simbòlic del scritp al directori init.d

$ cd /etc/init.d
$ sudo ln -s [script_path]/[script] ec2-setup

Ara la comanda update-rc-d ja reconeixerà el script. Executem la següent comanda:

$ sudo update-rc.d ec2-setup start 30 2 3 4 5 stop 70 0 1 6

Els valors 30 i 70 indiquen la prioritat (nombre més baix = més prioritari). En aquest exemple hem dit que en el llistat d’accions a executar en els procesos 2, 3, 4 i 5 (arrencada), el nostre script tingui una prioritat de 30. I en el cas dels processos 0, 1 i 6 (aturada) volem que estigui en prioritat 70. El recomanable és que si li donem una prioritat alta en els processos d’arrencada, en els processos d’aturada li donem baixa. Un truc és fer que els nombres sumin 100 (30 + 70).

Arxius d’instal·lació

Per a que el script sigui capaç de desempaquetar i instal·lar les aplicacions haurem de definir una estructura i format de l’arxiu comprimit que contindrà els codis font de les aplicacions.
En el meu cas vaig decidir fer servir tar.gz com a format de compressió i dins de l’arxiu la següent estructura de directoris:

  1. public_html: En aquest directori es troben els programes de l’aplicació així com el “autoinstall” que es cridat un cop s’ha instal·lat l’aplicació; s’encarrega de configurar parámetres de l’aplicació que depenen del servidor on és instal·lada.
  2. apache: Aquest directori contindrà sempre un arxiu amb les dades del virtualhost de l’aplicació. Aquest arxiu tindrà el nom de domini de l’aplicació; per exemple, “apache/www.example.com”.
En aquest post no parlaré de com crear virtualhosts per apache, però us deixo un exemple bàsic d’arxiu virtualhost:

        ServerAdmin admin@example.com
        ServerName www.example.com
        DocumentRoot /home/ubuntu/domains/www.example.com/public_html
        SetEnv DB_DSN mysql://admin:adminpass@mysql.example.com/example_db

Els arxius comprimits de les aplicacions els pujarem a S3. Podeu fer servir la consola de AWS o la comanda s3curl.

Domini de SimpleDB

Per a poder inserir dades a SimpleDB el que primer hem de fer és crear un domini. Per fer-ho executem la següent comanda:

$ sudo simpledb create-domain FrontendApps

Recordeu que el nom que trieu per el domini l’haureu de posar com a valor de la variable simpledb_domain en el script d’arrencada.

Donar d’alta una nova aplicació

Per a que tot aquest sistema funcioní hem de tenir un Bucket de S3 amb la capa lògica comprimida en un arxiu tar.gz i el seu equivalent registre en el domini de SimpleDB.
Veiem com podem donar d’alta una nova aplicació al domini de front-ends:

simpledb put FrontendApps www.example.com bucket=https://s3.amazon.com/BUCKET/STABLE key=sources.tar.gz

Creació de la AMI

Ja ho tenim tot enllestit per crear la AMI. Crear una AMI ho podem definir com fer una fotografia d’una instància que farem servir com a plantilla per crear instàncies iguals.
Això vol dir que, virtualment, tenim un nombre infinit de màquines disponibles per estar operatives al instant i configurades segons les nostres necessitats.
Crear una AMI per una instàcia amb sistema d’emmagatzemament  Internal Storage és diferent al de les instàncies EBS. El procés consisteix en tres passes:
  1. Crear un bundle del disc de la instància:
    sudo mkdir /mnt/[ami_name]
    sudo ec2-bundle-vol -u XXXX-XXXX-XXXX
    -c ~/.aws/x.509/cert-XXXXXXXXXXXXXXXXXXXX.pem
    -k ~/.aws/x.509/pk-XXXXXXXXXXXXXXXXXXXXXX.pem
    -r i386 -d /mnt/[ami-name] -p [ami_name]

    Es un procés que acostuma a trigar uns minuts. Tingueu paciència tot i que us sembli que s’ha quedat encallat.

  2. Pujar el bundle a S3.
    ec2-upload-bundle -a XXXXXXXXXXXXXX -s xxxxxxxxxxxxxxxxxxxxxxxxxxx
    --location EU
    -b [destination_bucket]
    -m [manifest_path]
    
  3. Registrar la AMI
    ec2reg [destination_bucket]/[manifest]
    -n "[Ami name]"
    -d "[AMI description]"
    -a i386
    --region eu-west-1
    

Si tot va bé ja tindrem una AMI preparada per aixecar instàncies iguals a la instància que hem configurat.

Consell: Abans de procedir amb la creació de la AMI és molt aconsellable que netejeu tots els arxius i programes que heu generat a les proves i que sabeu que no es faran servir.

Com fer servir la AMI Web front-end

Fins ara hem vist com crear una instància i configurar-la per allotjar front-ends de plataformes web amb un script que és capaç de consultar a SimpleDB un llista d’aplicacions i baixar la seva capa lògica de S3 per després instal·lar-les i crear-ne el seu virtualhost corresponent per Apache.
A partir d’aquesta instància hem creat una AMI, és a dir una plantilla, que és capaç de crear instàncies idèntiques a la que hem creat, incloent el script d’arrencada. I per tant amb el mateix comportament.

I quin és el potencial de tot això? Si tenim una plataforma distribuïda el potencial és molt gran. Ens permet tenir un llistat d’aplicacions i la seva capa lògica pujada a S3, crear una instància a partir de la AMI, la qual automàticament descarregarà i configurarà les aplicacions, però si a més, configurem CloudWatch i AutoSacler juntament amb un ELB, podem aconseguir que si aquesta instància es veu en compromís, ja sigui perquè falla o perquè no pot aguantar la càrrega, s’aixequin instàncies idèntiques i el ELB s’ajusti per desviar l’excés de càrrega cap a les noves instàncies amb la garantia de que les instàncies tindran la configuració i versió adients per començar a funcionar immediatament després d’haver-se creat. I tot això sense cap intervenció manual.

Anuncis

Deixa un comentari

Fill in your details below or click an icon to log in:

WordPress.com Logo

Esteu comentant fent servir el compte WordPress.com. Log Out / Canvia )

Twitter picture

Esteu comentant fent servir el compte Twitter. Log Out / Canvia )

Facebook photo

Esteu comentant fent servir el compte Facebook. Log Out / Canvia )

Google+ photo

Esteu comentant fent servir el compte Google+. Log Out / Canvia )

S'està connectant a %s