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:
- Instal·lar llibreries ssl
apt-get install libssl-dev
- 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’
- Baixar la llibreria PERL
wget http://aws-libraries.s3.amazonaws.com/perl/AmazonSimpleDB/2009-04-15/AmazonSimpleDB-2009-04-15-perl-library.zip
- 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ó:
- Primer s’assegura que el directori on es copiaran tots els codis font existeixi
mkdir -p $domains_folder
- Després, obté un array amb els noms de les aplicacions de SimpleDB
apps=$(simpledb select "select id from $simpledb_domain")
- 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)
- 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
- 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=(.*)'`
- Creem el directori on instal·larem l’aplicaicó.
#Construct app folder folder="$domains_folder/$app" #Create wep app folder mkdir -p $folder
- Baixem de S3 l’arxiu que conté la capa lògica de l’aplicació. Per això fem servir la comanda
.s3curl
. El descomprimim ambtar
.#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
- 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
- Creem el
virtualhost
de 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
- 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
- Desem l’aplicació a l’arxiu
.installedapps
#Registry app into apps file echo $app >> $apps_file
- 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:
- 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.
- 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”.
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
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
- 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.
- Pujar el bundle a S3.
ec2-upload-bundle -a XXXXXXXXXXXXXX -s xxxxxxxxxxxxxxxxxxxxxxxxxxx --location EU -b [destination_bucket] -m [manifest_path]
- 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.