{"id":4540,"date":"2022-05-27T13:58:00","date_gmt":"2022-05-27T11:58:00","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=4540"},"modified":"2022-06-30T15:32:21","modified_gmt":"2022-06-30T13:32:21","slug":"un-approccio-serverless-per-lintegrazione-con-gitlab-su-aws","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/un-approccio-serverless-per-lintegrazione-con-gitlab-su-aws\/","title":{"rendered":"Un approccio serverless per l’integrazione con GitLab su AWS"},"content":{"rendered":"\n
L\u2019ottimizzazione dei costi e l\u2019eccellenza operativa sono fattori determinanti per una strategia vincente, che porti all\u2019adozione del paradigma Cloud. I servizi gestiti serverless consentono di ridurre drasticamente i costi e di velocizzare le operazioni di mantenimento dell\u2019infrastruttura.<\/p>\n\n\n\n
In questo articolo descriveremo come integrare le pipeline GitLab su AWS usando ECS Fargate in uno scenario multi-ambiente.<\/p>\n\n\n\n
GitLab, per quanto riguarda l\u2019utilizzo di risorse computazionali, offre una grande flessibilit\u00e0: le pipeline possono essere eseguite da cluster Kuberenetes, Docker, su virtual machine on prem o su piattaforme personalizzate usando driver custom.<\/p>\n\n\n\n
La soluzione pi\u00f9 diffusa per l\u2019esecuzione di pipeline sul Cloud AWS prevede l\u2019utilizzo di istanze EC2. Questo approccio porta ad alcune inefficienze: avviare le istanze on-demand aumenta il tempo di esecuzione, rendendo impazienti gli sviluppatori (a causa del tempo di inizializzazione). Tenere attive istanze \u201cdi scorta\u201d durante la giornata disponibili per le build, di contro, aumenta i costi. <\/p>\n\n\n\n
Il nostro obiettivo \u00e8 trovare una soluzione che possa ridurre il tempo di esecuzione, facilitare la manutenzione e ottimizzare i costi.<\/p>\n\n\n\n
I container, ad esempio, hanno un tempo di avvio breve e aiutano a contenere i costi: in questo caso d\u2019uso il billing sarebbe proporzionale solamente al tempo di esecuzione effettivamente utilizzato. <\/p>\n\n\n\n
Per raggiungere il nostro obiettivo faremo in modo di eseguire su task ECS Fargate le nostre build. In aggiunta vedremo anche come utilizzare i servizi ECS per implementarle e gestirne l\u2019autoscaling. <\/p>\n\n\n\n
Prima di passare all\u2019implementazione pratica una piccola premessa: GitLab, per eseguire gli script definiti nelle pipeline, utilizza un agent software chiamato GitLab Runner, possiamo configurare una istanza del runner dedicata alla gestione dello scaling che si occupi di aggiungere e rimuovere risorse computazionali in base all\u2019andamento delle richieste.<\/p>\n\n\n\n
Nei nostri esempi assumeremo che siano utilizzati tre ambienti: sviluppo (dev), test (staging) e produzione (prod), utilizzeremo ruoli IAM differenti per i nostri runner per limitare i permessi assegnati ed utilizzare il principio di least privilege.<\/p>\n\n\n\n
I runner GitLab possono essere associati a tag che rendono possibile la scelta dell\u2019ambiente in cui verranno eseguite le build.<\/p>\n\n\n\n
In questo esempio \u00e8 definita una pipeline che compila e fa il deploy in 3 ambienti differenti:<\/p>\n\n\n\n
Implementare un runner Fargate base<\/strong><\/h2>\n\n\n\n
Assumendo che il nostro software sia scritto utilizzando NodeJS possiamo sviluppare un Dockerfile che permetta di fare la build di una immagine Docker contenente tutte le dipendenze (GitLab runner incluso).<\/p>\n\n\n\n
#!\/bin\/sh \n \n# Create a folder to store the user's SSH keys if it does not exist. \nUSER_SSH_KEYS_FOLDER=~\/.ssh \n[ ! -d ${USER_SSH_KEYS_FOLDER} ] && mkdir -p ${USER_SSH_KEYS_FOLDER} \n \n# Copy contents from the `SSH_PUBLIC_KEY` environment variable \n# to the `$USER_SSH_KEYS_FOLDER\/authorized_keys` file. \n# The environment variable must be set when the container starts. \necho \"${SSH_PUBLIC_KEY}\" > ${USER_SSH_KEYS_FOLDER}\/authorized_keys \n \n# Clear the `SSH_PUBLIC_KEY` environment variable. \nunset SSH_PUBLIC_KEY \n \n# Start the SSH daemon \n\/usr\/sbin\/sshd -D<\/code><\/pre>\n\n\n\n
<\/p>\n\n\n\n
<\/p>\n\n\n\n
In questo caso non c\u2019\u00e8 nessuna dipendenza dall\u2019ambiente in cui l\u2019immagine dovr\u00e0 essere eseguita.<\/p>\n\n\n\n
Implementare un runner per l\u2019autoscaling (Runner Manager)<\/strong><\/p>\n\n\n\n
Questo tipo di runner deve essere specializzato per poter gestire l\u2019ambiente in cui dovr\u00e0 essere eseguito: adotteremo il Fargate custom executor sviluppato da GitLab per utilizzare cluster ECS Fargate differenti per i nostri ambienti.<\/p>\n\n\n\n
La registrazione del nostro runner con il server GitLab sar\u00e0 automatizzata ed eseguita durante la fase di build, usando variabili per specificare il token e gli altri parametri di configurazione.<\/p>\n\n\n\n
Il custom executor Fargate necessita di un file di configurazione (\u201cconfig.toml\u201d) per poter specificare il cluster, le subnet, i security groups e la task definition da utilizzare per l\u2019esecuzione della pipeline. Faremo in modo di automatizzare anche questa configurazione nella fase di build del container.<\/p>\n\n\n\n
Per prima cosa dobbiamo ottenere un token per la registrazione del runner con il server GitLab.<\/p>\n\n\n\n
Alla sezione \u201cCI\/CD\u201d nelle impostazioni del progetto si pu\u00f2 espandere la sezione \u201cRunners\u201d.<\/p>\n\n\n\n
<\/p>\n\n\n\n<\/figure>\n\n\n\n
<\/p>\n\n\n\n
Gli unici dati necessari sono il registration Token e l\u2019indirizzo del server GitLab.<\/p>\n\n\n\n
L\u2019indirizzo del server GitLab pu\u00f2 essere anche inserito direttamente nel Dockerfile, tratteremo invece il token di registrazione come un segreto.<\/p>\n\n\n\n
Queste righe, contenute nel Dockerfile, si occupano della modifica del file di configurazione<\/p>\n\n\n\n
!\/bin\/bash\n\n# gitlab-runner data directory\nDATA_DIR=\"\/etc\/gitlab-runner\"\nCONFIG_FILE=${CONFIG_FILE:-$DATA_DIR\/config.toml}\n# custom certificate authority path\nCA_CERTIFICATES_PATH=${CA_CERTIFICATES_PATH:-$DATA_DIR\/certs\/ca.crt}\nLOCAL_CA_PATH=\"\/usr\/local\/share\/ca-certificates\/ca.crt\"\n\nupdate_ca() {\n echo \"Updating CA certificates...\"\n cp \"${CA_CERTIFICATES_PATH}\" \"${LOCAL_CA_PATH}\"\n update-ca-certificates --fresh >\/dev\/null\n}\n\nif [ -f \"${CA_CERTIFICATES_PATH}\" ]; then\n # update the ca if the custom ca is different than the current\n cmp --silent \"${CA_CERTIFICATES_PATH}\" \"${LOCAL_CA_PATH}\" || update_ca\nfi\n\n# launch gitlab-runner passing all arguments\nexec gitlab-runner \"$@\"<\/code><\/pre>\n\n\n\n
Terminata la fase di build dobbiamo trasferire l\u2019immagine nei repositoyi ECR (utilizzeremo gitlab-runner e gitlab-runner-autoscaling come nome), le istruzioni per la fase di push delle immagini docker sono disponibili nella documentazione del servizio ECR.<\/p>\n\n\n\n
<\/p>\n\n\n\n
<\/p>\n\n\n\n<\/figure>\n\n\n\n
<\/p>\n\n\n\n
Una volta completata questa fase, possiamo procedere alla configurazione delle Task Definition<\/p>\n\n\n\n
Ci occuperemo solamente la configurazione dell\u2019ambiente di sviluppo, le operazioni per test e produzione sono simili.<\/p>\n\n\n\n