Ciao a tutti,
Qualche tempo fa, mentre studiavo AWS, mi sono reso conto di non avere una profonda comprensione di come funzionano le pipeline e i container all'interno di AWS. Pertanto, ho deciso di seguire uno dei tanti laboratori gratuiti offerti da Adrian Cantrill per mettere in pratica questi argomenti. Poiché avevo anche bisogno di esercitarmi con CloudFormation (CF), ho deciso di creare tutti i servizi in diversi modelli CF.
Questa decisione non solo mi ha aiutato ad acquisire dimestichezza con la CF, ma principalmente a comprendere e realizzare determinati ruoli e permessi di specifici servizi per poter interagire tra loro. Queste sono cose che vengono fatte automaticamente tramite la console AWS, ma farlo con CF per vedere gli errori della tua pipeline ti aiuta a capire l'importanza di questo funzionamento.
Questo è l'intero codice CF nel mio repository -> https://github.com/hmanzoni/aws-cfn-stacks/tree/master/nested/pipeline. Se stai cercando una pipeline completa che funzioni con Docker Images e che si attivi ogni volta che viene effettuato un commit, puoi rilasciare questo template nel tuo account AWS seguendo le istruzioni fornite nel repository.
Prima di addentrarci in questo topic, vorrei descrivere i servizi utilizzati per creare la pipeline CI/CD e, naturalmente, l'architettura dell'intera infrastruttura.
Ecco una breve spiegazione dell'uso di ciascun servizio:
- CodeCommit: il servizio che ospita tutto il codice creato per l'app, il nostro controllo del codice sorgente.
- Elastic Container Registry (ECR): il servizio che offre spazio di archiviazione per la nostra immagine Docker.
- CodeBuild: svolge un ruolo cruciale nell'elaborazione del codice e nella creazione di immagini, e anche la nostra automazione di compilazione si baserà su di esso.
- Cluster Elastic Container Service (ECS): questo sarà responsabile dell'hosting dei diversi servizi.
- Servizio ECS: per fare funzionare la nostra app fornendo le risorse necessarie per eseguirla e pubblicarla.
- ECS TaskDefinition: dove definiamo tutte le istruzioni affinché il nostro container funzioni perfettamente.
- CodePipeline: ci aiuterà a orchestrare CodeCommit, CodeBuild ed ECS in modo che ogni commit generato crei una nuova immagine e venga pubblicato avviando un nuovo servizio ECS.
- Elastic Load Balancer (ELB) e Target Groups (TG): Insieme, ci aiuteranno a fornire l'endpoint dell’app ai nostri utenti.
- Security Group: questo sarà collegato al nostro ELB e al nostro servizio ECS, consentendo connessioni in entrata e in uscita alla rete Internet pubblica.
- Events Rule (Event Bridge): ci aiuterà a catturare gli eventi nel nostro CodeCommit e ad attivare il servizio Pipeline.
Di seguito è riportata l'architettura di tutti questi servizi
Come puoi vedere, i nostri amici "Roles" non compaiono in questa architettura. Questo è stato uno dei miei primi problemi, poiché i servizi AWS sono isolati e non possono comunicare tra loro a meno che non lo consentiamo. È qui che entrano in gioco i ruoli. Per iniziare a risolvere i problemi con la mia pipeline, ho iniziato a chiedermi chi dovrebbe comunicare con chi e chi dovrebbe generare cambiamenti in un altro servizio direttamente e indirettamente!
Come funziona?
Quando genero un commit nel mio repository, la mia pipeline si avvia (Stage Source) [1], quindi attiva il mio CodeBuild (Stage Build) [2], che legge tutto il codice [3], genera una nuova immagine [4] e la carica in ECR [5]. A questo punto, la mia pipeline avvierà un nuovo contenitore ECS con la nuova immagine [6] (Stage Deploy).
Alcune domande:
- Come può la mia pipeline sapere quando qualcosa cambia in CodeCommit?
- In che modo la mia pipeline può attivare il CodeBuild?
- Il mio CodeBuild può leggere liberamente da CodeCommit?
- In che modo il mio CodeBuild genera una nuova immagine?
- In che modo il mio CodeBuild può aggiungere cose al mio ECR?
- La mia pipeline può lanciare un nuovo ECS?
Le risposte:
[1] Ho scoperto che il mio trigger è in realtà EventRule, quindi l'ho aggiunto al mio codice. Tuttavia, EventRule deve sapere quando qualcosa cambia nel mio codice e necessita dell'autorizzazione per eseguire la pipeline. Per risolvere il problema, ho aggiunto un ruolo con queste autorizzazioni. Ho anche scoperto che il servizio non necessitava di autorizzazioni speciali per CodeCommit, poiché AWS ha già creato alcuni eventi (AWS-Doc https://docs.aws.amazon.com/codecommit/latest/userguide/monitoring-events.html).
EventPattern (Rif nel codice):
Policy necessaria per attivare la pipeline (Rif nel codice):
Problema [1] risolto.
---
[2][6] Per impostazione predefinita, la pipeline non può apportare modifiche ad altri servizi, anche se sono definiti in Stages. Per fare ciò, ho aggiunto un ExecutionRole alla mia pipeline con autorizzazioni per determinate azioni su CodeBuild ed ECS. Autorizzazioni per CodeBuild (Rif nel codice):
Autorizzazioni per ECS (Rif nel codice):
(Questa policy ha un potenziale di miglioramento e una strategia per raggiungerlo e che potrebbe comportare la revoca di tutte le autorizzazioni esistenti e l'analisi dei registri per determinare le autorizzazioni necessarie.)
Problemi [2] e [6] risolti ✓.
---
[3][4] Per generare un'immagine, CodeBuild deve avviare i codici Docker. Come facciamo questo? Domanda d'esame ;). Per ottenere ciò, dobbiamo definire il nostro file "buildspec.yml" nella cartella principale del nostro progetto (esempio della struttura di questo file https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html - build-spec-ref-example). Nel nostro file, dovremo definire le fasi di: “pre_build”, che scaricherà il codice da CodeCommit.
Per fare ciò, utilizzeremo AWS Auth, rendendo superflue eventuali policy aggiuntive, [3] risolto ✓.
"build", che avvierà il comando Docker per compilare tutto il codice e aggiungere il tag "latest".
"post_build", in questa fase lanceremo i comandi Docker per "push", ovvero caricare quest'ultima immagine nel nostro repository.
Questo è un esempio del file buildspec.yml necessario:
Prestare particolare attenzione alle variabili d'ambiente che sono definite nel codice (es. $IMAGE_REPO_NAME), queste sono definite nelle CodeBuild EnvironmentVariables (Ref in code):
Problemi [3] e [4] risolti ✓.
---
[5] Abbiamo usato la stessa logica di prima. È necessario aggiungere un ruolo con i permessi per poter scaricare il codice e dopo averlo elaborato, caricarlo nel nostro ECR.
Policy necessaria per interagire con ECR (rif. nel codice):
Problema [5] risolto ✓.
Se hai domande, consigli o suggerimenti, lascia un commento qui sotto. Sarà mio piacere fornirti una risposta :).