Nelle lezioni precedenti abbiamo visto come configurare il gruppo di istanze per la base di dati. In questo modo abbiamo lavorato sulla scalabilità delle informazioni che vengono persistite e lette dalla nostra applicazione. Ora dobbiamo creare uno strato di elaborazione che sia flessibile e scalabile in modo completamente automatizzato.
Possiamo arrivare a questo stadio perchè oramai tutte le informazioni sono state "terzializzate" a servizio così da permetterci di creare uno strato di elaborazione senza vincoli di persistenza e slegare le EC2 dalla conservazione di dati, ottenendo la possiblità di aggiungere e ridurre potenza di calcolo a seconda dello scenario che si crea.
Problemi legati alla scalabilità della base di dati
Poiché abbiamo diverse istanze database dobbiamo trovare una soluzione che permetta alla nostra applicazione di smistare:
- tutte le operazioni di scrittura,
UPDATE
,INSERT
eDELETE
verso l'instanza master; - le operazioni di lettura,
SELECT
verso una serie di altre macchine a scelta, o anche il master stesso se vogliamo.
È uno scenario complesso, infatti se controlliamo i prototipi di funzione che ci sono messi a disposizione non esiste la possibilità di collegarsi su diverse macchine:
PDO::__construct() ( string $dsn [, string $username [, string $password [, array $driver_options ]]] )
resource mysql_connect ([ string $server = ini_get("mysql.default_host") [, string $username = ini_get("mysql.default_user") [, string $password= ini_get("mysql.default_password") [, bool $new_link = false [, int $client_flags = 0 ]]]]] )
mysqli::__construct() ([ string $host = ini_get("mysqli.default_host") [, string $username = ini_get("mysqli.default_user") [, string $passwd = ini_get("mysqli.default_pw") [, string $dbname = "" [, int $port = ini_get("mysqli.default_port") [, string $socket = ini_get("mysqli.default_socket")]]]]]] )
Come possiamo vedere nessuno dei precedenti si occupa di gestire un impianto configurato con l'uso di Read Replica. Ciò significa che dobbiamo trovare una soluzione che ci permetta di utilizzare la nostra applicazione anche con un'infrastruttura complessa. Per questo possiamo utilizzare un componente particolare che si chiama: MySQL Native Driver for PHP. È disponibile dalla versione 5.3.3 in avanti ed è quello che utilizzeremo per astrarre la nostra configurazione.
Il native driver si sostituisce a "libmysql" che tipicamente è utilizzata durante la "compilazione" di PHP, così facendo possiamo utilizzare questa libreria che supporta la configurazione master/slave.
Prima di tutto dobbiamo ricordarci di compilare con il supporto a "mysqlnd
", in pratica durante la configurazione di PHP:
--with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo=mysqlnd
A questo punto dobbiamo delegare a "mysqlnd_ms
" la gestione del master/slave. In pratica si utilizza una configurazione JSON ed il percorso viene specificato nel "php.ini
" o un metodo equivalente, vediamo un esempio:
mysqlnd_ms.enable = 1
mysqlnd_ms.config_file = /path/to/mysqlnd_ms_plugin.json
Il file di configurazione è così composto:
{
"myapp": {
"master": {
"master_0": {
"host": "localhost",
"socket": "\/tmp\/mysql.sock"
}
},
"slave": {
"slave_0": {
"host": "192.168.2.27",
"port": "3306"
}
}
}
}
Il file di configurazione è piuttosto intuitivo, la prima sezione configura il master ed una seconda invece si occupa degli slave. Il nome della configurazione, in questo caso: "myapp
" è utilizzata per la connessione, in pratica:
$conn = mysql_connect("myapp", "username" "password");
Grazie al "native driver" abbiamo in modo semplice ed efficace astratto la connessione alla base di dati accedendo ad un'infrastruttura diversa senza dover mettere mano al codice.
Preparazione dell'immagine AMI
Adesso abbiamo tutte le carte in regola per creare l'immagine e far partire la nostra applicazione. Non ci resta che configurare un template che sia abbastanza flessibile e riutilizzabile con i componenti dedicati all'elaborazione delle pagine web, quindi: Apache2, PHP5 configurati e pronti per ospitare la nostra applicazione WordPress.
Creare un'AMI completa di WordPress a bordo, per quanto sia il metodo più semplice è anche particolarmente sconsigliabile in quanto ogni volta che si vuole aggiornare un componente si deve ricreare il "bundle" e configurare nuovamente l'impianto per attivare queste nuove istanze.
Opteremo per una soluzione mista, ovvero configureremo il template di base per attivare un server web configurato ma senza applicazione, ed utilizzeremo il sistema chiamato "EC2_USER_DATA" per eseguire uno script di shell durante il boot della macchina virtuale.
Per la configurazione della macchina virtuale partiremo da un template di base che si trova nella "community" il cui id è: ami-2b44735f
.
Per costruire l'immagine non dobbiamo fare altro che avviare una nuova istanza basata su questa AMI così da poterla aggiornare e configurare con le nostre impostazioni e poi salvare questo nuovo template.
Per lavorare in modo utile, dobbiamo utilizzare due componenti fondamentali messi a disposizione da AWS proprio a questo scopo e sono: API tools ed AMI tools, entrambi strumenti per le EC2.
Una volta avviato questo template non dobbiamo fare altro che installare e configurare PHP, Apache2 e tutte le estensioni di cui abbiamo bisogno per la nostra applicazione WP, ricordandoci che il PHP deve essere configurato con il supporto a "mysqlnd
".
Dopo questi step siamo pronti a salvare l'immagine.
Per prima cosa dobbiamo spostare i nostri certificato e chiave privata (cert-*
e pk-*
che possiamo scaricare del nostro account utente su aws.amazon.com) sulla macchina. Utilizziamo la cartella "mnt
" a questo scopo così da essere sicuri con non finiscano nell'immagine: si tratta di una istanza "instance-store" ed il volume effimero è montato su "/mnt". Ora creiamo una cartella dove salvare l'immagine di questa macchina:
mkdir /mnt/ami-instance-name
Con il comando "ec2-bundle-vol
", questo particolare comando può metterci un poco di tempo a terminare:
ec2-bundle-vol -d /mnt/ami-instance-name -k /path/to/your/pk-(long string).pem -c /path/to/your/cert-(long string).pem -u YOUR_AMAZON_ACCOUNT_ID_WITHOUT_DASHES
Ora la nostra macchina virtuale è stata "fotografata", "esplosa" in diversi file ed aspetta solo di essere portata su un bucket S3 così da essere poi disponibile sulla console grafica di AWS. Per fare l'upload della macchina virtuale dobbiamo utilizzare il comando: "ec2-upload-bundle
":
ec2-upload-bundle -b bucket-ami -m /mnt/ami-instance-name/image.manifest.xml -a YOUR_AWS_ACCESS_KEY -s YOUR_AWS_SECRET_KEY
Da questo punto possiamo tranquillamente utilizzare la console grafica, andando nella gestione delle EC2, poi AMI e da qui utilizzare il pulsante "Register new AMI" per attivare questa nuova istanza come in figura:
Ora abbiamo a disposizione "instance-store" nuova e configurata. Il template di partenza che abbiamo utilizzato aveva già tutte le configurazioni per eseguire "on-boot" il file di configurazione passato come "EC2_USER_DATA", quindi in siamo pronti per utilizzare questa particolarità per scaricare, configurare e rendere disponibile live la nostra applicazione WordPress.
Non ci resta che preparare lo script di shell che configuri la macchina al boot. Iniziamo a pensare a cosa ci serve per avviare la nostra istanza:
- scaricare una versione di WP dal SVN
- scaricare il template nella cartella dedicata
- utilizzare il file di configurazione della nostra applicazione "wp-config.php"
- aggiungere i vari plugin di cui abbiamo bisogno
Un possibile script di avvio potrebbe essere il seguente:
#!/bin/bash
set -e -x
export DEBIAN_FRONTEND=noninteractive
YOUR_DOMAIN_NAME="www.my-domain.tld"
MEMCACHED_ADDR="a.cache.your-domain.tld"
MEMCACHED_PORT="11211"
echo session.save_handler = memcache >> /etc/php5/php.ini
echo session.save_path = "tcp://$MEMCACHED_ADDR:$MEMCACHED_PORT" >> /etc/php5/php.ini
echo mysqlnd_ms.enable = 1 >> /etc/php5/php.ini
echo mysqlnd_ms.config_file = /mnt/database/db-config.ini >> /etc/php5/php.ini
# Checkout WordPress application in /mnt/wordpress path
svn co http://core.svn.wordpress.org/tags/3.5.1 /mnt/wordpress
# Do similar steps for plugins and themes
# Use your personal svn repository to download your config
svn export http://svn.your-domain.tld/db-config.ini /mnt/database/db-config.ini --force
# Use your personal svn repository to download your WordPress configuration
svn export http://svn.your-domain.tld/wordpress/wp-config.php /mnt/wordpress/wp-config.php
# Create new VirtualHost
APACHE_HOST=/etc/apache2/sites-available/wordpress
touch $APACHE_HOST
echo "<VirtualHost *:80>" >> $APACHE_HOST
echo "ServerAdmin dev@your-domain.tld" >> $APACHE_HOST
echo "DocumentRoot /mnt/wordpress" >> $APACHE_HOST
echo "ServerName $YOUR_DOMAIN_NAME" >> $APACHE_HOST
echo "<Directory /mnt/wordpress>" >> $APACHE_HOST
echo "Options -Indexes FollowSymLinks" >> $APACHE_HOST
echo "AllowOverride All" >> $APACHE_HOST
echo "Order allow,deny" >> $APACHE_HOST
echo "allow from all" >> $APACHE_HOST
echo "</Directory>" >> $APACHE_HOST
echo "ErrorLog syslog:local7" >> $APACHE_HOST
echo "CustomLog \"|/usr/bin/logger -t apache2 -p local6.info\" combined" >> $APACHE_HOST
echo "</VirtualHost>" >> $APACHE_HOST
# Enable apache modules
a2enmod rewrite
a2enmod vhost_alias
a2enmod headers
a2enmod expires
a2enmod deflate
a2dismod autoindex
a2ensite wordpress
a2dissite default
# Restart Apache Server
/etc/init.d/apache2 restart
Nella prima parte dello script impostiamo alcune variabili che ci saranno utili dopo e configuriamo il file "php.ini
" aggiungendo lo stoccaggio delle sessioni sul nostro cluster memcached, precedentemente configurato.
Subito dopo aggiungiamo la configurazione per la gestione dei server master/slave MySQL tramite il connettore "mysqlnd
" analizzato in precedenza.
A questo punto scarichiamo dal SVN ufficiale la tag di WordPress che vogliamo utilizzare in produzione, e facciamo lo stesso per plugin e template. Da un nostro server SVN aziendale (GIT, Mercurial o altri sistemi è indifferente) scarichiamo anche il file "wp-config.php
" che contiene la configurazione della nostra applicazione ed anche la configurazione master/slave vista nella sezione dedicata al "native driver" di MySQL.
Non resta che configurare Apache creando un Virtual Host dedicato alla nostra applicazione, attivare i vari moduli che possono esserci utili e poi riavviare il server web così da renderlo disponibile al pubblico.
Ora che abbiamo lo script di shell, possiamo lavorare sull'autoscaling.