Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps

Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps - Relazione

Universit`a degli Studi di Trieste
Dipartimento di Ingegneria e Architettura
Corso di Studi in Ingegneria Informatica
Tesi di Laurea Triennale
Progetto e implementazione di una pipeline di
sviluppo software con tecnologie DevOps
Laureando:
Mattia Milleri
Relatore:
prof. Francesco Fabris
Correlatore:
ing. Sergio Benedetti
ANNO ACCADEMICO 2015–2016
Indice
Introduzione 3
1 Strumenti DevOps 5
1.1 Vagrant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Confronto sistemi provisioning . . . . . . . . . . . . . . . . . 6
1.2.1 Ansible . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.2 Chef . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.3 Puppet . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4 Tabella di confronto sistemi provisioning . . . . . . . . 8
1.3 Jenkins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2 Pipeline di sviluppo 11
2.1 Applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2 Configurazione Jenkins . . . . . . . . . . . . . . . . . . . . . . 12
2.3 Architettura del sistema . . . . . . . . . . . . . . . . . . . . . 13
2.4 Stage 1 - Build Tests . . . . . . . . . . . . . . . . . . . . . . . 14
2.4.1 Configurazione Vagrant . . . . . . . . . . . . . . . . . 15
2.4.2 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 16
2.5 Stage 2 - Stress Tests . . . . . . . . . . . . . . . . . . . . . . . 16
2.5.1 Configurazione Vagrant . . . . . . . . . . . . . . . . . 16
2.5.2 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.3 Test con JMeter e Selenium . . . . . . . . . . . . . . . 17
2.6 Stage 3 - Deploy su Google Cloud . . . . . . . . . . . . . . . . 18
2.6.1 Configurazione Google Cloud . . . . . . . . . . . . . . 19
2.6.2 Configurazione Vagrant . . . . . . . . . . . . . . . . . 19
2.6.3 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 20
Conclusioni 22
Codice sorgente 23
Jenkinsfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Vagrantfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Ansible - playbook-stage1.yml . . . . . . . . . . . . . . . . . . . . . 29
Ansible - playbook-stage2.yml . . . . . . . . . . . . . . . . . . . . . 31
1
Ansible - playbook-stage3.yml . . . . . . . . . . . . . . . . . . . . . 34
2
Introduzione
Il lavoro di tesi formalizzato in questo documento `e stato eseguito presso
Esteco SPA. L’ambito `e quello dello sviluppo di applicazioni in ambiente
web.
Lo scopo del lavoro `e quello di automatizzare completamente tutta la
pipeline di sviluppo di una applicazione web, a partire dalla compilazione e
fino alla messa in produzione, utilizzando degli strumenti DevOps.
Cos’`e una pipeline di sviluppo?
Una pipeline di sviluppo `e la rappresentazione di tutti i passi del percorso
cui un software `e assoggettato prima di poter arrivare in produzione.
Per ovvii motivi si ha l’esigenza di automatizzare tutto il percorso; ci`o
risponde alle seguenti richieste, necessarie per avere un’applicazione stabile
e sicura:
• se devono esserci dei fallimenti in un qualche punto della pipeline,
`e importante avere dei test che falliscono presto, in modo da poter
reagire tempestivamente agli errori, nei vari test di validazione, di
stress e di usabilit`a;
• togliere la componente di errore umano nella fase di installazione. Te-
st, configurazioni e installazioni vengono eseguite sempre esattamente
nello stesso modo;
• avere la certezza dell’uguaglianza fra le varie macchine di test e di
produzione. Essendo create in modo automatico a partire da uno
script esse saranno sempre identiche;
• rendere la preparazione dell’ambiente e l’installazione dell’applicazione
qualcosa di ”programmabile”; in questo modo, una volta creato lo
script, tutti possono eseguirlo, non `e pi`u necessario fare affidamento
su una singola persona che era l’unica a conoscere come procedere con
l’installazione.
3
Cosa si intende con strumenti DevOps?
DevOps `e un termine coniato nel 2009 da Patrick Debois; esso descrive un
insieme di pratiche volte ad aiutare la collaborazione fra quelli che sono i
due maggiori agenti nel processo di sviluppo di una applicazione: gli svilup-
patori (DEVelopers) da una parte e la parte di amministrazione di sistemi
(OPerationS) dall’altra.
Il risultato di tale approccio `e una forte automazione del processo pro-
duttivo, che permette di velocizzare e rendere pi`u affidabile la messa in
produzione di un’applicazione.
Con strumenti DevOps indichiamo quindi tutte quelle applicazioni che
permettono di automatizzare le operazioni di amministrazione di sistema.
Nei prossimi capitoli esamineremo nel dettaglio la struttura della pipeline
e il funzionamento degli strumenti necessari per realizzarla.
4
Capitolo 1
Strumenti DevOps
In questo capitolo descriveremo brevemente il funzionamento degli strumenti
di automazione DevOps che andremo ad utilizzare in seguito all’interno della
pipeline.
1.1 Vagrant
Vagrant `e un programma creato nel 2010 da Mitchell Hashimoto e permette
la creazione e manutenzione di macchine virtuali.
La costruzione di una macchina virtuale `e interamente formalizzata al-
l’interno di uno script, detto Vagrantfile, che permette di descrivere le ca-
ratteristiche richieste all’interno di quest’ultima.
Vagrant `e caratterizzato da 3 componenti principali, che entrano in gioco
in successione nella creazione della macchina virtuale.
Il primo sono le Vagrant Box.
Ogni macchina virtuale viene generata a partire da una certa immagi-
ne, detta Vagrant Box, che costituisce la base con il sistema operativo
che andremo ad utilizzare come fondamenta nella costruzione.
Esistono varie Box pronte all’uso che possono essere scaricare diretta-
mente dal sito di Vagrant. Solitamente queste sono create e messe a
disposizione da altri utenti o direttamente dal produttore del sistema
operativo, a meno che non richiedano licenze particolari a pagamento,
come nel caso di Windows o MacOS.
Alternativamente, se dovessero esserci esigenze o prerequisiti partico-
lari, `e sempre possibile creare una Box a partire da macchina virtuale
preesistente.
Il secondo sono i Providers.
5
Il Provider `e il sistema utilizzato nella creazione della macchina vir-
tuale. Quello di default `e VirtualBox, ma tramite un sistema di plugin
`e possibile ottenere il supporto per altri provider, come ad esempio
VMware, Google Cloud o Amazon AWS.
Il terzo sono i Provisioners.
I Provisioners sono gli strumenti che si occupano di configurare auto-
maticamente la macchina in un certo modo una volta creata.
Oltre alla possibilit`a di fornire direttamente comandi di shell, esiste il
supporto anche a strumenti pi`u avanzati, fra i quali cito Ansible, Chef
e Puppet che esamineremo in seguito.
1.2 Confronto sistemi provisioning
In questa sezione descriveremo tre diversi sistemi di provisioning: Ansible,
Chef e Puppet.
Confronteremo fra loro le diverse caratteristiche di ognuno, decidendo
infine qual `e tra questi lo strumento migliore, cio`e quello che si adatta meglio
ai requisiti del nostro progetto.
1.2.1 Ansible
Ansible `e un sistema di automazione open-source che permette il provisio-
ning e la configurazione remota di macchine virtuali oltre all’installazione di
applicazioni web.
Come la maggior parte dei sistemi di provisioning, Ansible riconosce una
architettura a due livelli, composta da una macchina di controllo e dai nodi.
La caratteristica principale di Ansible `e la sua architettura agentless, che
non richiede installazione di client sui nodi da gestire.
Il funzionamento `e determinato da un Inventory, che contiene tutte le
informazioni riguardo ai nodi da gestire pi`u tutte le operazioni da eseguire
su ogni singolo nodo.
Il Playbook che contiene le operazioni da eseguire sui nodi non `e un
vero `e proprio script, `e invece la descrizione di uno ”stato” che la macchina
deve avere. In base allo stato attuale della macchina verranno decretate
quali fra le tante operazioni descritte vanno eseguite per raggiungere lo stato
desiderato, e di conseguenza, i moduli relativi alle operazioni che verranno
inviati ed eseguiti sui vari nodi.
La comunicazione fra i il nodo di controllo e quello da controllare avviene
tramite il protocollo SSH: una volta avvenuta la connessione il server di
controllo invia dei moduli all’altro che vengono successivamente eseguiti.
6
1.2.2 Chef
Chef `e uno strumento open-source di gestione della configurazione e provi-
sioning.
Utilizza una architettura a 3 strati composta da:
Chef DK Il Chef Development Kit va installato su una workstation che
sar`a utilizzata per la creazione dei vari script di configurazione ed
installazione da eseguire sui nodi.
Chef Server Agisce come server di controllo e contiene sia tutte le informa-
zioni relative ai nodi da controllare che i ”Cookbook” con le operazioni
da eseguire sui singoli nodi.
Chef Client Deve essere in esecuzione su ogni nodo controllato, esegue un
polling periodico sul server di controllo, se trova delle differenze le
scarica e aggiorna il nodo allo stato definito dai Cookbook.
Alternativamente alla modalit`a client / server, pu`o essere anche eseguito
in modalit`a standalone ”chef-solo” direttamente sul nodo da controllare.
La comunicazione fra il server e il client `e regolata da un protocollo
proprietario. Viene utilizzata una coppia di chiavi RSA per l’autenticazione,
questo previene che un nodo possa accedere a dati che non lo pertengono e
assicura che vengano gestiti solo i nodi registrati.
1.2.3 Puppet
Puppet `e uno strumento open-source per la gestione della configurazione del
software.
Sfrutta un linguaggio dichiarativo proprietario per la descrizione della
configurazione dei nodi.
Utilizza una struttura client / server, composta da:
Puppet Master `e il server con tutte le istruzioni, detti ”Manifests”, per
la configurazione dei nodi.
Puppet Agent `e il client da installare su ogni nodo, si collega al server,
recupera le configurazioni e le installa, comunicando il risultato al
server.
Puppet DB `e una parte opzionale della struttura che affianca il server e
salva molte informazioni aggiuntive riguardo ai nodi e all’esecuzione
di ogni operazione.
La comunicazione fra client `e server avviene tramite Facter. Facter `e
una libreria di profiling che comunica via protocollo HTTPS con il server,
fornendogli informazioni relative al client come sistema operativo, IP e confi-
gurazione attuale. Il server quindi risponde con la configurazione desiderata
7
e fornisce i comandi specifici che l’agente del client dovr`a eseguire in base al
sistema operativo presente sul nodo.
Essendo la comunicazione basata su HTTPS sar`a necessario configurare
dei certificati SSL, sia per il server che per il client, per autorizzare lo scambio
di informazioni fra le varie parti.
1.2.4 Tabella di confronto sistemi provisioning
In questa tabella confronteremo i tre sistemi di provisioning appena descritti
in base alle caratteristiche ritenute pi`u importanti in riferimento al nostro
progetto.
ANSIBLE CHEF PUPPET
In questi test tutti e 3 i sistemi di provisioning sono utilizzati
a partire da una virtual machine Ubuntu 16.04 LTS “Xenial
Xerus” 64 bit creata con Vagrant.
Community La community `e molto nutrita in tutti e tre i casi. Que-
sto garantisce che esister`a un certo livello di supporto per i
plugin in futuro.
Ansible Galaxy Chef
Supermarket
Puppet Forge
Numero
”ricette”
presenti
9713 3163 4716
Esistono molti duplicati per ogni singola ricetta, perch´e ma-
gari lo stesso modulo viene creato da molti autori diver-
si o con minime variazioni per risolvere problemi specifici.
Un maggior numero di ricette non `e quindi necessariamente
indice di maggior qualit`a delle ricette stesse o di maggior
copertura software.
Il numero di ricette per Windows o MacOS `e notevolmente
inferiore al numero di ricette per Linux.
Linguaggio Open source,
Python
Open source,
Ruby
Open source,
Ruby
Linguaggio
di configu-
razione e
scripting
Playbook scritti in
YAML (Human
Readable)
Recipes e Coo-
kbooks scritti in
Ruby, ma non c’`e
necessit`a di cono-
scere il linguaggio
per crearne uno
Manifests scritti
in Puppet langua-
ge
Architettura Agentless Client / Server +
Workstation con
ChefDK per la
creazione delle ri-
cette
Client / Server
8
Modo di
funziona-
mento
Task eseguiti se-
quenzialmente, se
uno fallisce inter-
rompe l’esecuzio-
ne.
Task eseguiti se-
quenzialmente, se
uno fallisce inter-
rompe l’esecuzio-
ne. Cerca di falli-
re il prima possi-
bile tramite anali-
si dello script (es.
file che manca-
no. . . ).
Task eseguiti in
ordine casuale,
ma supporta
l’impostazione di
un ordine preciso
di esecuzione.
Esegue ogni vol-
ta tutti i task
e segnala quanti
falliscono o no.
Tool
aggiuntivi
I moduli esterni
necessari per l’e-
secuzione vengo-
no installati sulla
workstation dove
si esegue Ansible
I moduli ester-
ni vanno instal-
lati con ChefDK
e vengono salvati
nel cookbook che
dovr`a essere mes-
so sul server
Bisogna installare
i moduli necessa-
ri tramite coman-
do sulla macchi-
na ospite (`e possi-
bile installarli au-
tomaticamente in
base al Manifest,
ma cio`o richiede
strumenti di ge-
stione addiziona-
li)
Velocit`a di
provisio-
ning e
update
Dai test eseguiti la velocit`a `e essenzialmente la stessa con
tutti e 3 i sistemi. In quanto il tempo di installazione `e det-
tato pi`u dal tempo di scaricamento dei pacchetti da installa-
re che dal tempo necessario all’esecuzione di un particolare
provisioner.
Supporto
alla cloud
La creazione delle macchine virtuali `e fornita da Vagrant che
supporta di base VirtualBox, Hyper-V e Docker.
Il supporto per la cloud, come ad esempio Amazon AWS o
Google Cloud, `e fornita tramite plugin.
Alla fine del confronto, in base a quelle che sono le esigenze del nostro
progetto, `e stato deciso di utilizzare Ansible.
La scelta `e stata dettata da:
• semplicit`a di architettura: il sistema prevede solo una macchina ser-
ver che va ad eseguire degli script su determinate macchine, non `e
necessario organizzare e configurare nessun client;
• linguaggio di scripting: sfruttando YAML, ovvero un linguaggio ”hu-
man readable”, risulta molto pi`u chiaro e comprensibile rispetto agli
altri;
9
• minor impatto sulla macchina ospite: sfruttando una architettura
agentless non necessita di installazioni di client sulle varie macchine
ospite, eliminando quindi sia problemi di aggiornamento e manuten-
zione degli stessi, che di contaminazione dell’ambiente di esecuzione;
• praticit`a di installazione dei plugin: `e sufficiente installarli soltanto
sulla macchina server;
• pi`u adatto per le esigenze del nostro progetto: la creazione di macchine
virtuali ad-hoc per il testing era pi`u in sintonia con il funzionamento
di Ansible, in quanto esso prevede che sia il server quello che va ad
applicare le modifiche sui nodi, al contrario, le altre due alternative
prevedono un sistema in cui sono i singoli nodi quelli che vanno a
prendere le configurazioni dal server centrale.
Tutti questi elementi gli conferiscono una maggiore semplicit`a e lo ren-
dono quello pi`u adatto all’utilizzo, relativamente al nostro caso d’uso.
1.3 Jenkins
Jenkins `e un server di Continuous Integration open-source scritto in lin-
guaggio Java.
Permette di definire e automatizzare il processo di costruzione e installa-
zione di un’applicazione, descrivendo in una pipeline tutti i passi, di cui so-
litamente i pi`u importanti sono: compilazione, test e installazione, necessari
per il deployment di un’applicazione web in produzione.
Viene eseguito come servizio sulla macchina che lo ospita, configurazione
e funzionamento sono completamente gestiti tramite interfaccia web. Questo
permette l’installazione alternativamente su una macchina remota, quasi
essenziale nel caso in cui il progetto software sia sviluppato da un team di
programmatori, con necessit`a di accesso simultaneo per controllare svariate
parti del processo.
La struttura di Jenkins supporta dei plugin che permettono l’amplia-
mento delle funzionalit`a della piattaforma di base. Funzionalit`a aggiuntive
possono essere, ad esempio, l’interfacciamento con vari sistemi di gestione
del codice sorgente o l’implementazione di diversi strumenti per il testing,
fornendo una pratica interfaccia visuale per l’analisi dei risultati.
Questo strumento sar`a il nocciolo attorno al quale andremo a costruire
la pipeline di sviluppo software, fornendo la base di automazione da cui
eseguire tutti gli altri strumenti necessari.
10
Capitolo 2
Pipeline di sviluppo
Lo scopo del lavoro di tesi `e quello di progettare una pipeline completa di
sviluppo software.
La pipeline prevede, oltre alla compilazione del codice, anche l’esecuzione
di vari test che andranno eseguiti su delle macchine virtuali dove sar`a stata
installata l’applicazione.
La pipeline sar`a divisa in 3 principali sezioni o ”stage”:
Stage 1 Compilazione dell’applicazione, test di unit`a e di integrazione.
Stage 2 Test di carico e di interfaccia utente.
Stage 3 Messa in produzione su Google Cloud.
Introdurremo ora l’applicazione che andremo ad utilizzare. Esamineremo
poi le configurazioni necessarie e le operazioni eseguite per ogni stage della
pipeline.
2.1 Applicazione
Si `e scelto di utilizzare Shopizer come applicazione di test per cui costruire
la pipeline di sviluppo.
Shopizer `e una applicazione open-source scritta in linguaggio Java che
permette la creazione di siti web volti alla vendita di prodotti.
Supporta due diversi tipi di DBMS: H2 e MySQL, che, date le loro diver-
se caratteristiche, useremo separatamente nei primi due stage per eseguire
differenti batterie di test.
Elenchiamo ora i prerequisiti dell’applicazione, questi andranno soddi-
sfatti dai vari strumenti che useremo in seguito:
• lo strumento di build automation Maven, utilizzato sia per la compi-
lazione, che per l’esecuzione dei test di unit`a e integrazione
11
Figura 2.1: Schermata Home di un sito creato con Shopizer
• un sistema operativo su cui far girare la macchina virtuale Java e l’ap-
plication server: non viene richiesto niente di particolare, utilizzeremo
un sistema operativo Linux Ubuntu 16.04 LTS “Xenial Xerus” a 64
bit
• installazione di Java 8, di cui utilizzeremo la versione open source
• un application server: utilizzeremo Apache Tomcat 8
• un server MySQL
2.2 Configurazione Jenkins
Jenkins necessita di una configurazione alquanto limitata, in quanto, nono-
stante sia il motore che muover`a il processo produttivo, recuperer`a tutte le
informazioni relative alle operazioni da eseguire da un file di script salvato
nel sistema di gestione sorgenti del progetto.
Le operazioni da eseguire sono:
• la creazione di uno o pi`u utenti che possano accedere al sistema.
• L’installazione di tutti i plugin necessari al funzionamento della pipe-
line, nel nostro caso essi sono:
12
Plugin Pipeline essenziale, permette la creazione del percorso di
sviluppo software
Plugin Git necessario per recuperare il codice sorgente dell’applica-
zione dalla repository
Plugin JUnit necessario per la pubblicazione dei risultati dei vari
test eseguiti con Maven
• La creazione di un progetto di tipo Pipeline.
• Configurare il progetto creato nel passo precedente in modo che possa
prendersi lo script, detto Jenkinsfile, con le operazioni da eseguire nella
Pipeline. Questo `e fatto semplicemente fornendo l’url della repository
Git del nostro progetto.
• Assicurarsi che la coppia di chiavi RSA sia presente nella cartella .ssh/
dell’utente jenkins e copia della chiave privata di autenticazione a
Google Cloud nella cartella del progetto.
Da questo momento `e sufficiente premere il tasto Build per eseguire
automaticamente tutti i passi descritti nel Jenkinsfile.
Se si dovesse verificare un errore in uno qualsiasi del vari passaggi, ver-
rebbe interrotta l’esecuzione dei passi successivi e l’intera Pipeline verrebbe
segnalata come “fallita”.
2.3 Architettura del sistema
Il sistema sar`a strutturato nel modo seguente: avremo una macchina prin-
cipale, che pu`o essere la nostra workstation o anche una macchina remota,
dove sar`a installato Jenkins. Vista la mole di lavoro richiesta: compilazione
di sorgenti e creazione di macchine virtuali, `e importante che sia fornita di
un hardware abbastanza potente.
Tutto il codice sorgente, sia relativo all’applicazione che ai vari file di
script e configurazione necessari nel processo di sviluppo sono tutti versio-
nati in una repository Git ospitata in locale sulla stessa macchina. Cionono-
stante, alcuni file, come ad esempio chiavi private RSA o file contenenti dati
sensibili, non possono essere salvati in sistemi di versionamento per motivi
di sicurezza e verranno quindi installati a mano.
Tutte le operazioni della pipeline verranno eseguite dall’utente jenkins a
partire dalla cartella nel workspace relativa al nostro progetto. `E importante
quindi assicurarsi che tutti i file necessari e i permessi sugli stessi siano
impostati correttamente,
Va fatta una distinzione importante: le operazioni che vedremo descritte
all’interno del Jenkinsfile di configurazione della pipeline saranno eseguite
13
in locale sulla macchina principale, tutti gli script Ansible invece verranno
eseguiti sulle macchine virtuali create a richiesta.
In generale avremo quindi Jenkins che eseguir`a in locale i comandi sulla
sua pipeline, usando Vagrant per la creazione delle virtual machines che a
sua volta richiamer`a gli script di Ansible per effettuare il provisioning.
2.4 Stage 1 - Build Tests
In questa prima fase verr`a effettuata la compilazione del codice con supporto
al DBMS H2, questo `e un DBMS residente in memoria e non ha bisogno di
nessuna configurazione per funzionare, fornisce di conseguenza un ambiente
pi`u semplice dove effettuare i primi test.
Figura 2.2: Passi del primo stage della pipeline
A cui corrisponde la seguente sezione di codice all’interno del Jenkinsfile,
il codice completo `e disponibile in appendice a pagina 23:
stage(’Clone Repository’) {
git ’${repository_url}’
}
stage(’Build’) {
sh ’mvn clean install -DskipTests’
}
stage(’Create Virtual Machine - Stage1’) {
14
sh ’vagrant up stage1’
}
La prima operazione fondamentale da eseguire `e la clonazione della
repository con il codice sorgente.
In seguito il codice viene compilato. Vengono saltati i test in questa
prima fase in quanto necessitano della macchina virtuale funzionanente per
poter essere eseguiti con successo.
Viene quindi creata e configurata completamente la macchina virtuale.
stage(’Tests - Stage1’) {
try {
sh ’mvn test’
} finally {
junit ’sm-shop/target/surefire-reports/*.xml’
}
}
Ora che la macchina virtuale con l’applicazione `e funzionante, in que-
st’ultima sezione vengono effettuati i test e, indipendentemente dal successo
o fallimento della loro esecuzione, pubblicati i risultati.
2.4.1 Configurazione Vagrant
Essendo questa la prima volta che lo incontriamo, descriviamo la configura-
zione di Vagrant. La configurazione sar`a molto simile per quanto riguarda
le prime due macchine virtuali che andremo a creare.
Con riferimento al codice completo in appendice a pagina 26.
Come prima cosa viene impostato il tipo di immagine da utilizzare per
la creazione della macchina:
config.vm.box = "ubuntu/xenial64"
nel nostro caso un linux Ubuntu 16.04 LTS “Xenial Xerus”.
In seguito viene eseguito il provisioning sulla macchina con Ansible. No-
tiamo come viene installato, tramite comandi di shell di sistema, il linguaggio
Python, necessario al funzionamento di Ansible sulla macchina ospite.
stage1.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y python
SHELL
In questa sezione viene richiamato per l’esecuzione lo script con la confi-
gurazione desiderata della macchina virtuale. Il fatto che venga eseguito co-
me sudo indica che avr`a poteri di amministratore all’interno della macchina,
necessari per l’installazione dei vari programmi.
15
stage1.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook-stage1.yml"
ansible.sudo = true
end
2.4.2 Script Ansible
Con riferimento al codice completo in appendice a pagina 29.
In questo primo caso lo script `e molto semplice.
Ci si assicura che l’application server Tomcat 8 sia installato e funzio-
nante.
Vengono impostate alcune opzioni di Java, in quanto l’applicazione che
stiamo usando necessita di una quantit`a di memoria superiore a quella che
viene designata di default.
L’ultimo passaggio `e quello di installazione dell’applicazione, per effet-
tuarla `e sufficiente copiare il file sm-shop.war generato nella precedente fase
di compilazione e copiarlo nella cartella webapps/ di Tomcat.
2.5 Stage 2 - Stress Tests
In questa fase ricompileremo l’applicazione con il supporto per MySQL e
in seguito installeremo una macchina virtuale su cui effettuare dei test di
carico tramite JMeter e di usabilit`a con Selenium.
Figura 2.3: Passi del secondo stage della pipeline
2.5.1 Configurazione Vagrant
Sempre in riferimento al codice del Vagrantfile di prima a pagina 26.
Notiamo che il codice per il secondo stage `e praticamente lo stesso, la
differenza pi`u importante `e data dalla riga:
stage2.vm.network "private_network", ip: "192.168.1.3"
16
in cui viene configurata una rete virtuale fra la macchina principale e quella
virtuale, questo passo `e necessario per permettere l’accesso diretto al da-
tabase da parte di JMeter, in modo da potergli permettere di effettuare i
test.
2.5.2 Script Ansible
In riferimento al codice del playbook per Ansible relativo allo Stage 2 in
appendice a pagina 31.
In questo caso notiamo che lo script `e pi`u complicato rispetto al passato.
Oltre all’installazione e configurazione di Tomcat come nello stage pre-
cedente troviamo molte altre operazioni.
Viene installato il server MySQL insieme ai prerequisiti per permettere
ad Ansible di controllarlo.
Vengono creati il database e l’utente che verr`a utilizzato dall’applicazione
per accederci.
`E importante notare che il database viene creato fornendogli uno script
SQL, il cui scopo `e: aumentare il numero di prodotti con cui viene popolato
inizialmente e impostare tutte le informazioni necessarie per configurare i
pagamenti e le spedizioni, fondamentali per riuscire a completare un ordine.
2.5.3 Test con JMeter e Selenium
In questa sezione introdurremo altri due strumenti, utilizzati per effettuare
dei test di carico sulla nostra applicazione.
JMeter
JMeter `e uno strumento che permette l’esecuzione di test di carico su un
sito web.
I test sono composti da un certo elenco di pagine, JMeter procede ad
effetturare una chiamata HTTP per ogni singola pagina dell’elenco.
Se si volessero eseguire dei test su un database, al posto dell’elenco di
pagine da visitare, ci sarebbe un elenco di query SQL da eseguire.
In ognuno dei due casi sono necessarie altre tre informazioni:
• il numero di threads, cio`e di utenti simulati, da eseguire in parallelo
• il periodo di rampa, che imposta quanto a lungo ritardare la parten-
za dei singoli utenti, ad esempio se impongo un periodo di 10 secondi,
JMeter finir`a di far partire tutti i miei utenti virtuali dopo 10 secondi
• il numero di ripetizioni da eseguire per ogni utente
17
Selenium
Selenium `e un programma che permette di automatizzare la navigazione di
pagine web.
Utilizza un plugin del browser web Firefox per creare i propri test,
eseguibili singolarmente o in suite.
La creazione di un test `e effettuata avviando la modalit`a di registrazio-
ne la quale provvede a catturare le operazioni effettuate mentre si naviga
manualmente sul sito.
In seguito l’esecuzione dei test `e effettuata da un runner che, attraverso
dei driver, controller`a i vari browser su cui lanciare i test automaticamente.
Nel nostro caso, l’utente jenkins non aveva le autorizzazioni necessarie
per eseguire programmi sul server grafico X11. Abbiamo dovuto quindi uti-
lizzare Xvfb per creare un ambiente grafico virtuale dove far partire Chrome,
che `e il browser con cui abbiamo effettuato i test.
Una volta eseguiti i test, sia con JMeter che con Selenium, viene richia-
mato un plugin di Jenkins che permette di salvare e pubblicare nell’inter-
faccia della pipeline i file con i risultati.
2.6 Stage 3 - Deploy su Google Cloud
In questa terza ed ultima fase descriveremo come `e stato effettuato il deploy
dell’applicazione in un ambiente cloud.
Figura 2.4: Passi del terzo stage della pipeline
18
Per quanto sia il passo pi`u semplice dal punto di vista della pipeli-
ne, richiede un certo numero di configurazioni da fare manualmente per
la preparazione dell’ambiente di produzione su Cloud di Google.
2.6.1 Configurazione Google Cloud
Come gi`a anticipato in precedenza ci sono parecchie operazioni da effettuare
per poter configurare correttamente l’accesso e la conseguente creazione e
gestione di macchine virtuali tramite Vagrant.
Le varie operazioni da compiere sono le seguenti:
• Eseguire l’accesso alla Google Developer Console con un utente Google.
• Creare un progetto.
• Nella sezione “Metadata”, importare le chiavi RSA pubbliche per la
connessione via SSH fra Vagrant e la virtual machine in cloud.
• Creare un account di servizio che verr`a utilizzato per eseguire tutte le
operazioni sulle macchine virtuali.
• Fornire all’account appena creato tutti i permessi necessari per poter
funzionare correttamente.
• Scaricare il file JSON con la chiave privata necessaria per autenticare
automaticamente l’account di servizio.
• Impostare correttamente le regole del firewall per permettere la con-
nessione alla propria applicazione una volta installata. Di default tutte
le connessioni remote alla macchina sono bloccate.
2.6.2 Configurazione Vagrant
La configurazione di Vagrant differisce notevolmente rispetto agli stage pre-
cendenti. Ci riferiamo nuovamente al codice completo del Vagrantfile a
pagina 26.
Utilizzeremo un nuovo provider, google e non pi`u virtualbox e sar`a
necessario inoltre cambiare l’immagine di base, la Vagrant Box, in quanto
Google fornisce direttamente una lista di immagini gi`a pronte da utilizzare.
Vediamo le configurazioni nel dettaglio.
Come prima cosa viene impostata la nuova immagine di base:
stage3.vm.box = "google/gce"
Inseriamo le informazioni con cui abbiamo configurato la Google Cloud:
google.google_project_id = ’#{project_id}’
google.google_client_email = ’#{service_account_mail}’
google.google_json_key_location = ’#{json_private_key}’
19
Descriviamo il tipo di macchina virtuale che desideriamo creare:
google.name = ’#{instance_name}’
google.zone = "europe-west1-d"
google.machine_type = "n1-standard-1"
google.image = "ubuntu-1604-xenial-v20170202"
Queste informazioni comprendono:
• il nome dell’istanza, cio`e della virtual machine, da creare
• la zona dove creare l’istanza
• il tipo di macchina desiderata, scegliendo quindi numero di processori
e memoria da installare
• l’immagine con il sistema operativo con cui creare la macchina
Ultima configurazione da fare `e imporre lo stesso nome utente con cui
abbiamo creato le chiavi RSA che abbiamo importato in Google Cloud, oltre
ad assicurarci che prenda il file giusto con le chiavi.
override.ssh.username = ’#{ssh_user_name}’
override.ssh.private_key_path = "~/.ssh/id_rsa"
Oltre a queste impostazioni il resto dello script rimane invariato rispetto
agli stage precedenti.
2.6.3 Script Ansible
A causa della macchina di base leggermente diversa fra questo stage e quelli
precedenti, alcuni passaggi dello script Ansible hanno dovuto esser modificati
leggermente rispetto a prima per essere eseguiti senza problemi.
Possiamo verificarlo confrontando i sorgenti in appendice alle pagine 31
(Stage 2) e 34 (Stage 3).
Nonostante gli script di configurazione riportino alcune differenze fra di
loro, il risultato finale dopo l’esecuzione `e lo stesso in entrambi i casi.
20
Figura2.5:RappresentazionecompletadellapipelineinJenkins
21
Conclusioni
Il progetto di creazione di una pipeline completa per l’automazione `e av-
venuto con successo, dimostrando che `e possibile eliminare la necessit`a di
esecuzione manuale di molte operazioni all’interno del processo di sviluppo
software.
Conseguenze di questo approccio automatizzato, oltre a quello di rispar-
mio di tempo, sono di poter effettuare la messa in produzione di una appli-
cazione in modo pi`u coerente, il che porta l’applicazione stessa ad essere pi`u
stabile e sicura.
Sviluppi futuri
Possibili sviluppi futuri includono l’implementazione di nuove tipologie di
test, come ad esempio test sulla sicurezza del sistema, per assicurarsi di non
esporre un sistema vulnerabile alla rete.
Un’altra tipologia di test da inserire sarebbe quella di test di accettazione
da parte dell’utente, che tramite l’interfaccia stessa di Jenkins potrebbe
autonomamente creare la propria istanza dell’applicazione, eseguire i test su
una sessione browser aperta automaticamente e infine compilare un rapporto
sul test sempre rimanendo all’interno dell’interfaccia di Jenkins.
Fra gli sviluppi futuri possiamo anche includere la creazione di una repo-
sitory aziendale di macchine virtuali per Vagrant, il che risponde alla neces-
sit`a di avere macchine macchine di test configurate in modi molto particolari.
Questo avviene soprattutto se consideriamo sistemi di test che necessitano
di sistemi operativi Windows o MacOS dove l’installazione `e generalmente
poco automatizzabile e richiede l’inserimento delle licenze d’uso che sono a
pagamento.
In alternativa, fornendo gi`a macchine pronte all’uso, una repository lo-
cale pu`o essere utilizzata soltanto per evitare di sprecare inutilmente del
tempo scaricando e installando gli stessi pacchetti software ogni volta che
viene creata una nuova istanza per far girare i test.
22
Codice sorgente
Jenkinsfile
Questo `e il codice sorgente della pipeline di sviluppo software creata con
Jenkins. Verr`a eseguito sulla workstation dove avremo installato Jenkins e
proceder`a a compilare l’applicazione e richiamare i comandi per la gestione
delle virtual machine.
#!groovy
node {
stage(’Clone Repository’) {
// Clones the git repository with the source code of our
// project
git ’${git_url}’
}
stage(’Build’) {
// Builds the application, but skips tests that will be run
// at a later stage in the pipeline
sh ’mvn clean install -DskipTests’
}
stage(’Create Virtual Machine - Stage1’) {
try {
// Destroy all existing virtual machines
sh ’vagrant destroy --force’
sh ’vagrant up stage1’
} catch (err) {
// Sends a email in case of an error during the creation
// of the first virtual machine
mail to: ’${user_mail}’,
subject: ’ERRORE’,
body: ’Si `e verificato un errore ${err.message}’
}
}
stage(’Tests - Stage1’) {
23
try {
// Runs the tests
sh ’mvn test’
} finally {
// Publishes the results using junit
junit ’sm-shop/target/surefire-reports/*.xml’
}
}
stage(’Modify sources and build with MySQL support.’) {
// Copies the file with the correct settings for building
// the application with MySQL support
sh ’cp database.properties 
sm-shop/src/main/resources/database.properties’
sh ’mvn clean install -DskipTests’
}
stage(’Create Virtual Machine - Stage2’) {
// Destroys out previous stage virtual machine and creates
// the second one, this time including MySQL server
sh ’vagrant destroy --force’
sh ’vagrant up stage2’
}
stage(’Tests - Stage2’) {
try {
sh ’mvn test’
} finally {
junit ’sm-shop/target/surefire-reports/*.xml’
}
}
stage(’Install JMeter’) {
// Downloads and installs JMeter to a local directory
if (fileExists(’apache-jmeter-3.1/’)) {
} else {
sh ’wget "${jmeter_url}"’
sh ’tar -xzf apache-jmeter-3.1.tgz’
}
// Downloads and installs MySQL JDBC connector for JMeter
if (fileExists(’${mysql_connector_name}’)) {
} else {
sh ’wget ${mysql_connector_url}’
sh ’tar -C apache-jmeter-3.1/lib/
--strip-components 1 
-xzf ${mysql_connector_name}’
}
}
24
stage(’Tests with JMeter’) {
// Needs this wait time for the Vm to get online.
sh ’sleep 2m’
// Load test webapp
sh ’./apache-jmeter-3.1/bin/jmeter -n
-t jmeter-test.jmx -l jmeter-test.jtl’
// Load test database
sh ’./apache-jmeter-3.1/bin/jmeter -n
-t jmeter-mysql.jmx -l jmeter-mysql.jtl’
// Publish test result
archiveArtifacts ’jmeter-test.jtl,
jmeter-mysql.jtl,
jmeter.log’
}
stage(’Install Selenium and chromedriver’) {
// Install selenium
if (fileExists(’${selenium_name}’)) {
} else {
sh ’wget ${selenium_url}’
}
// Install chromedriver
if (fileExists(’chromedriver’)) {
} else {
sh ’wget ${chromedriver_url}’
sh ’unzip ${chromedriver_name}’
}
}
stage(’Tests with Selenium’) {
// Run a script where we
// setup xvfb for headless chrome
// and run selenium tests
sh ’sh selenium-test.sh’
// Publish test result
archiveArtifacts ’selenium-results.htm’
}
stage(’Deploy on Google Cloud’) {
sh ’vagrant up stage3 --provider=google’
}
}
25
Vagrantfile
Questo `e il codice sorgente di Vagrant utilizzato nella creazione delle virtual
machine.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don’t change it unless you know what
# you’re doing.
Vagrant.configure("2") do |config|
# Every Vagrant development environment requires a box. You can
# search for boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/xenial64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# ‘vagrant box outdated‘. This is not recommended.
# config.vm.box_check_update = false
config.vm.provider "virtualbox" do |vb|
# Customize the amount of memory on the VM:
vb.memory = "2048"
end
# Create virtual machine for Stage1 (H2 database)
config.vm.define "stage1" do |stage1|
# stage1.vm.network "private_network", ip: "192.168.1.2"
# We need this port forwarding to avoid conflicts, because the
# localhost is already hosting the Jenkins server on port 8080
stage1.vm.network "forwarded_port", guest: 8080, host: 8085
# We need to make sure to have python installed to allow Ansible
# to work
stage1.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y python
SHELL
# This calls the Ansible script for provisioning
stage1.vm.provision "ansible" do |ansible|
26
ansible.playbook = "playbook-stage1.yml"
# Running the script as sudo grants us root permissions on the
# virtual machine, we need this since we are installing
# new packages
ansible.sudo = true
end
end
# Create virtual machine for Stage2 (MySQL)
config.vm.define "stage2" do |stage2|
# In this case we also give the machine an ip address to allow
# direct connection to the database to run tests
stage2.vm.network "private_network", ip: "192.168.1.3"
stage2.vm.network "forwarded_port", guest: 8080, host: 8087
stage2.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y python
SHELL
stage2.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook-stage2.yml"
ansible.sudo = true
end
end
# Create virtual machine for Stage3 (Google Cloud)
config.vm.define "stage3" do |stage3|
stage3.vm.box = "google/gce"
stage3.vm.provider :google do |google, override|
# This is out private informations section
google.google_project_id = "#{project_id}"
google.google_client_email = "#{service_account_mail}"
google.google_json_key_location = "#{json_private_key}"
# In this section we describe the machine we want to create
# Define the name of the instance.
google.name = "#{instance_name}"
# Set the zone where the instance will be located.
# To find out available zones:
# ‘gcloud compute zones list‘.
27
google.zone = "europe-west1-d"
# Set the machine type to use. To find out available types:
# ‘gcloud compute machine-types list --zone asia-east1-c‘.
google.machine_type = "n1-standard-1"
# Set the machine image to use. To find out available images:
# ‘£ gcloud compute images list‘.
google.image = "ubuntu-1604-xenial-v20170202"
# We override the default connection settings to match those
# in our RSA keys
override.ssh.username = "#{ssh_user_name}"
override.ssh.private_key_path = "~/.ssh/id_rsa"
end
stage3.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y python
SHELL
stage3.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook-stage3.yml"
ansible.verbose = true
ansible.sudo = true
end
end
end
28
Ansible - playbook-stage1.yml
Questo `e lo script di Ansible per il provisioning della prima macchina vir-
tuale. In questo caso viene semplicemente installato e configurato Tomcat
ed effettuato il deploy dell’applicazione.
---
- hosts: all
vars_files:
- vars.yml
tasks:
- name: Ensure Tomcat 8 is installed.
apt:
name: tomcat8
state: installed
- name: Replace Old Java options for Tomcat 8.
lineinfile:
dest: /etc/default/tomcat8
regexp: ’^JAVA_OPTS’
line: ’JAVA_OPTS="-Djava.awt.headless=true 
-XX:+UseConcMarkSweepGC"’
state: present
- name: Set New Java options for Tomcat 8.
# We need to set these options because our application requires
# more memory than what is provided by default
lineinfile:
dest: /etc/default/tomcat8
insertafter: ’^JAVA_OPTS’
line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m 
-Xmx1024m -XX:MaxPermSize=256m"’
state: present
- name: Restart Tomcat 8 with the new options.
service:
name: tomcat8
state: restarted
enabled: yes
- name: Change /var/lib/tomcat8 permissions.
# When created tomcat8 directory is owned by root, we restore
# the correct ownership to allow tomcat to create his own files
29
file:
path: /var/lib/tomcat8
owner: tomcat8
group: tomcat8
- name: Deploy application.
# To deploy the application we just need to copy the war package
# inside the webapps directory in tomcat home directory
become: yes
become_user: root
copy:
src: sm-shop/target/{{ snapshot_name }}
dest: /var/lib/tomcat8/webapps/sm-shop.war
30
Ansible - playbook-stage2.yml
Questo `e lo script di Ansible per il provisioning della seconda macchina
virtuale. In questo caso, oltre ad installare Tomcat, viene installato e con-
figurato il server MySQL, creato e popolato il database per l’applicazione e
creato l’utente per la connessione al database.
---
- hosts: all
vars_files:
- vars.yml
tasks:
- name: Ensure Tomcat 8 is installed.
apt:
name: tomcat8
state: installed
- name: Replace Old Java options for Tomcat 8.
lineinfile:
dest: /etc/default/tomcat8
regexp: ’^JAVA_OPTS’
line: ’JAVA_OPTS="-Djava.awt.headless=true
-XX:+UseConcMarkSweepGC"’
state: present
- name: Set New Java options for Tomcat 8.
# We need to set these options because our application requires
# more memory than what is provided by default
lineinfile:
dest: /etc/default/tomcat8
insertafter: ’^JAVA_OPTS’
line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m
-Xmx1024m -XX:MaxPermSize=256m"’
state: present
- name: Restart Tomcat 8 with the new options.
service:
name: tomcat8
state: restarted
enabled: yes
- name: Change /var/lib/tomcat8 permissions.
# When created tomcat8 directory is owned by root, we restore
31
# the correct ownership to allow tomcat to create his own files
file:
path: /var/lib/tomcat8
owner: tomcat8
group: tomcat8
- name: Ensure MySQL server is installed.
apt:
name: "{{ item }}"
state: installed
with_items:
- mysql-server
- mysql-client
- python-mysqldb
- name: Ensure MySQL server is running.
service:
name: mysql
state: started
enabled: yes
- name: Copy the mysqld.cnf
# This configuration file contains the setting to allow remote
# connection to the database
become: yes
become_user: root
copy:
src: mysqld.cnf
dest: /etc/mysql/mysql.conf.d/mysqld.cnf
- name: Restart MySQL
service:
name: mysql
state: restarted
- name: Create and populate SALESMANAGER MySQL database
# Using the import function we automatically execute the given
# SQL script on creation
mysql_db:
name: SALESMANAGER
state: import
target: /vagrant/SALESMANAGER-dump.sql
- name: Copy static data
32
# These are the files where the CMS saves static images
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: tomcat8
group: tomcat8
with_items:
- { src: ’StoreRepository.dat’,
dest: ’/var/lib/tomcat8/files/store/’ }
- { src: ’FilesRepository.dat’,
dest: ’/var/lib/tomcat8/files/repos/’ }
- name: Create user for SALESMANAGER MySQL database
mysql_user:
name: "{{ db.user }}"
password: "{{ db.password }}"
host: "{{ item }}"
priv: "*.*:ALL,GRANT"
state: present
with_items:
- "{{ db.host }}"
- localhost
- name: Deploy application.
# To deploy the application we just need to copy the war package
# inside the webapps directory in tomcat home directory
become: yes
become_user: root
copy:
src: sm-shop/target/{{ snapshot_name }}
dest: /var/lib/tomcat8/webapps/sm-shop.war
33
Ansible - playbook-stage3.yml
Questo `e lo script di Ansible per il provisioning della terza macchina virtuale.
A causa di diverse configurazioni di sicurezza rispetto alle macchine prece-
denti, alcuni comandi sono stati leggermente modificati. Nonostante tutti
il risultato `e identico rispetto all’esecuzione dello script per l’installazione
della macchina virtuale precedente.
---
- hosts: all
vars_files:
- vars.yml
tasks:
- name: Ensure Tomcat 8 is installed.
apt:
name: tomcat8
state: installed
- name: Replace Old Java options for Tomcat 8.
lineinfile:
dest: /etc/default/tomcat8
regexp: ’^JAVA_OPTS’
line: ’JAVA_OPTS="-Djava.awt.headless=true
-XX:+UseConcMarkSweepGC"’
state: present
- name: Set New Java options for Tomcat 8.
# We need to set these options because our application requires
# more memory than what is provided by default
lineinfile:
dest: /etc/default/tomcat8
insertafter: ’^JAVA_OPTS’
line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m
-Xmx1024m -XX:MaxPermSize=256m"’
state: present
- name: Restart Tomcat 8 with the new options.
service:
name: tomcat8
state: restarted
enabled: yes
- name: Change /var/lib/tomcat8 permissions.
34
# When created tomcat8 directory is owned by root, we restore
# the correct ownership to allow tomcat to create his own files
file:
path: /var/lib/tomcat8
owner: tomcat8
group: tomcat8
- name: Ensure MySQL server is installed.
apt:
name: "{{ item }}"
state: installed
with_items:
- mysql-server
- mysql-client
- python-mysqldb
- name: Ensure MySQL server is running.
service:
name: mysql
state: started
enabled: yes
- name: Copy static data
# These are the files where the CMS saves static images
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: tomcat8
group: tomcat8
with_items:
- { src: ’StoreRepository.dat’,
dest: ’/var/lib/tomcat8/files/store/’ }
- { src: ’FilesRepository.dat’,
dest: ’/var/lib/tomcat8/files/repos/’ }
- name: Create user for SALESMANAGER MySQL database
mysql_user:
name: "{{ db.user }}"
password: "{{ db.password }}"
host: "{{ item }}"
priv: "*.*:ALL,GRANT"
state: present
with_items:
- "{{ db.host }}"
35
- localhost
- name: Create SALESMANAGER MySQL database
# Due to different security setting in this case we have to
# create the database and then populate it at a later time
mysql_db:
name: SALESMANAGER
state: present
- name: Populate SALESMANAGER MySQL database
mysql_db:
name: SALESMANAGER
login_user: "{{ db.user }}"
login_password: "{{ db.password }}"
state: import
target: /vagrant/SALESMANAGER-dump.sql
- name: Deploy application.
become: yes
become_user: root
copy:
src: sm-shop/target/{{ snapshot_name }}
dest: /var/lib/tomcat8/webapps/sm-shop.war
36
Bibliografia
[1] Gene Kim, Jez Humble, Patrick Debois & John Willis. The DevOps
Handbook. IT Revolution Press, 2016.
[2] Jeff Geerling. Ansible for DevOps. Leanpub, 2015.
[3] Ansible
Website: https://www.ansible.com/
Wiki: https://en.wikipedia.org/wiki/Ansible_(software)
Github: https://github.com/ansible/ansible
[4] Chef
Website: https://www.chef.io/
Wiki: https://en.wikipedia.org/wiki/Chef_(software)
Github: https://github.com/chef/chef
[5] Puppet
Website: https://puppet.com/
Wiki: https://en.wikipedia.org/wiki/Puppet_(software)
Github: https://github.com/puppetlabs/puppet
[6] Vagrant
Website: https://www.vagrantup.com/
Wiki: https://en.wikipedia.org/wiki/Vagrant_(software)
Github: https://github.com/mitchellh/vagrant
[7] Jenkins
Website: https://jenkins.io/
Wiki: https://en.wikipedia.org/wiki/Jenkins_(software)
Github: https://github.com/jenkinsci
[8] JMeter
Website: http://jmeter.apache.org/
Wiki: https://en.wikipedia.org/wiki/Apache_JMeter
[9] JMeter - Building a Web Test Plan
http://jmeter.apache.org/usermanual/build-web-test-
plan.html
37
[10] JMeter - Recording Tests
http://jmeter.apache.org/usermanual/jmeter_proxy_step_by_
step.pdf
[11] Selenium
Website: http://www.seleniumhq.org/
Wiki: https://en.wikipedia.org/wiki/Selenium_(software)
Github: https://github.com/SeleniumHQ/selenium
[12] Shopizer
Website: http://www.shopizer.com
Wiki: https://github.com/shopizer-ecommerce/shopizer/wiki
Github: https://github.com/shopizer-ecommerce/shopizer
[13] Setup Development Environment with Vagrant on Google Compute
Engine
https://realguess.net/2015/09/07/setup-development-
environment-with-vagrant-on-google-compute-engine/
[14] Compute Engine Management with Puppet, Chef, Salt, and Ansible
https://cloud.google.com/solutions/google-compute-engine-
management-puppet-chef-salt-ansible
[15] Provider ufficiale per Google Compute Engine (GCE) di Vagrant
https://github.com/mitchellh/vagrant-google
38

Recomendados

Progetto e implementazione di una pipeline di sviluppo software con tecnologi... por
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...Progetto e implementazione di una pipeline di sviluppo software con tecnologi...
Progetto e implementazione di una pipeline di sviluppo software con tecnologi...Mattia Milleri
360 vistas19 diapositivas
I processi di sviluppo software: l'evoluzione agile ed il DevOps por
I processi di sviluppo software: l'evoluzione agile ed il DevOpsI processi di sviluppo software: l'evoluzione agile ed il DevOps
I processi di sviluppo software: l'evoluzione agile ed il DevOpsGiulio Destri
2.8K vistas49 diapositivas
Tdd e continuous delivery sull'infrastruttura por
Tdd e continuous delivery sull'infrastrutturaTdd e continuous delivery sull'infrastruttura
Tdd e continuous delivery sull'infrastrutturaCodemotion
1.7K vistas82 diapositivas
TDD e Continuous Delivery sull'infrastruttura por
TDD e Continuous Delivery sull'infrastrutturaTDD e Continuous Delivery sull'infrastruttura
TDD e Continuous Delivery sull'infrastrutturaFilippo Liverani
2.8K vistas82 diapositivas
Total Testing in DevOps por
Total Testing in DevOpsTotal Testing in DevOps
Total Testing in DevOpsGianni Bombelli
96 vistas30 diapositivas
Qualità del Software por
Qualità del SoftwareQualità del Software
Qualità del SoftwareYeser Rema
486 vistas10 diapositivas

Más contenido relacionado

La actualidad más candente

Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1 por
Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1
Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1dotnetcode
51 vistas22 diapositivas
Introduzione ad angular 7/8 por
Introduzione ad angular 7/8Introduzione ad angular 7/8
Introduzione ad angular 7/8Valerio Radice
2K vistas63 diapositivas
Android Test Driven Development por
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Developmentsazilla
606 vistas52 diapositivas
Autumn Event Vicenza por
Autumn Event VicenzaAutumn Event Vicenza
Autumn Event VicenzaPiero Sbressa
290 vistas14 diapositivas
Introduzione a .Net Core por
Introduzione a .Net CoreIntroduzione a .Net Core
Introduzione a .Net CoreAntonio Di Motta
380 vistas18 diapositivas
SugarCRM Enterprise Development Virtual Appliance por
SugarCRM Enterprise Development Virtual ApplianceSugarCRM Enterprise Development Virtual Appliance
SugarCRM Enterprise Development Virtual ApplianceAntonio Musarra
1.2K vistas11 diapositivas

La actualidad más candente(6)

Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1 por dotnetcode
Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1
Meetup DotNetCode Settembre 2018 - ASP.NET Core 2.1
dotnetcode51 vistas
Android Test Driven Development por sazilla
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Development
sazilla606 vistas
SugarCRM Enterprise Development Virtual Appliance por Antonio Musarra
SugarCRM Enterprise Development Virtual ApplianceSugarCRM Enterprise Development Virtual Appliance
SugarCRM Enterprise Development Virtual Appliance
Antonio Musarra1.2K vistas

Similar a Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps

Uno studio sull'efficacia di checker automatici per la modernizzazione di cod... por
Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...
Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...Idriss Riouak
163 vistas69 diapositivas
Progettazione e sviluppo di un software applicativo su un single board computer por
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerAlessandro Mascherin
312 vistas44 diapositivas
PALUZZANO TESI por
PALUZZANO TESIPALUZZANO TESI
PALUZZANO TESIEnrico Paluzzano
746 vistas43 diapositivas
SESAMO (application login automator): evoluzioni applicative e considerazioni... por
SESAMO (application login automator): evoluzioni applicative e considerazioni...SESAMO (application login automator): evoluzioni applicative e considerazioni...
SESAMO (application login automator): evoluzioni applicative e considerazioni...AndrijaCiric1
31 vistas37 diapositivas
Corso java por
Corso javaCorso java
Corso javaRiccardo Grutteria
352 vistas147 diapositivas
Progetto SOD Davide Sito por
Progetto SOD Davide SitoProgetto SOD Davide Sito
Progetto SOD Davide SitoDavide Sito
100 vistas27 diapositivas

Similar a Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps(20)

Uno studio sull'efficacia di checker automatici per la modernizzazione di cod... por Idriss Riouak
Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...
Uno studio sull'efficacia di checker automatici per la modernizzazione di cod...
Idriss Riouak163 vistas
Progettazione e sviluppo di un software applicativo su un single board computer por Alessandro Mascherin
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computer
SESAMO (application login automator): evoluzioni applicative e considerazioni... por AndrijaCiric1
SESAMO (application login automator): evoluzioni applicative e considerazioni...SESAMO (application login automator): evoluzioni applicative e considerazioni...
SESAMO (application login automator): evoluzioni applicative e considerazioni...
AndrijaCiric131 vistas
Progetto SOD Davide Sito por Davide Sito
Progetto SOD Davide SitoProgetto SOD Davide Sito
Progetto SOD Davide Sito
Davide Sito100 vistas
Software testing with mocking framework (Android App) por gioacchinolonardo
Software testing with mocking framework (Android App)Software testing with mocking framework (Android App)
Software testing with mocking framework (Android App)
gioacchinolonardo120 vistas
Imparare asp.net 107 por Pi Libri
Imparare asp.net 107Imparare asp.net 107
Imparare asp.net 107
Pi Libri223 vistas
Estrazione automatica di informazioni da documenti cartacei: progetto e reali... por Luca Bressan
Estrazione automatica di informazioni da documenti cartacei: progetto e reali...Estrazione automatica di informazioni da documenti cartacei: progetto e reali...
Estrazione automatica di informazioni da documenti cartacei: progetto e reali...
Luca Bressan1.2K vistas
Generazione automatica diagrammi di rete con template pptx por GiacomoZorzin
Generazione automatica diagrammi di rete con template pptxGenerazione automatica diagrammi di rete con template pptx
Generazione automatica diagrammi di rete con template pptx
GiacomoZorzin21 vistas
Analisi e realizzazione di uno strumento per la verifica di conformità su sis... por Davide Bravin
Analisi e realizzazione di uno strumento per la verifica di conformità su sis...Analisi e realizzazione di uno strumento per la verifica di conformità su sis...
Analisi e realizzazione di uno strumento per la verifica di conformità su sis...
Davide Bravin627 vistas
Designing with microservices - Daniele Mondello por Daniele Mondello
Designing with microservices - Daniele MondelloDesigning with microservices - Daniele Mondello
Designing with microservices - Daniele Mondello
Daniele Mondello338 vistas
Tesi Laurea Specialistica Ingegneria Informatica. Alessandro Andreosè por guesta10af3
Tesi Laurea Specialistica Ingegneria Informatica. Alessandro AndreosèTesi Laurea Specialistica Ingegneria Informatica. Alessandro Andreosè
Tesi Laurea Specialistica Ingegneria Informatica. Alessandro Andreosè
guesta10af31.3K vistas

Último

CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZ por
CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZCONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZ
CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZServizi a rete
71 vistas30 diapositivas
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria Luisa por
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria LuisaCONVEGNO ECOMONDO 09/11-D'ALUISO Maria Luisa
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria LuisaServizi a rete
69 vistas25 diapositivas
CONVEGNO ECOMONDO 09/11-DELL'ANNA Fabrizio por
CONVEGNO ECOMONDO 09/11-DELL'ANNA FabrizioCONVEGNO ECOMONDO 09/11-DELL'ANNA Fabrizio
CONVEGNO ECOMONDO 09/11-DELL'ANNA FabrizioServizi a rete
66 vistas27 diapositivas
CONVEGNO ECOMONDO 09/11-MALVEZZI Simone por
CONVEGNO ECOMONDO 09/11-MALVEZZI SimoneCONVEGNO ECOMONDO 09/11-MALVEZZI Simone
CONVEGNO ECOMONDO 09/11-MALVEZZI SimoneServizi a rete
88 vistas28 diapositivas
CONVEGNO ECOMONDO 09/11-BRUNETTI Maurizia por
CONVEGNO ECOMONDO 09/11-BRUNETTI MauriziaCONVEGNO ECOMONDO 09/11-BRUNETTI Maurizia
CONVEGNO ECOMONDO 09/11-BRUNETTI MauriziaServizi a rete
71 vistas9 diapositivas
CONVEGNO ECOMONDO 09/11-BERTANI Tommaso por
CONVEGNO ECOMONDO 09/11-BERTANI TommasoCONVEGNO ECOMONDO 09/11-BERTANI Tommaso
CONVEGNO ECOMONDO 09/11-BERTANI TommasoServizi a rete
71 vistas6 diapositivas

Último(10)

CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZ por Servizi a rete
CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZCONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZ
CONVEGNO ECOMONDO 09/11--COLUCCI + DECOLLANZ
Servizi a rete71 vistas
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria Luisa por Servizi a rete
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria LuisaCONVEGNO ECOMONDO 09/11-D'ALUISO Maria Luisa
CONVEGNO ECOMONDO 09/11-D'ALUISO Maria Luisa
Servizi a rete69 vistas
CONVEGNO ECOMONDO 09/11-DELL'ANNA Fabrizio por Servizi a rete
CONVEGNO ECOMONDO 09/11-DELL'ANNA FabrizioCONVEGNO ECOMONDO 09/11-DELL'ANNA Fabrizio
CONVEGNO ECOMONDO 09/11-DELL'ANNA Fabrizio
Servizi a rete66 vistas
CONVEGNO ECOMONDO 09/11-MALVEZZI Simone por Servizi a rete
CONVEGNO ECOMONDO 09/11-MALVEZZI SimoneCONVEGNO ECOMONDO 09/11-MALVEZZI Simone
CONVEGNO ECOMONDO 09/11-MALVEZZI Simone
Servizi a rete88 vistas
CONVEGNO ECOMONDO 09/11-BRUNETTI Maurizia por Servizi a rete
CONVEGNO ECOMONDO 09/11-BRUNETTI MauriziaCONVEGNO ECOMONDO 09/11-BRUNETTI Maurizia
CONVEGNO ECOMONDO 09/11-BRUNETTI Maurizia
Servizi a rete71 vistas
CONVEGNO ECOMONDO 09/11-BERTANI Tommaso por Servizi a rete
CONVEGNO ECOMONDO 09/11-BERTANI TommasoCONVEGNO ECOMONDO 09/11-BERTANI Tommaso
CONVEGNO ECOMONDO 09/11-BERTANI Tommaso
Servizi a rete71 vistas
CONVEGNO ECOMONDO 09/11-SCIBILIA Gerardo por Servizi a rete
CONVEGNO ECOMONDO 09/11-SCIBILIA GerardoCONVEGNO ECOMONDO 09/11-SCIBILIA Gerardo
CONVEGNO ECOMONDO 09/11-SCIBILIA Gerardo
Servizi a rete68 vistas
CONVEGNO ECOMONDO 09/11-QUAZZO Armando por Servizi a rete
CONVEGNO ECOMONDO 09/11-QUAZZO ArmandoCONVEGNO ECOMONDO 09/11-QUAZZO Armando
CONVEGNO ECOMONDO 09/11-QUAZZO Armando
Servizi a rete73 vistas
Progettazione ed installazione impianti d'antenna por Massimo Talia
Progettazione ed installazione impianti d'antenna Progettazione ed installazione impianti d'antenna
Progettazione ed installazione impianti d'antenna
Massimo Talia5 vistas
CONVEGNO ECOMONDO 09/11-BARBONE Gaetano por Servizi a rete
CONVEGNO ECOMONDO 09/11-BARBONE GaetanoCONVEGNO ECOMONDO 09/11-BARBONE Gaetano
CONVEGNO ECOMONDO 09/11-BARBONE Gaetano
Servizi a rete76 vistas

Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps

  • 1. Universit`a degli Studi di Trieste Dipartimento di Ingegneria e Architettura Corso di Studi in Ingegneria Informatica Tesi di Laurea Triennale Progetto e implementazione di una pipeline di sviluppo software con tecnologie DevOps Laureando: Mattia Milleri Relatore: prof. Francesco Fabris Correlatore: ing. Sergio Benedetti ANNO ACCADEMICO 2015–2016
  • 2. Indice Introduzione 3 1 Strumenti DevOps 5 1.1 Vagrant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2 Confronto sistemi provisioning . . . . . . . . . . . . . . . . . 6 1.2.1 Ansible . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2.2 Chef . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.3 Puppet . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.4 Tabella di confronto sistemi provisioning . . . . . . . . 8 1.3 Jenkins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2 Pipeline di sviluppo 11 2.1 Applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2 Configurazione Jenkins . . . . . . . . . . . . . . . . . . . . . . 12 2.3 Architettura del sistema . . . . . . . . . . . . . . . . . . . . . 13 2.4 Stage 1 - Build Tests . . . . . . . . . . . . . . . . . . . . . . . 14 2.4.1 Configurazione Vagrant . . . . . . . . . . . . . . . . . 15 2.4.2 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 16 2.5 Stage 2 - Stress Tests . . . . . . . . . . . . . . . . . . . . . . . 16 2.5.1 Configurazione Vagrant . . . . . . . . . . . . . . . . . 16 2.5.2 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 17 2.5.3 Test con JMeter e Selenium . . . . . . . . . . . . . . . 17 2.6 Stage 3 - Deploy su Google Cloud . . . . . . . . . . . . . . . . 18 2.6.1 Configurazione Google Cloud . . . . . . . . . . . . . . 19 2.6.2 Configurazione Vagrant . . . . . . . . . . . . . . . . . 19 2.6.3 Script Ansible . . . . . . . . . . . . . . . . . . . . . . . 20 Conclusioni 22 Codice sorgente 23 Jenkinsfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Vagrantfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Ansible - playbook-stage1.yml . . . . . . . . . . . . . . . . . . . . . 29 Ansible - playbook-stage2.yml . . . . . . . . . . . . . . . . . . . . . 31 1
  • 3. Ansible - playbook-stage3.yml . . . . . . . . . . . . . . . . . . . . . 34 2
  • 4. Introduzione Il lavoro di tesi formalizzato in questo documento `e stato eseguito presso Esteco SPA. L’ambito `e quello dello sviluppo di applicazioni in ambiente web. Lo scopo del lavoro `e quello di automatizzare completamente tutta la pipeline di sviluppo di una applicazione web, a partire dalla compilazione e fino alla messa in produzione, utilizzando degli strumenti DevOps. Cos’`e una pipeline di sviluppo? Una pipeline di sviluppo `e la rappresentazione di tutti i passi del percorso cui un software `e assoggettato prima di poter arrivare in produzione. Per ovvii motivi si ha l’esigenza di automatizzare tutto il percorso; ci`o risponde alle seguenti richieste, necessarie per avere un’applicazione stabile e sicura: • se devono esserci dei fallimenti in un qualche punto della pipeline, `e importante avere dei test che falliscono presto, in modo da poter reagire tempestivamente agli errori, nei vari test di validazione, di stress e di usabilit`a; • togliere la componente di errore umano nella fase di installazione. Te- st, configurazioni e installazioni vengono eseguite sempre esattamente nello stesso modo; • avere la certezza dell’uguaglianza fra le varie macchine di test e di produzione. Essendo create in modo automatico a partire da uno script esse saranno sempre identiche; • rendere la preparazione dell’ambiente e l’installazione dell’applicazione qualcosa di ”programmabile”; in questo modo, una volta creato lo script, tutti possono eseguirlo, non `e pi`u necessario fare affidamento su una singola persona che era l’unica a conoscere come procedere con l’installazione. 3
  • 5. Cosa si intende con strumenti DevOps? DevOps `e un termine coniato nel 2009 da Patrick Debois; esso descrive un insieme di pratiche volte ad aiutare la collaborazione fra quelli che sono i due maggiori agenti nel processo di sviluppo di una applicazione: gli svilup- patori (DEVelopers) da una parte e la parte di amministrazione di sistemi (OPerationS) dall’altra. Il risultato di tale approccio `e una forte automazione del processo pro- duttivo, che permette di velocizzare e rendere pi`u affidabile la messa in produzione di un’applicazione. Con strumenti DevOps indichiamo quindi tutte quelle applicazioni che permettono di automatizzare le operazioni di amministrazione di sistema. Nei prossimi capitoli esamineremo nel dettaglio la struttura della pipeline e il funzionamento degli strumenti necessari per realizzarla. 4
  • 6. Capitolo 1 Strumenti DevOps In questo capitolo descriveremo brevemente il funzionamento degli strumenti di automazione DevOps che andremo ad utilizzare in seguito all’interno della pipeline. 1.1 Vagrant Vagrant `e un programma creato nel 2010 da Mitchell Hashimoto e permette la creazione e manutenzione di macchine virtuali. La costruzione di una macchina virtuale `e interamente formalizzata al- l’interno di uno script, detto Vagrantfile, che permette di descrivere le ca- ratteristiche richieste all’interno di quest’ultima. Vagrant `e caratterizzato da 3 componenti principali, che entrano in gioco in successione nella creazione della macchina virtuale. Il primo sono le Vagrant Box. Ogni macchina virtuale viene generata a partire da una certa immagi- ne, detta Vagrant Box, che costituisce la base con il sistema operativo che andremo ad utilizzare come fondamenta nella costruzione. Esistono varie Box pronte all’uso che possono essere scaricare diretta- mente dal sito di Vagrant. Solitamente queste sono create e messe a disposizione da altri utenti o direttamente dal produttore del sistema operativo, a meno che non richiedano licenze particolari a pagamento, come nel caso di Windows o MacOS. Alternativamente, se dovessero esserci esigenze o prerequisiti partico- lari, `e sempre possibile creare una Box a partire da macchina virtuale preesistente. Il secondo sono i Providers. 5
  • 7. Il Provider `e il sistema utilizzato nella creazione della macchina vir- tuale. Quello di default `e VirtualBox, ma tramite un sistema di plugin `e possibile ottenere il supporto per altri provider, come ad esempio VMware, Google Cloud o Amazon AWS. Il terzo sono i Provisioners. I Provisioners sono gli strumenti che si occupano di configurare auto- maticamente la macchina in un certo modo una volta creata. Oltre alla possibilit`a di fornire direttamente comandi di shell, esiste il supporto anche a strumenti pi`u avanzati, fra i quali cito Ansible, Chef e Puppet che esamineremo in seguito. 1.2 Confronto sistemi provisioning In questa sezione descriveremo tre diversi sistemi di provisioning: Ansible, Chef e Puppet. Confronteremo fra loro le diverse caratteristiche di ognuno, decidendo infine qual `e tra questi lo strumento migliore, cio`e quello che si adatta meglio ai requisiti del nostro progetto. 1.2.1 Ansible Ansible `e un sistema di automazione open-source che permette il provisio- ning e la configurazione remota di macchine virtuali oltre all’installazione di applicazioni web. Come la maggior parte dei sistemi di provisioning, Ansible riconosce una architettura a due livelli, composta da una macchina di controllo e dai nodi. La caratteristica principale di Ansible `e la sua architettura agentless, che non richiede installazione di client sui nodi da gestire. Il funzionamento `e determinato da un Inventory, che contiene tutte le informazioni riguardo ai nodi da gestire pi`u tutte le operazioni da eseguire su ogni singolo nodo. Il Playbook che contiene le operazioni da eseguire sui nodi non `e un vero `e proprio script, `e invece la descrizione di uno ”stato” che la macchina deve avere. In base allo stato attuale della macchina verranno decretate quali fra le tante operazioni descritte vanno eseguite per raggiungere lo stato desiderato, e di conseguenza, i moduli relativi alle operazioni che verranno inviati ed eseguiti sui vari nodi. La comunicazione fra i il nodo di controllo e quello da controllare avviene tramite il protocollo SSH: una volta avvenuta la connessione il server di controllo invia dei moduli all’altro che vengono successivamente eseguiti. 6
  • 8. 1.2.2 Chef Chef `e uno strumento open-source di gestione della configurazione e provi- sioning. Utilizza una architettura a 3 strati composta da: Chef DK Il Chef Development Kit va installato su una workstation che sar`a utilizzata per la creazione dei vari script di configurazione ed installazione da eseguire sui nodi. Chef Server Agisce come server di controllo e contiene sia tutte le informa- zioni relative ai nodi da controllare che i ”Cookbook” con le operazioni da eseguire sui singoli nodi. Chef Client Deve essere in esecuzione su ogni nodo controllato, esegue un polling periodico sul server di controllo, se trova delle differenze le scarica e aggiorna il nodo allo stato definito dai Cookbook. Alternativamente alla modalit`a client / server, pu`o essere anche eseguito in modalit`a standalone ”chef-solo” direttamente sul nodo da controllare. La comunicazione fra il server e il client `e regolata da un protocollo proprietario. Viene utilizzata una coppia di chiavi RSA per l’autenticazione, questo previene che un nodo possa accedere a dati che non lo pertengono e assicura che vengano gestiti solo i nodi registrati. 1.2.3 Puppet Puppet `e uno strumento open-source per la gestione della configurazione del software. Sfrutta un linguaggio dichiarativo proprietario per la descrizione della configurazione dei nodi. Utilizza una struttura client / server, composta da: Puppet Master `e il server con tutte le istruzioni, detti ”Manifests”, per la configurazione dei nodi. Puppet Agent `e il client da installare su ogni nodo, si collega al server, recupera le configurazioni e le installa, comunicando il risultato al server. Puppet DB `e una parte opzionale della struttura che affianca il server e salva molte informazioni aggiuntive riguardo ai nodi e all’esecuzione di ogni operazione. La comunicazione fra client `e server avviene tramite Facter. Facter `e una libreria di profiling che comunica via protocollo HTTPS con il server, fornendogli informazioni relative al client come sistema operativo, IP e confi- gurazione attuale. Il server quindi risponde con la configurazione desiderata 7
  • 9. e fornisce i comandi specifici che l’agente del client dovr`a eseguire in base al sistema operativo presente sul nodo. Essendo la comunicazione basata su HTTPS sar`a necessario configurare dei certificati SSL, sia per il server che per il client, per autorizzare lo scambio di informazioni fra le varie parti. 1.2.4 Tabella di confronto sistemi provisioning In questa tabella confronteremo i tre sistemi di provisioning appena descritti in base alle caratteristiche ritenute pi`u importanti in riferimento al nostro progetto. ANSIBLE CHEF PUPPET In questi test tutti e 3 i sistemi di provisioning sono utilizzati a partire da una virtual machine Ubuntu 16.04 LTS “Xenial Xerus” 64 bit creata con Vagrant. Community La community `e molto nutrita in tutti e tre i casi. Que- sto garantisce che esister`a un certo livello di supporto per i plugin in futuro. Ansible Galaxy Chef Supermarket Puppet Forge Numero ”ricette” presenti 9713 3163 4716 Esistono molti duplicati per ogni singola ricetta, perch´e ma- gari lo stesso modulo viene creato da molti autori diver- si o con minime variazioni per risolvere problemi specifici. Un maggior numero di ricette non `e quindi necessariamente indice di maggior qualit`a delle ricette stesse o di maggior copertura software. Il numero di ricette per Windows o MacOS `e notevolmente inferiore al numero di ricette per Linux. Linguaggio Open source, Python Open source, Ruby Open source, Ruby Linguaggio di configu- razione e scripting Playbook scritti in YAML (Human Readable) Recipes e Coo- kbooks scritti in Ruby, ma non c’`e necessit`a di cono- scere il linguaggio per crearne uno Manifests scritti in Puppet langua- ge Architettura Agentless Client / Server + Workstation con ChefDK per la creazione delle ri- cette Client / Server 8
  • 10. Modo di funziona- mento Task eseguiti se- quenzialmente, se uno fallisce inter- rompe l’esecuzio- ne. Task eseguiti se- quenzialmente, se uno fallisce inter- rompe l’esecuzio- ne. Cerca di falli- re il prima possi- bile tramite anali- si dello script (es. file che manca- no. . . ). Task eseguiti in ordine casuale, ma supporta l’impostazione di un ordine preciso di esecuzione. Esegue ogni vol- ta tutti i task e segnala quanti falliscono o no. Tool aggiuntivi I moduli esterni necessari per l’e- secuzione vengo- no installati sulla workstation dove si esegue Ansible I moduli ester- ni vanno instal- lati con ChefDK e vengono salvati nel cookbook che dovr`a essere mes- so sul server Bisogna installare i moduli necessa- ri tramite coman- do sulla macchi- na ospite (`e possi- bile installarli au- tomaticamente in base al Manifest, ma cio`o richiede strumenti di ge- stione addiziona- li) Velocit`a di provisio- ning e update Dai test eseguiti la velocit`a `e essenzialmente la stessa con tutti e 3 i sistemi. In quanto il tempo di installazione `e det- tato pi`u dal tempo di scaricamento dei pacchetti da installa- re che dal tempo necessario all’esecuzione di un particolare provisioner. Supporto alla cloud La creazione delle macchine virtuali `e fornita da Vagrant che supporta di base VirtualBox, Hyper-V e Docker. Il supporto per la cloud, come ad esempio Amazon AWS o Google Cloud, `e fornita tramite plugin. Alla fine del confronto, in base a quelle che sono le esigenze del nostro progetto, `e stato deciso di utilizzare Ansible. La scelta `e stata dettata da: • semplicit`a di architettura: il sistema prevede solo una macchina ser- ver che va ad eseguire degli script su determinate macchine, non `e necessario organizzare e configurare nessun client; • linguaggio di scripting: sfruttando YAML, ovvero un linguaggio ”hu- man readable”, risulta molto pi`u chiaro e comprensibile rispetto agli altri; 9
  • 11. • minor impatto sulla macchina ospite: sfruttando una architettura agentless non necessita di installazioni di client sulle varie macchine ospite, eliminando quindi sia problemi di aggiornamento e manuten- zione degli stessi, che di contaminazione dell’ambiente di esecuzione; • praticit`a di installazione dei plugin: `e sufficiente installarli soltanto sulla macchina server; • pi`u adatto per le esigenze del nostro progetto: la creazione di macchine virtuali ad-hoc per il testing era pi`u in sintonia con il funzionamento di Ansible, in quanto esso prevede che sia il server quello che va ad applicare le modifiche sui nodi, al contrario, le altre due alternative prevedono un sistema in cui sono i singoli nodi quelli che vanno a prendere le configurazioni dal server centrale. Tutti questi elementi gli conferiscono una maggiore semplicit`a e lo ren- dono quello pi`u adatto all’utilizzo, relativamente al nostro caso d’uso. 1.3 Jenkins Jenkins `e un server di Continuous Integration open-source scritto in lin- guaggio Java. Permette di definire e automatizzare il processo di costruzione e installa- zione di un’applicazione, descrivendo in una pipeline tutti i passi, di cui so- litamente i pi`u importanti sono: compilazione, test e installazione, necessari per il deployment di un’applicazione web in produzione. Viene eseguito come servizio sulla macchina che lo ospita, configurazione e funzionamento sono completamente gestiti tramite interfaccia web. Questo permette l’installazione alternativamente su una macchina remota, quasi essenziale nel caso in cui il progetto software sia sviluppato da un team di programmatori, con necessit`a di accesso simultaneo per controllare svariate parti del processo. La struttura di Jenkins supporta dei plugin che permettono l’amplia- mento delle funzionalit`a della piattaforma di base. Funzionalit`a aggiuntive possono essere, ad esempio, l’interfacciamento con vari sistemi di gestione del codice sorgente o l’implementazione di diversi strumenti per il testing, fornendo una pratica interfaccia visuale per l’analisi dei risultati. Questo strumento sar`a il nocciolo attorno al quale andremo a costruire la pipeline di sviluppo software, fornendo la base di automazione da cui eseguire tutti gli altri strumenti necessari. 10
  • 12. Capitolo 2 Pipeline di sviluppo Lo scopo del lavoro di tesi `e quello di progettare una pipeline completa di sviluppo software. La pipeline prevede, oltre alla compilazione del codice, anche l’esecuzione di vari test che andranno eseguiti su delle macchine virtuali dove sar`a stata installata l’applicazione. La pipeline sar`a divisa in 3 principali sezioni o ”stage”: Stage 1 Compilazione dell’applicazione, test di unit`a e di integrazione. Stage 2 Test di carico e di interfaccia utente. Stage 3 Messa in produzione su Google Cloud. Introdurremo ora l’applicazione che andremo ad utilizzare. Esamineremo poi le configurazioni necessarie e le operazioni eseguite per ogni stage della pipeline. 2.1 Applicazione Si `e scelto di utilizzare Shopizer come applicazione di test per cui costruire la pipeline di sviluppo. Shopizer `e una applicazione open-source scritta in linguaggio Java che permette la creazione di siti web volti alla vendita di prodotti. Supporta due diversi tipi di DBMS: H2 e MySQL, che, date le loro diver- se caratteristiche, useremo separatamente nei primi due stage per eseguire differenti batterie di test. Elenchiamo ora i prerequisiti dell’applicazione, questi andranno soddi- sfatti dai vari strumenti che useremo in seguito: • lo strumento di build automation Maven, utilizzato sia per la compi- lazione, che per l’esecuzione dei test di unit`a e integrazione 11
  • 13. Figura 2.1: Schermata Home di un sito creato con Shopizer • un sistema operativo su cui far girare la macchina virtuale Java e l’ap- plication server: non viene richiesto niente di particolare, utilizzeremo un sistema operativo Linux Ubuntu 16.04 LTS “Xenial Xerus” a 64 bit • installazione di Java 8, di cui utilizzeremo la versione open source • un application server: utilizzeremo Apache Tomcat 8 • un server MySQL 2.2 Configurazione Jenkins Jenkins necessita di una configurazione alquanto limitata, in quanto, nono- stante sia il motore che muover`a il processo produttivo, recuperer`a tutte le informazioni relative alle operazioni da eseguire da un file di script salvato nel sistema di gestione sorgenti del progetto. Le operazioni da eseguire sono: • la creazione di uno o pi`u utenti che possano accedere al sistema. • L’installazione di tutti i plugin necessari al funzionamento della pipe- line, nel nostro caso essi sono: 12
  • 14. Plugin Pipeline essenziale, permette la creazione del percorso di sviluppo software Plugin Git necessario per recuperare il codice sorgente dell’applica- zione dalla repository Plugin JUnit necessario per la pubblicazione dei risultati dei vari test eseguiti con Maven • La creazione di un progetto di tipo Pipeline. • Configurare il progetto creato nel passo precedente in modo che possa prendersi lo script, detto Jenkinsfile, con le operazioni da eseguire nella Pipeline. Questo `e fatto semplicemente fornendo l’url della repository Git del nostro progetto. • Assicurarsi che la coppia di chiavi RSA sia presente nella cartella .ssh/ dell’utente jenkins e copia della chiave privata di autenticazione a Google Cloud nella cartella del progetto. Da questo momento `e sufficiente premere il tasto Build per eseguire automaticamente tutti i passi descritti nel Jenkinsfile. Se si dovesse verificare un errore in uno qualsiasi del vari passaggi, ver- rebbe interrotta l’esecuzione dei passi successivi e l’intera Pipeline verrebbe segnalata come “fallita”. 2.3 Architettura del sistema Il sistema sar`a strutturato nel modo seguente: avremo una macchina prin- cipale, che pu`o essere la nostra workstation o anche una macchina remota, dove sar`a installato Jenkins. Vista la mole di lavoro richiesta: compilazione di sorgenti e creazione di macchine virtuali, `e importante che sia fornita di un hardware abbastanza potente. Tutto il codice sorgente, sia relativo all’applicazione che ai vari file di script e configurazione necessari nel processo di sviluppo sono tutti versio- nati in una repository Git ospitata in locale sulla stessa macchina. Cionono- stante, alcuni file, come ad esempio chiavi private RSA o file contenenti dati sensibili, non possono essere salvati in sistemi di versionamento per motivi di sicurezza e verranno quindi installati a mano. Tutte le operazioni della pipeline verranno eseguite dall’utente jenkins a partire dalla cartella nel workspace relativa al nostro progetto. `E importante quindi assicurarsi che tutti i file necessari e i permessi sugli stessi siano impostati correttamente, Va fatta una distinzione importante: le operazioni che vedremo descritte all’interno del Jenkinsfile di configurazione della pipeline saranno eseguite 13
  • 15. in locale sulla macchina principale, tutti gli script Ansible invece verranno eseguiti sulle macchine virtuali create a richiesta. In generale avremo quindi Jenkins che eseguir`a in locale i comandi sulla sua pipeline, usando Vagrant per la creazione delle virtual machines che a sua volta richiamer`a gli script di Ansible per effettuare il provisioning. 2.4 Stage 1 - Build Tests In questa prima fase verr`a effettuata la compilazione del codice con supporto al DBMS H2, questo `e un DBMS residente in memoria e non ha bisogno di nessuna configurazione per funzionare, fornisce di conseguenza un ambiente pi`u semplice dove effettuare i primi test. Figura 2.2: Passi del primo stage della pipeline A cui corrisponde la seguente sezione di codice all’interno del Jenkinsfile, il codice completo `e disponibile in appendice a pagina 23: stage(’Clone Repository’) { git ’${repository_url}’ } stage(’Build’) { sh ’mvn clean install -DskipTests’ } stage(’Create Virtual Machine - Stage1’) { 14
  • 16. sh ’vagrant up stage1’ } La prima operazione fondamentale da eseguire `e la clonazione della repository con il codice sorgente. In seguito il codice viene compilato. Vengono saltati i test in questa prima fase in quanto necessitano della macchina virtuale funzionanente per poter essere eseguiti con successo. Viene quindi creata e configurata completamente la macchina virtuale. stage(’Tests - Stage1’) { try { sh ’mvn test’ } finally { junit ’sm-shop/target/surefire-reports/*.xml’ } } Ora che la macchina virtuale con l’applicazione `e funzionante, in que- st’ultima sezione vengono effettuati i test e, indipendentemente dal successo o fallimento della loro esecuzione, pubblicati i risultati. 2.4.1 Configurazione Vagrant Essendo questa la prima volta che lo incontriamo, descriviamo la configura- zione di Vagrant. La configurazione sar`a molto simile per quanto riguarda le prime due macchine virtuali che andremo a creare. Con riferimento al codice completo in appendice a pagina 26. Come prima cosa viene impostato il tipo di immagine da utilizzare per la creazione della macchina: config.vm.box = "ubuntu/xenial64" nel nostro caso un linux Ubuntu 16.04 LTS “Xenial Xerus”. In seguito viene eseguito il provisioning sulla macchina con Ansible. No- tiamo come viene installato, tramite comandi di shell di sistema, il linguaggio Python, necessario al funzionamento di Ansible sulla macchina ospite. stage1.vm.provision "shell", inline: <<-SHELL sudo apt-get update sudo apt-get install -y python SHELL In questa sezione viene richiamato per l’esecuzione lo script con la confi- gurazione desiderata della macchina virtuale. Il fatto che venga eseguito co- me sudo indica che avr`a poteri di amministratore all’interno della macchina, necessari per l’installazione dei vari programmi. 15
  • 17. stage1.vm.provision "ansible" do |ansible| ansible.playbook = "playbook-stage1.yml" ansible.sudo = true end 2.4.2 Script Ansible Con riferimento al codice completo in appendice a pagina 29. In questo primo caso lo script `e molto semplice. Ci si assicura che l’application server Tomcat 8 sia installato e funzio- nante. Vengono impostate alcune opzioni di Java, in quanto l’applicazione che stiamo usando necessita di una quantit`a di memoria superiore a quella che viene designata di default. L’ultimo passaggio `e quello di installazione dell’applicazione, per effet- tuarla `e sufficiente copiare il file sm-shop.war generato nella precedente fase di compilazione e copiarlo nella cartella webapps/ di Tomcat. 2.5 Stage 2 - Stress Tests In questa fase ricompileremo l’applicazione con il supporto per MySQL e in seguito installeremo una macchina virtuale su cui effettuare dei test di carico tramite JMeter e di usabilit`a con Selenium. Figura 2.3: Passi del secondo stage della pipeline 2.5.1 Configurazione Vagrant Sempre in riferimento al codice del Vagrantfile di prima a pagina 26. Notiamo che il codice per il secondo stage `e praticamente lo stesso, la differenza pi`u importante `e data dalla riga: stage2.vm.network "private_network", ip: "192.168.1.3" 16
  • 18. in cui viene configurata una rete virtuale fra la macchina principale e quella virtuale, questo passo `e necessario per permettere l’accesso diretto al da- tabase da parte di JMeter, in modo da potergli permettere di effettuare i test. 2.5.2 Script Ansible In riferimento al codice del playbook per Ansible relativo allo Stage 2 in appendice a pagina 31. In questo caso notiamo che lo script `e pi`u complicato rispetto al passato. Oltre all’installazione e configurazione di Tomcat come nello stage pre- cedente troviamo molte altre operazioni. Viene installato il server MySQL insieme ai prerequisiti per permettere ad Ansible di controllarlo. Vengono creati il database e l’utente che verr`a utilizzato dall’applicazione per accederci. `E importante notare che il database viene creato fornendogli uno script SQL, il cui scopo `e: aumentare il numero di prodotti con cui viene popolato inizialmente e impostare tutte le informazioni necessarie per configurare i pagamenti e le spedizioni, fondamentali per riuscire a completare un ordine. 2.5.3 Test con JMeter e Selenium In questa sezione introdurremo altri due strumenti, utilizzati per effettuare dei test di carico sulla nostra applicazione. JMeter JMeter `e uno strumento che permette l’esecuzione di test di carico su un sito web. I test sono composti da un certo elenco di pagine, JMeter procede ad effetturare una chiamata HTTP per ogni singola pagina dell’elenco. Se si volessero eseguire dei test su un database, al posto dell’elenco di pagine da visitare, ci sarebbe un elenco di query SQL da eseguire. In ognuno dei due casi sono necessarie altre tre informazioni: • il numero di threads, cio`e di utenti simulati, da eseguire in parallelo • il periodo di rampa, che imposta quanto a lungo ritardare la parten- za dei singoli utenti, ad esempio se impongo un periodo di 10 secondi, JMeter finir`a di far partire tutti i miei utenti virtuali dopo 10 secondi • il numero di ripetizioni da eseguire per ogni utente 17
  • 19. Selenium Selenium `e un programma che permette di automatizzare la navigazione di pagine web. Utilizza un plugin del browser web Firefox per creare i propri test, eseguibili singolarmente o in suite. La creazione di un test `e effettuata avviando la modalit`a di registrazio- ne la quale provvede a catturare le operazioni effettuate mentre si naviga manualmente sul sito. In seguito l’esecuzione dei test `e effettuata da un runner che, attraverso dei driver, controller`a i vari browser su cui lanciare i test automaticamente. Nel nostro caso, l’utente jenkins non aveva le autorizzazioni necessarie per eseguire programmi sul server grafico X11. Abbiamo dovuto quindi uti- lizzare Xvfb per creare un ambiente grafico virtuale dove far partire Chrome, che `e il browser con cui abbiamo effettuato i test. Una volta eseguiti i test, sia con JMeter che con Selenium, viene richia- mato un plugin di Jenkins che permette di salvare e pubblicare nell’inter- faccia della pipeline i file con i risultati. 2.6 Stage 3 - Deploy su Google Cloud In questa terza ed ultima fase descriveremo come `e stato effettuato il deploy dell’applicazione in un ambiente cloud. Figura 2.4: Passi del terzo stage della pipeline 18
  • 20. Per quanto sia il passo pi`u semplice dal punto di vista della pipeli- ne, richiede un certo numero di configurazioni da fare manualmente per la preparazione dell’ambiente di produzione su Cloud di Google. 2.6.1 Configurazione Google Cloud Come gi`a anticipato in precedenza ci sono parecchie operazioni da effettuare per poter configurare correttamente l’accesso e la conseguente creazione e gestione di macchine virtuali tramite Vagrant. Le varie operazioni da compiere sono le seguenti: • Eseguire l’accesso alla Google Developer Console con un utente Google. • Creare un progetto. • Nella sezione “Metadata”, importare le chiavi RSA pubbliche per la connessione via SSH fra Vagrant e la virtual machine in cloud. • Creare un account di servizio che verr`a utilizzato per eseguire tutte le operazioni sulle macchine virtuali. • Fornire all’account appena creato tutti i permessi necessari per poter funzionare correttamente. • Scaricare il file JSON con la chiave privata necessaria per autenticare automaticamente l’account di servizio. • Impostare correttamente le regole del firewall per permettere la con- nessione alla propria applicazione una volta installata. Di default tutte le connessioni remote alla macchina sono bloccate. 2.6.2 Configurazione Vagrant La configurazione di Vagrant differisce notevolmente rispetto agli stage pre- cendenti. Ci riferiamo nuovamente al codice completo del Vagrantfile a pagina 26. Utilizzeremo un nuovo provider, google e non pi`u virtualbox e sar`a necessario inoltre cambiare l’immagine di base, la Vagrant Box, in quanto Google fornisce direttamente una lista di immagini gi`a pronte da utilizzare. Vediamo le configurazioni nel dettaglio. Come prima cosa viene impostata la nuova immagine di base: stage3.vm.box = "google/gce" Inseriamo le informazioni con cui abbiamo configurato la Google Cloud: google.google_project_id = ’#{project_id}’ google.google_client_email = ’#{service_account_mail}’ google.google_json_key_location = ’#{json_private_key}’ 19
  • 21. Descriviamo il tipo di macchina virtuale che desideriamo creare: google.name = ’#{instance_name}’ google.zone = "europe-west1-d" google.machine_type = "n1-standard-1" google.image = "ubuntu-1604-xenial-v20170202" Queste informazioni comprendono: • il nome dell’istanza, cio`e della virtual machine, da creare • la zona dove creare l’istanza • il tipo di macchina desiderata, scegliendo quindi numero di processori e memoria da installare • l’immagine con il sistema operativo con cui creare la macchina Ultima configurazione da fare `e imporre lo stesso nome utente con cui abbiamo creato le chiavi RSA che abbiamo importato in Google Cloud, oltre ad assicurarci che prenda il file giusto con le chiavi. override.ssh.username = ’#{ssh_user_name}’ override.ssh.private_key_path = "~/.ssh/id_rsa" Oltre a queste impostazioni il resto dello script rimane invariato rispetto agli stage precedenti. 2.6.3 Script Ansible A causa della macchina di base leggermente diversa fra questo stage e quelli precedenti, alcuni passaggi dello script Ansible hanno dovuto esser modificati leggermente rispetto a prima per essere eseguiti senza problemi. Possiamo verificarlo confrontando i sorgenti in appendice alle pagine 31 (Stage 2) e 34 (Stage 3). Nonostante gli script di configurazione riportino alcune differenze fra di loro, il risultato finale dopo l’esecuzione `e lo stesso in entrambi i casi. 20
  • 23. Conclusioni Il progetto di creazione di una pipeline completa per l’automazione `e av- venuto con successo, dimostrando che `e possibile eliminare la necessit`a di esecuzione manuale di molte operazioni all’interno del processo di sviluppo software. Conseguenze di questo approccio automatizzato, oltre a quello di rispar- mio di tempo, sono di poter effettuare la messa in produzione di una appli- cazione in modo pi`u coerente, il che porta l’applicazione stessa ad essere pi`u stabile e sicura. Sviluppi futuri Possibili sviluppi futuri includono l’implementazione di nuove tipologie di test, come ad esempio test sulla sicurezza del sistema, per assicurarsi di non esporre un sistema vulnerabile alla rete. Un’altra tipologia di test da inserire sarebbe quella di test di accettazione da parte dell’utente, che tramite l’interfaccia stessa di Jenkins potrebbe autonomamente creare la propria istanza dell’applicazione, eseguire i test su una sessione browser aperta automaticamente e infine compilare un rapporto sul test sempre rimanendo all’interno dell’interfaccia di Jenkins. Fra gli sviluppi futuri possiamo anche includere la creazione di una repo- sitory aziendale di macchine virtuali per Vagrant, il che risponde alla neces- sit`a di avere macchine macchine di test configurate in modi molto particolari. Questo avviene soprattutto se consideriamo sistemi di test che necessitano di sistemi operativi Windows o MacOS dove l’installazione `e generalmente poco automatizzabile e richiede l’inserimento delle licenze d’uso che sono a pagamento. In alternativa, fornendo gi`a macchine pronte all’uso, una repository lo- cale pu`o essere utilizzata soltanto per evitare di sprecare inutilmente del tempo scaricando e installando gli stessi pacchetti software ogni volta che viene creata una nuova istanza per far girare i test. 22
  • 24. Codice sorgente Jenkinsfile Questo `e il codice sorgente della pipeline di sviluppo software creata con Jenkins. Verr`a eseguito sulla workstation dove avremo installato Jenkins e proceder`a a compilare l’applicazione e richiamare i comandi per la gestione delle virtual machine. #!groovy node { stage(’Clone Repository’) { // Clones the git repository with the source code of our // project git ’${git_url}’ } stage(’Build’) { // Builds the application, but skips tests that will be run // at a later stage in the pipeline sh ’mvn clean install -DskipTests’ } stage(’Create Virtual Machine - Stage1’) { try { // Destroy all existing virtual machines sh ’vagrant destroy --force’ sh ’vagrant up stage1’ } catch (err) { // Sends a email in case of an error during the creation // of the first virtual machine mail to: ’${user_mail}’, subject: ’ERRORE’, body: ’Si `e verificato un errore ${err.message}’ } } stage(’Tests - Stage1’) { 23
  • 25. try { // Runs the tests sh ’mvn test’ } finally { // Publishes the results using junit junit ’sm-shop/target/surefire-reports/*.xml’ } } stage(’Modify sources and build with MySQL support.’) { // Copies the file with the correct settings for building // the application with MySQL support sh ’cp database.properties sm-shop/src/main/resources/database.properties’ sh ’mvn clean install -DskipTests’ } stage(’Create Virtual Machine - Stage2’) { // Destroys out previous stage virtual machine and creates // the second one, this time including MySQL server sh ’vagrant destroy --force’ sh ’vagrant up stage2’ } stage(’Tests - Stage2’) { try { sh ’mvn test’ } finally { junit ’sm-shop/target/surefire-reports/*.xml’ } } stage(’Install JMeter’) { // Downloads and installs JMeter to a local directory if (fileExists(’apache-jmeter-3.1/’)) { } else { sh ’wget "${jmeter_url}"’ sh ’tar -xzf apache-jmeter-3.1.tgz’ } // Downloads and installs MySQL JDBC connector for JMeter if (fileExists(’${mysql_connector_name}’)) { } else { sh ’wget ${mysql_connector_url}’ sh ’tar -C apache-jmeter-3.1/lib/ --strip-components 1 -xzf ${mysql_connector_name}’ } } 24
  • 26. stage(’Tests with JMeter’) { // Needs this wait time for the Vm to get online. sh ’sleep 2m’ // Load test webapp sh ’./apache-jmeter-3.1/bin/jmeter -n -t jmeter-test.jmx -l jmeter-test.jtl’ // Load test database sh ’./apache-jmeter-3.1/bin/jmeter -n -t jmeter-mysql.jmx -l jmeter-mysql.jtl’ // Publish test result archiveArtifacts ’jmeter-test.jtl, jmeter-mysql.jtl, jmeter.log’ } stage(’Install Selenium and chromedriver’) { // Install selenium if (fileExists(’${selenium_name}’)) { } else { sh ’wget ${selenium_url}’ } // Install chromedriver if (fileExists(’chromedriver’)) { } else { sh ’wget ${chromedriver_url}’ sh ’unzip ${chromedriver_name}’ } } stage(’Tests with Selenium’) { // Run a script where we // setup xvfb for headless chrome // and run selenium tests sh ’sh selenium-test.sh’ // Publish test result archiveArtifacts ’selenium-results.htm’ } stage(’Deploy on Google Cloud’) { sh ’vagrant up stage3 --provider=google’ } } 25
  • 27. Vagrantfile Questo `e il codice sorgente di Vagrant utilizzato nella creazione delle virtual machine. # -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don’t change it unless you know what # you’re doing. Vagrant.configure("2") do |config| # Every Vagrant development environment requires a box. You can # search for boxes at https://atlas.hashicorp.com/search. config.vm.box = "ubuntu/xenial64" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # ‘vagrant box outdated‘. This is not recommended. # config.vm.box_check_update = false config.vm.provider "virtualbox" do |vb| # Customize the amount of memory on the VM: vb.memory = "2048" end # Create virtual machine for Stage1 (H2 database) config.vm.define "stage1" do |stage1| # stage1.vm.network "private_network", ip: "192.168.1.2" # We need this port forwarding to avoid conflicts, because the # localhost is already hosting the Jenkins server on port 8080 stage1.vm.network "forwarded_port", guest: 8080, host: 8085 # We need to make sure to have python installed to allow Ansible # to work stage1.vm.provision "shell", inline: <<-SHELL sudo apt-get update sudo apt-get install -y python SHELL # This calls the Ansible script for provisioning stage1.vm.provision "ansible" do |ansible| 26
  • 28. ansible.playbook = "playbook-stage1.yml" # Running the script as sudo grants us root permissions on the # virtual machine, we need this since we are installing # new packages ansible.sudo = true end end # Create virtual machine for Stage2 (MySQL) config.vm.define "stage2" do |stage2| # In this case we also give the machine an ip address to allow # direct connection to the database to run tests stage2.vm.network "private_network", ip: "192.168.1.3" stage2.vm.network "forwarded_port", guest: 8080, host: 8087 stage2.vm.provision "shell", inline: <<-SHELL sudo apt-get update sudo apt-get install -y python SHELL stage2.vm.provision "ansible" do |ansible| ansible.playbook = "playbook-stage2.yml" ansible.sudo = true end end # Create virtual machine for Stage3 (Google Cloud) config.vm.define "stage3" do |stage3| stage3.vm.box = "google/gce" stage3.vm.provider :google do |google, override| # This is out private informations section google.google_project_id = "#{project_id}" google.google_client_email = "#{service_account_mail}" google.google_json_key_location = "#{json_private_key}" # In this section we describe the machine we want to create # Define the name of the instance. google.name = "#{instance_name}" # Set the zone where the instance will be located. # To find out available zones: # ‘gcloud compute zones list‘. 27
  • 29. google.zone = "europe-west1-d" # Set the machine type to use. To find out available types: # ‘gcloud compute machine-types list --zone asia-east1-c‘. google.machine_type = "n1-standard-1" # Set the machine image to use. To find out available images: # ‘£ gcloud compute images list‘. google.image = "ubuntu-1604-xenial-v20170202" # We override the default connection settings to match those # in our RSA keys override.ssh.username = "#{ssh_user_name}" override.ssh.private_key_path = "~/.ssh/id_rsa" end stage3.vm.provision "shell", inline: <<-SHELL sudo apt-get update sudo apt-get install -y python SHELL stage3.vm.provision "ansible" do |ansible| ansible.playbook = "playbook-stage3.yml" ansible.verbose = true ansible.sudo = true end end end 28
  • 30. Ansible - playbook-stage1.yml Questo `e lo script di Ansible per il provisioning della prima macchina vir- tuale. In questo caso viene semplicemente installato e configurato Tomcat ed effettuato il deploy dell’applicazione. --- - hosts: all vars_files: - vars.yml tasks: - name: Ensure Tomcat 8 is installed. apt: name: tomcat8 state: installed - name: Replace Old Java options for Tomcat 8. lineinfile: dest: /etc/default/tomcat8 regexp: ’^JAVA_OPTS’ line: ’JAVA_OPTS="-Djava.awt.headless=true -XX:+UseConcMarkSweepGC"’ state: present - name: Set New Java options for Tomcat 8. # We need to set these options because our application requires # more memory than what is provided by default lineinfile: dest: /etc/default/tomcat8 insertafter: ’^JAVA_OPTS’ line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m -Xmx1024m -XX:MaxPermSize=256m"’ state: present - name: Restart Tomcat 8 with the new options. service: name: tomcat8 state: restarted enabled: yes - name: Change /var/lib/tomcat8 permissions. # When created tomcat8 directory is owned by root, we restore # the correct ownership to allow tomcat to create his own files 29
  • 31. file: path: /var/lib/tomcat8 owner: tomcat8 group: tomcat8 - name: Deploy application. # To deploy the application we just need to copy the war package # inside the webapps directory in tomcat home directory become: yes become_user: root copy: src: sm-shop/target/{{ snapshot_name }} dest: /var/lib/tomcat8/webapps/sm-shop.war 30
  • 32. Ansible - playbook-stage2.yml Questo `e lo script di Ansible per il provisioning della seconda macchina virtuale. In questo caso, oltre ad installare Tomcat, viene installato e con- figurato il server MySQL, creato e popolato il database per l’applicazione e creato l’utente per la connessione al database. --- - hosts: all vars_files: - vars.yml tasks: - name: Ensure Tomcat 8 is installed. apt: name: tomcat8 state: installed - name: Replace Old Java options for Tomcat 8. lineinfile: dest: /etc/default/tomcat8 regexp: ’^JAVA_OPTS’ line: ’JAVA_OPTS="-Djava.awt.headless=true -XX:+UseConcMarkSweepGC"’ state: present - name: Set New Java options for Tomcat 8. # We need to set these options because our application requires # more memory than what is provided by default lineinfile: dest: /etc/default/tomcat8 insertafter: ’^JAVA_OPTS’ line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m -Xmx1024m -XX:MaxPermSize=256m"’ state: present - name: Restart Tomcat 8 with the new options. service: name: tomcat8 state: restarted enabled: yes - name: Change /var/lib/tomcat8 permissions. # When created tomcat8 directory is owned by root, we restore 31
  • 33. # the correct ownership to allow tomcat to create his own files file: path: /var/lib/tomcat8 owner: tomcat8 group: tomcat8 - name: Ensure MySQL server is installed. apt: name: "{{ item }}" state: installed with_items: - mysql-server - mysql-client - python-mysqldb - name: Ensure MySQL server is running. service: name: mysql state: started enabled: yes - name: Copy the mysqld.cnf # This configuration file contains the setting to allow remote # connection to the database become: yes become_user: root copy: src: mysqld.cnf dest: /etc/mysql/mysql.conf.d/mysqld.cnf - name: Restart MySQL service: name: mysql state: restarted - name: Create and populate SALESMANAGER MySQL database # Using the import function we automatically execute the given # SQL script on creation mysql_db: name: SALESMANAGER state: import target: /vagrant/SALESMANAGER-dump.sql - name: Copy static data 32
  • 34. # These are the files where the CMS saves static images copy: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: tomcat8 group: tomcat8 with_items: - { src: ’StoreRepository.dat’, dest: ’/var/lib/tomcat8/files/store/’ } - { src: ’FilesRepository.dat’, dest: ’/var/lib/tomcat8/files/repos/’ } - name: Create user for SALESMANAGER MySQL database mysql_user: name: "{{ db.user }}" password: "{{ db.password }}" host: "{{ item }}" priv: "*.*:ALL,GRANT" state: present with_items: - "{{ db.host }}" - localhost - name: Deploy application. # To deploy the application we just need to copy the war package # inside the webapps directory in tomcat home directory become: yes become_user: root copy: src: sm-shop/target/{{ snapshot_name }} dest: /var/lib/tomcat8/webapps/sm-shop.war 33
  • 35. Ansible - playbook-stage3.yml Questo `e lo script di Ansible per il provisioning della terza macchina virtuale. A causa di diverse configurazioni di sicurezza rispetto alle macchine prece- denti, alcuni comandi sono stati leggermente modificati. Nonostante tutti il risultato `e identico rispetto all’esecuzione dello script per l’installazione della macchina virtuale precedente. --- - hosts: all vars_files: - vars.yml tasks: - name: Ensure Tomcat 8 is installed. apt: name: tomcat8 state: installed - name: Replace Old Java options for Tomcat 8. lineinfile: dest: /etc/default/tomcat8 regexp: ’^JAVA_OPTS’ line: ’JAVA_OPTS="-Djava.awt.headless=true -XX:+UseConcMarkSweepGC"’ state: present - name: Set New Java options for Tomcat 8. # We need to set these options because our application requires # more memory than what is provided by default lineinfile: dest: /etc/default/tomcat8 insertafter: ’^JAVA_OPTS’ line: ’JAVA_OPTS="${JAVA_OPTS} -Xms1024m -Xmx1024m -XX:MaxPermSize=256m"’ state: present - name: Restart Tomcat 8 with the new options. service: name: tomcat8 state: restarted enabled: yes - name: Change /var/lib/tomcat8 permissions. 34
  • 36. # When created tomcat8 directory is owned by root, we restore # the correct ownership to allow tomcat to create his own files file: path: /var/lib/tomcat8 owner: tomcat8 group: tomcat8 - name: Ensure MySQL server is installed. apt: name: "{{ item }}" state: installed with_items: - mysql-server - mysql-client - python-mysqldb - name: Ensure MySQL server is running. service: name: mysql state: started enabled: yes - name: Copy static data # These are the files where the CMS saves static images copy: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: tomcat8 group: tomcat8 with_items: - { src: ’StoreRepository.dat’, dest: ’/var/lib/tomcat8/files/store/’ } - { src: ’FilesRepository.dat’, dest: ’/var/lib/tomcat8/files/repos/’ } - name: Create user for SALESMANAGER MySQL database mysql_user: name: "{{ db.user }}" password: "{{ db.password }}" host: "{{ item }}" priv: "*.*:ALL,GRANT" state: present with_items: - "{{ db.host }}" 35
  • 37. - localhost - name: Create SALESMANAGER MySQL database # Due to different security setting in this case we have to # create the database and then populate it at a later time mysql_db: name: SALESMANAGER state: present - name: Populate SALESMANAGER MySQL database mysql_db: name: SALESMANAGER login_user: "{{ db.user }}" login_password: "{{ db.password }}" state: import target: /vagrant/SALESMANAGER-dump.sql - name: Deploy application. become: yes become_user: root copy: src: sm-shop/target/{{ snapshot_name }} dest: /var/lib/tomcat8/webapps/sm-shop.war 36
  • 38. Bibliografia [1] Gene Kim, Jez Humble, Patrick Debois & John Willis. The DevOps Handbook. IT Revolution Press, 2016. [2] Jeff Geerling. Ansible for DevOps. Leanpub, 2015. [3] Ansible Website: https://www.ansible.com/ Wiki: https://en.wikipedia.org/wiki/Ansible_(software) Github: https://github.com/ansible/ansible [4] Chef Website: https://www.chef.io/ Wiki: https://en.wikipedia.org/wiki/Chef_(software) Github: https://github.com/chef/chef [5] Puppet Website: https://puppet.com/ Wiki: https://en.wikipedia.org/wiki/Puppet_(software) Github: https://github.com/puppetlabs/puppet [6] Vagrant Website: https://www.vagrantup.com/ Wiki: https://en.wikipedia.org/wiki/Vagrant_(software) Github: https://github.com/mitchellh/vagrant [7] Jenkins Website: https://jenkins.io/ Wiki: https://en.wikipedia.org/wiki/Jenkins_(software) Github: https://github.com/jenkinsci [8] JMeter Website: http://jmeter.apache.org/ Wiki: https://en.wikipedia.org/wiki/Apache_JMeter [9] JMeter - Building a Web Test Plan http://jmeter.apache.org/usermanual/build-web-test- plan.html 37
  • 39. [10] JMeter - Recording Tests http://jmeter.apache.org/usermanual/jmeter_proxy_step_by_ step.pdf [11] Selenium Website: http://www.seleniumhq.org/ Wiki: https://en.wikipedia.org/wiki/Selenium_(software) Github: https://github.com/SeleniumHQ/selenium [12] Shopizer Website: http://www.shopizer.com Wiki: https://github.com/shopizer-ecommerce/shopizer/wiki Github: https://github.com/shopizer-ecommerce/shopizer [13] Setup Development Environment with Vagrant on Google Compute Engine https://realguess.net/2015/09/07/setup-development- environment-with-vagrant-on-google-compute-engine/ [14] Compute Engine Management with Puppet, Chef, Salt, and Ansible https://cloud.google.com/solutions/google-compute-engine- management-puppet-chef-salt-ansible [15] Provider ufficiale per Google Compute Engine (GCE) di Vagrant https://github.com/mitchellh/vagrant-google 38