GitLab, un completo strumento DevOps – Parte 1: installazione e configurazione

Introduzione

Si fa in fretta dire DevOps, ma quando si arriva all’atto pratico, è inutile girarci attorno, chi davvero può definirsi un DevOp? Basti pensare alla nomenclatura: in italiano, i termini inglesi plurali andrebbero riportati senza la “s”, ma quanta gente si vanta di essere “un DevOps“? Finché è un errore grammaticale va tutto bene, ma quando poi si arriva al plurale maiestatis e multi-personalità le cose iniziano a farsi preoccupanti.

Scherzi a parte, la precisazione è d’obbligo: la parola DevOps identifica uno specifico set di strumenti e metodologie lavorative che consentono di ottimizzare i processi di gestione del ciclo di vita delle applicazioni.

Questa serie di articoli si pone l’obiettivo di chiarire il concetto di DevOps nella pratica, mediante l’utilizzo di uno strumento che a detta di molti (Forrester su tutti) rappresenta la migliore espressione di quanto il mercato ha da offrire in materia: GitLab.

Chi può dirlo poi, alla fine di tutto sarà bello magari trovarsi davanti a una birra ed affermare coscienziosamente: sì, io sono un DevOp. O almeno ci provo

GitLab, il principio e la fine

Tagliando subito la testa al toro: cos’è GitLab? Un’azienda? Un servizio pubblico di repository Git? Un software che si può installare sulla propria macchina? Un’alternativa a GitHub?

La risposta è: tutte queste cose.

Per quanto concerne nello specifico l’obiettivo di questa serie di articoli però la definizione che calza meglio GitLab è quella presente sul sito stesso:

GitLab is a complete DevOps platform, delivered as a single application. From project planning and source code management to CI/CD, monitoring, and security.

GitLab è una piattaforma DevOps completa, distribuita come una singola applicazione che gestisce la pianificazione dei progetti ed il codice sorgente fino alla CI/CD, monitoraggio e sicurezza.

Niente di più chiaro quindi.

Quanto si cercherà di implementare in questa serie di articoli è appunto l’intero processo che governa il ciclo vitale di una applicazione: dalla singola linea di codice alla sua pubblicazione in produzione. Dal principio, alla fine.

Installare GitLab: con i container è più bello

Pur non scendendo molto nei dettagli di come i container funzionano, è essenziale comprendere l’efficacia del loro utilizzo in un contesto come quello che si sta andando ad implementare.

Installare un’applicazione complessa come GitLab mediante container consente di non doversi preoccupare delle dipendenze software, rendere l’intero sistema trasportabile ed in generale ottimizzare i tempi.

Basterà fissare alcune cartelle per avere tutto lo scibile relativo al programma accessibile:

rasca@anomalia [~]> mkdir -p /home/rasca/gitlab/{config,logs,data}

Ed avviare il container mediante il comando docker, con alcune specifiche opzioni:

rasca@anomalia [~]> sudo docker run --detach --name gitlab --restart always --volume /home/rasca/gitlab/config:/etc/gitlab --volume /home/rasca/gitlab/logs:/var/log/gitlab --volume /home/rasca/gitlab/data:/var/opt/gitlab --hostname gitlab.mmul.local --publish 443:443 --publish 80:80 --publish 22:2222 gitlab/gitlab-ce:latest

Come spiegato poco sopra spiegare come funziona docker non è fra gli obiettivi di questo articolo (potrebbe essere utile dare un’occhiata alla serie di Matteo Cappadonna sull’argomento), ma spiegare le opzioni passate può aiutare a comprendere lo stato generale delle cose:

È stato avviato mediante il comando docker run un container in modalità detached (--detach ossia in modalità non interattiva) denominato gitlab (--name) la cui politica di riavvio (--restart) sarà always (cioè il demone docker cercherà sempre di riavviare il servizio se questo venisse interrotto) e che effettua il mapping di tre cartelle locali (quelle create sopra) con le tre relative all’interno del container (tutte le opzioni --volume). Tutto quello che serve a GitLab è all’interno di queste cartelle e se ci state pensando, sì, per trasportare l’applicazione (o effettuare un backup) basterà conservare queste cartelle.

Infine l’applicazione verrà esposta su tre porte: http (80), https (443) e ssh (2222) mediante l’opzione --publish. Da notare come la mappatura delle porte TCP è direttamente dipendente da quanto già presente nel proprio sistema, infatti se qualcuna delle porte menzionate è già occupata (vedi ad esempio quella relativa ad ssh) allora scegliere una porta differente potrebbe essere la scelta più giusta.

L’immagine di partenza sarà la versione latest di gitlab-ce, disponibile sul Docker Hub nel repository denominato gitlab.

Dopo qualche secondo (o minuto, o ora se la propria connessione è a 56Kb) l’output della console dovrebbe mostrare qualcosa di simile a questo:

Unable to find image 'gitlab/gitlab-ce:latest' locally
latest: Pulling from gitlab/gitlab-ce
f7277927d38a: Pull complete 
8d3eac894db4: Pull complete 
edf72af6d627: Pull complete 
3e4f86211d23: Pull complete 
4ec7e7d7a45c: Pull complete 
65a276d83919: Pull complete 
ff3f6b1a97bb: Pull complete 
54cbf5dfca45: Pull complete 
4f7521f24b40: Pull complete 
fcce27c8dfc4: Pull complete 
Digest: sha256:cb473b6df91ca6657ae3e1135224aa09b0507a3511383cc704b67f81956e9e0d
Status: Downloaded newer image for gitlab/gitlab-ce:latest
79585c89d7c02b49bb469fc0e2cbe4417fc5fcf93a61a4ad70ff52b975f83080

Ed una rapida occhiata dovrebbe poter confermare che le porte mappate siano effettivamente in ascolto:

rasca@anomalia [~]> ss -nltp '( sport = :443 or sport = :80 or sport = :2222 )'
State    Recv-Q    Send-Q        Local Address:Port        Peer Address:Port    
LISTEN   0         128                       *:2222                   *:*       
LISTEN   0         128                       *:80                     *:*       
LISTEN   0         128                       *:443                    *:*

Una rapida occhiata mediante browser mostrerà come alla porta 80 di localhost il servizio accessibile:

All’interno delle cartelle mappate sui volumi si potrà inoltre notare come il processo di avvio abbia creato dei file:

rasca@anomalia [~]> sudo find gitlab/
gitlab/
...
...
gitlab/logs/nginx/gitlab_access.log
gitlab/logs/nginx/error.log
gitlab/logs/nginx/gitlab_error.log
gitlab/logs/nginx/config
...
...
gitlab/data/grafana/data/grafana.db
gitlab/data/grafana/data/plugins
...
...
gitlab/config/gitlab.rb
gitlab/config/ssh_host_ed25519_key.pub
gitlab/config/trusted-certs
gitlab/config/ssh_host_ecdsa_key
gitlab/config/ssh_host_rsa_key.pub
gitlab/config/ssh_host_ecdsa_key.pub

Il contenuto della cartella rappresenta l’interezza dell’installazione effettuata. Stoppando il container, prendendo la cartella gitlab e spostandola su un’altra macchina, replicando il comando usato sopra, si otterrà la stessa identica installazione.

Configurazione preliminare

Quanto effettuato sinora rappresenta meramente un’installazione base dell’ambiente GitLab, tant’è che ogni tentativo di connessione via https fallirà miseramente:

Alcuni aspetti della configurazione vanno quindi modificati, in modo da permettere all’ambiente di comportarsi secondo le aspettative.

Abilitare SSL

In fase di avvio del container abbiamo passato un parametro denominato --hostname il cui valore era gitlab.mmul.local. Idealmente questo nome dovrebbe essere risolto dalla nostra macchina in modo da poter basare l’abilitazione SSL su questo nome specifico.

Per l’esempio specifico trattato l’indirizzo ideale da associare alla url è quello dell’interfaccia docker0:

rasca@anomalia [~]> ip addr show dev docker0
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:d3:e7:0d:12 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d3ff:fee7:d12/64 scope link 
       valid_lft forever preferred_lft foreve

esposta sull’host e visibile da tutti i container. Pertanto la risoluzione del nome sarà la seguente:

rasca@anomalia [~]> ping -c2 gitlab.mmul.local
PING gitlab.mmul.local (172.17.0.1) 56(84) bytes of data.
64 bytes from gitlab.mmul.local (172.17.0.1): icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from gitlab.mmul.local (172.17.0.1): icmp_seq=2 ttl=64 time=0.057 ms

--- gitlab.mmul.local ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1019ms
rtt min/avg/max/mdev = 0.038/0.047/0.057/0.011 

Questo significa che all’interno del file /etc/hosts è stata aggiunta una riga simile a questa:

172.17.0.1       gitlab.mmul.local

Il nome gitlab.mmul.local risponde pertanto a 172.17.0.1.

Ora che abbiamo il nome, manca da creare il certificato e da renderlo disponibile a GitLab. Tutto questo è fattibile creando la cartella ssl nel path gitlab/config e generandovi al suo interno la chiave ed il certificato ad essa associato:

rasca@anomalia [~/gitlab/config]> sudo mkdir ssl
rasca@anomalia [~/gitlab/config]> cd ssl
rasca@anomalia [~/gitlab/config/ssl]> sudo openssl genrsa -out gitlab.mmul.local.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.................+++++
....................................................+++++
e is 65537 (0x010001)
rasca@anomalia [~/gitlab/config/ssl]> sudo openssl req -new -key gitlab.mmul.local.key -out gitlab.mmul.local.csr -subj "/CN=gitlab.mmul.local"
rasca@anomalia [~/gitlab/config/ssl]> sudo openssl x509 -req -days 366 -in gitlab.mmul.local.csr -signkey gitlab.mmul.local.key -out gitlab.mmul.local.crt
Signature ok
subject=CN = gitlab.mmul.local
Getting Private key

L’operazione avrà creato i seguenti file:

rasca@anomalia [~/gitlab/config/ssl]> ls -l 
total 12
 -rw-r--r-- 1 root root 1013 ago 20 15:03 gitlab.mmul.local.crt
 -rw-r--r-- 1 root root  903 ago 20 15:02 gitlab.mmul.local.csr
 -rw------- 1 root root 1675 ago 20 15:01 gitlab.mmul.local.key

Che andranno quindi attivati all’interno del file di configurazione di GitLab, disponibile nel path gitlab/config/gitlab.rb mediante la modifica delle seguenti opzioni, peraltro le uniche attivate all’interno del file:

external_url 'https://gitlab.mmul.local'
nginx['redirect_http_to_https'] = true
nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.mmul.local.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.mmul.local.key"

A questo punto non rimane altro da fare attivare le modifiche effettuate, mediante questa semplice invocazione di docker:

rasca@anomalia [~]> sudo docker exec -it gitlab gitlab-ctl reconfigure
Starting Chef Client, version 14.13.11
resolving cookbooks for run list: ["gitlab"]
...
...

Viene detto al comando docker di eseguire (exec), allocando un terminale in modalità interattiva (-it), all’interno del container gitlab, il comando gitlab-ctl reconfigure che si occuperà di leggere e applicare le modifiche effettuate alla configurazione di GitLab.

Una volta che il processo di riconfigurazione (basato su ricette Chef) è completato sarà possibile verificare dal browser come l’indirizzo https adesso risponda:

Certo, il sito è considerato un potenziale rischio poiché il suo certificato è auto generato, ma una volta confermata l’eccezione di sicurezza avremo la possibilità di fruire dei servizi mediante https. Non solo, una volta che si proverà a contattare il sito all’indirizzo http://gitlab.mmul.local si verrà automaticamente rediretti alla versione https:

Da notare infine come GitLab supporti nativamente i certificati letsencrypt che consentono una gestione SSL completa con il solo inserimento della mail all’interno del file di configurazione.

Conclusioni

La prima puntata di questa serie termina qui, GitLab è raggiungibile mediante protocollo https ed è già completamente funzionante. Nel prossimo episodio verrà approfondita l’interfaccia, creato un progetto e descritta l’iterazione che porta alla gestione delle issue direttamente da GitLab.

Insomma, il meglio deve ancora venire!

Tags: , , ,