Ricerca nel sito web

Come creare immagini Docker in una pipeline CI GitLab


Un caso d'uso comune per le pipeline CI è la creazione delle immagini Docker che utilizzerai per distribuire la tua applicazione. GitLab CI è un'ottima scelta per questo in quanto supporta un servizio pull proxy integrato, il che significa pipeline più veloci e un registro integrato per archiviare le immagini create.

In questa guida, ti mostreremo come configurare build Docker che utilizzano entrambe le funzionalità di cui sopra. I passaggi che devi seguire variano leggermente a seconda del tipo di esecutore GitLab Runner che utilizzerai per la tua pipeline. Di seguito tratteremo gli esecutori Shell e Docker.

Costruire con Shell Executor

Se stai utilizzando l'esecutore Shell, assicurati di aver installato Docker sulla macchina che ospita il tuo runner. L'esecutore funziona eseguendo normali comandi shell utilizzando il binario docker sull'host del Runner.

Vai al repository Git per il progetto per il quale desideri creare immagini. Crea un file .gitlab-ci.yml nella radice del repository. Questo file definisce la pipeline GitLab CI che verrà eseguita quando esegui il push delle modifiche al tuo progetto.

Aggiungi il seguente contenuto al file:

class="co4">stagesclass="sy2">:
  - build
class="co4">
docker_build:class="co3">
  stageclass="sy2">: buildclass="co4">
  scriptclass="sy2">:
    - docker build -t example.com/example-image:latest .
    - docker push example.com/example-image:latest

Questa configurazione semplicistica è sufficiente per dimostrare le basi delle build di immagini basate su pipeline. GitLab clona automaticamente il tuo repository Git nell'ambiente di compilazione, quindi l'esecuzione di docker build utilizzerà il Dockerfile del tuo progetto e renderà disponibile il contenuto del repository come contesto di compilazione.

Al termine della compilazione, puoi eseguire il docker push dell'immagine nel tuo registro. Altrimenti sarebbe disponibile solo per l'installazione Docker locale che ha eseguito la build. Se utilizzi un registro privato, esegui prima docker login per fornire i dettagli di autenticazione corretti:

script:
  - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD

Definisci i valori delle due variabili credenziali andando su Impostazioni > CI/CD > Variabili nell'interfaccia utente web di GitLab. Fare clic sul pulsante blu Aggiungi variabile per creare una nuova variabile e assegnare un valore. GitLab renderà queste variabili disponibili nell'ambiente shell utilizzato per eseguire il lavoro.

Costruire con Docker Executor

L'esecutore Docker di GitLab Runner è comunemente usato per fornire un ambiente completamente pulito per ogni lavoro. Il lavoro verrà eseguito in un contenitore isolato, quindi il file binario docker sull'host Runner sarà inaccessibile.

L'esecutore Docker ti offre due possibili strategie per creare la tua immagine: utilizzare Docker-in-Docker o associare il socket Docker dell'host all'ambiente di compilazione del Runner. Quindi utilizzi l'immagine del contenitore Docker ufficiale come immagine del tuo lavoro, rendendo disponibile il comando docker nel tuo script CI.

Docker-in-Docker

L'utilizzo di Docker-in-Docker (DinD) per creare le tue immagini ti offre un ambiente completamente isolato per ogni lavoro. Il processo Docker che esegue la compilazione sarà figlio del contenitore che GitLab Runner crea sull'host per eseguire il processo CI.

Devi registrare il tuo esecutore GitLab Runner Docker con la modalità privilegiata abilitata per usare DinD. Aggiungi il flag --docker-privileged quando registri il tuo corridore:

sudo gitlab-runner register -n 
  --url https://example.com 
  --registration-token $GITLAB_REGISTRATION_TOKEN 
  --executor docker 
  --description "Docker Runner" 
  --docker-image "docker:20.10" 
  --docker-volumes "/certs/client" 
  --docker-privileged

All'interno della tua pipeline CI, aggiungi l'immagine docker:dind come servizio. Ciò rende Docker disponibile come immagine separata collegata all'immagine del lavoro. Sarai in grado di utilizzare il comando docker per creare immagini utilizzando l'istanza Docker nel contenitore docker:dind.

class="co4">servicesclass="sy2">:
  - docker:dind
class="co4">
docker_build:class="co3">
  stageclass="sy2">: buildclass="co3">
  imageclass="sy2">: docker:latestclass="co4">
  scriptclass="sy2">:
    - docker build -t example-image:latest .

L'uso di DinD ti offre build completamente isolate che non possono influire l'una sull'altra o sul tuo host. Il principale svantaggio è un comportamento di memorizzazione nella cache più complicato: ogni lavoro ottiene un nuovo ambiente in cui i livelli creati in precedenza non saranno accessibili. Puoi risolvere parzialmente questo problema provando a estrarre la versione precedente dell'immagine prima di crearla, quindi utilizzando il flag di compilazione --cache-from per rendere disponibili i livelli dell'immagine estratta come sorgente della cache:

class="co4">docker_build:class="co3">
  stageclass="sy2">: buildclass="co3">
  imageclass="sy2">: docker:latestclass="co4">
  scriptclass="sy2">:
    - docker pull $CI_REGISTRY_IMAGE:latest || true
    - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .

Supporti per presa di corrente

Il montaggio del socket Docker del tuo host nell'ambiente del tuo lavoro è un'opzione alternativa quando utilizzi l'esecutore Docker. Ciò ti offre una memorizzazione nella cache senza interruzioni ed elimina la necessità di aggiungere il servizio docker:dind alla tua configurazione CI.

Per configurarlo, registra il tuo Runner con un flag docker-volumes che associa il socket Docker dell'host a /var/run/docker.sock all'interno dei contenitori di lavoro:

sudo gitlab-runner register -n 
  --url https://example.com 
  --registration-token $GITLAB_REGISTRATION_TOKEN 
  --executor docker 
  --description "Docker Runner" 
  --docker-image "docker:20.10" 
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock

Ora i lavori che vengono eseguiti con l'immagine docker saranno in grado di utilizzare il binario docker normalmente. Le operazioni si verificheranno effettivamente sul tuo computer host, diventando fratelli del contenitore del lavoro anziché figli.

Questo è effettivamente simile all'utilizzo dell'esecutore della shell con l'installazione di Docker del tuo host. Le immagini risiedono sull'host, facilitando l'uso continuo della normale memorizzazione nella cache del livello docker build.

Sebbene questo approccio possa portare a prestazioni più elevate, meno configurazioni e nessuna delle limitazioni di DinD, presenta problemi specifici. Le più importanti tra queste sono le implicazioni sulla sicurezza: i lavori potrebbero eseguire comandi Docker arbitrari sul tuo host Runner, quindi un progetto dannoso nella tua istanza GitLab potrebbe eseguire docker run -it maligna-image:latest o docker rm -f $ (docker ps -a) con conseguenze devastanti.

GitLab avverte inoltre che l'associazione socket può causare problemi quando i lavori vengono eseguiti contemporaneamente. Ciò si verifica quando fai affidamento su contenitori creati con nomi specifici. Se due istanze di un processo vengono eseguite in parallelo, la seconda avrà esito negativo poiché il nome del contenitore esiste già sull'host.

Dovresti invece prendere in considerazione l'utilizzo di DinD se prevedi che uno di questi problemi sia problematico. Sebbene DinD non sia più generalmente consigliato, può avere più senso per le istanze GitLab rivolte al pubblico che eseguono lavori CI simultanei.

Invio di immagini al registro di GitLab

I progetti GitLab hanno l'opzione di un registro integrato che puoi utilizzare per archiviare le tue immagini. Puoi visualizzare il contenuto del registro accedendo a Packages & Registries > Container Registry nella barra laterale del tuo progetto. Se non vedi questo collegamento, abilita il registro andando su Impostazioni > Generali > Visibilità, progetto, funzionalità e autorizzazioni e attivando l'interruttore Registro contenitore.

GitLab imposta automaticamente le variabili di ambiente nei tuoi lavori CI che ti consentono di fare riferimento al registro dei contenitori del tuo progetto. Modifica la sezione script per accedere al registro e inviare la tua immagine:

class="co4">scriptclass="sy2">:
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
  - docker build -t $CI_REGISTRY_IMAGE:latest .
  - docker push $CI_REGISTRY_IMAGE:latest

GitLab genera un set sicuro di credenziali per ciascuno dei tuoi job CI. La variabile di ambiente $CI_JOB_TOKEN conterrà un token di accesso che il lavoro può utilizzare per connettersi al registro come utente gitlab-ci-token. L'URL del server del registro è disponibile come $CI_REGISTRY.

La variabile finale, $CI_REGISTRY_IMAGE, fornisce il percorso completo del registro contenitori del tuo progetto. Questa è una base adatta per i tuoi tag immagine. Puoi estendere questa variabile per creare sotto-repository, come $CI_REGISTRY_IMAGE/production/api:latest.

Altri client Docker possono estrarre le immagini dal registro autenticandosi utilizzando un token di accesso. Puoi generarli nella schermata Impostazioni > Token di accesso del tuo progetto. Aggiungi l'ambito read_registry, quindi usa le credenziali visualizzate per docker login al registro del tuo progetto.

Utilizzo del proxy di dipendenza di GitLab

Il proxy di dipendenza di GitLab fornisce un livello di memorizzazione nella cache per le immagini upstream che estrai da Docker Hub. Ti aiuta a rimanere entro i limiti di velocità di Docker Hub estraendo il contenuto delle immagini solo quando sono effettivamente cambiate. Ciò migliorerà anche le prestazioni delle tue build.

Il proxy di dipendenza viene attivato a livello di gruppo GitLab andando su Impostazioni > Pacchetti e registri > Proxy di dipendenza. Una volta abilitato, anteponi ai riferimenti immagine nel tuo file .gitlab-ci.yml $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX per farli passare attraverso il proxy:

class="co4">docker_build:class="co3">
  stageclass="sy2">: buildclass="co3">
  imageclass="sy2">: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latestclass="co4">
  services:class="co3">
    - nameclass="sy2">: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dindclass="co3">
      aliasclass="sy2">: docker

Questo è tutto quello che c'è da fare! GitLab Runner accede automaticamente al registro del proxy delle dipendenze, quindi non è necessario fornire manualmente le credenziali.

GitLab ora memorizzerà nella cache le tue immagini, offrendoti prestazioni migliorate e resilienza alle interruzioni di rete. Si noti che anche la definizione di services ha dovuto essere modificata: le variabili di ambiente non funzionano con il modulo in linea utilizzato in precedenza, quindi è necessario specificare l'immagine completa name, quindi un comando alias a cui fare riferimento nella sezione script.

Sebbene ora abbiamo impostato il proxy per le immagini utilizzate direttamente dalle nostre fasi di lavoro, è necessario altro lavoro per aggiungere il supporto per l'immagine di base nel Dockerfile da compilare. Un'istruzione regolare come questa non passerà attraverso il proxy:

FROM ubuntu:latest

Per aggiungere questo pezzo finale, usa gli argomenti di build di Docker per rendere disponibile l'URL del proxy di dipendenza quando passi attraverso il Dockerfile:

ARG GITLAB_DEPENDENCY_PROXY
FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest

Quindi modifica il comando docker build per definire il valore della variabile:

class="co4">scriptclass="sy2">:
  class="sy2">>
class="co0">    - docker build 
        --build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} 
        -t example-image:latest .

Ora anche la tua immagine di base verrà estratta attraverso il proxy delle dipendenze.

Riepilogo

Le build di immagini Docker sono facilmente integrate nelle tue pipeline GitLab CI. Dopo la configurazione iniziale di Runner, i comandi docker build e docker push nella sezione script del lavoro sono tutto ciò che serve per creare un'immagine con Dockerfile nel tuo repository. Il registro dei contenitori integrato di GitLab ti offre uno spazio di archiviazione privato per le immagini del tuo progetto.

Oltre alle build di base, vale la pena integrare il proxy di dipendenza di GitLab per accelerare le prestazioni ed evitare di raggiungere i limiti di velocità di Docker Hub. È inoltre necessario verificare la sicurezza dell'installazione valutando se il metodo selezionato consente a progetti non attendibili di eseguire comandi sull'host Runner. Sebbene presenti i suoi problemi, Docker-in-Docker è l'approccio più sicuro quando la tua istanza GitLab è pubblicamente accessibile o a cui accede un'ampia base di utenti.

Articoli correlati:


Tutti i diritti riservati. © Linux-Console.net • 2019-2025