Un processo di consegna affidabile e automatizzato riduce i tempi di inattività e gli errori umani nell’esercizio di soluzioni aziendali digitali. In questo articolo spiego in modo pratico come configurare una CI/CD-pipeline con GitLab CI, integrare lo scanning delle immagini Docker e implementare rollback automatizzati. L’obiettivo è un percorso operativo manutenibile: Build → Test → Scan → Deploy → Osservazione → rollback automatico in caso di errori critici. Das Fokus-Keyword CI/CD-Pipeline mit GitLab CI finden Sie bereits in der Einleitung, damit die Suchintention klar ist.
Perché una CI/CD-pipeline con GitLab CI?
GitLab CI è il sistema CI/CD integrato in GitLab che esegue pipeline basate su .gitlab-ci.yml. Importante per gli amministratori: GitLab CI orchestra i Runner (agenti di esecuzione), dispone di integrazioni native con la registry e può essere collegato a strumenti esterni (scanning, monitoring). Una pipeline strutturata riduce il rischio di deploy, automatizza i controlli di sicurezza (image scanning) e consente deploy reversibili (rollback).
Panoramica architetturale e prerequisiti
L’architettura tipica comprende GitLab (Repository + CI), GitLab Runners, una container-Registry (ad es. GitLab Registry o un Harbor privato), uno strumento di image scanning (ad es. Trivy, Clair o GitLabs Container Scanning), un livello di orchestrazione (spesso Kubernetes) e monitoring/alerting (ad es. Prometheus + Alertmanager). I prerequisiti sono:
- Istanza GitLab con Runner e accesso alla registry.
- Accessi autenticati alla registry (Tokens/CI_JOB_TOKEN oder Deploy-Keys).
- Ambiente target con API di deploy (kubectl + Kubeconfig oder Helm).
- Monitoring con metriche di health e SLO definite per la presa di decisione.
- Meccanismi di rollback e playbook documentati per i team di operation.
Definizione dei termini
CI/CD (Continuous Integration / Continuous Deployment) descrive i passaggi automatizzati dall’integrazione del codice fino alla consegna. L’image scanning verifica le immagini container per vulnerabilità e errori di configurazione. Il rollback indica il ripristino di una modifica di deployment quando una release è difettosa. SBOM (Software Bill of Materials) è l’elenco di tutte le componenti di un artifact e supporta le analisi di compliance e security.
Progettazione della pipeline: Stages, responsabilità, Policy
Una struttura di stage praticabile:
- prepare: checkout, preparazione degli artefatti
- build: build dell’immagine e tagging
- scan: image scanning (controlli di sicurezza / policy)
- test: unit, integration e smoke test
- deploy: canary / deploy primario
- verify: controlli di integrità e controlli di telemetria
- promote / finalize: promozione dopo un canary riuscito
È importante la separazione dei doveri: i job di build e scan non dovrebbero essere eseguiti sullo stesso Runner dei job di deploy produttivi, per minimizzare il blast radius e i privilegi.
Strategia di image tagging
Usare tag immutabili (ad es. Git-Commit-SHA o semver più build-id). I tag mutabili come latest sono problematici in produzione, perché rendono difficile la riproducibilità e il rollback.
Esempio .gitlab-ci.yml: minimale, ma affidabile per il funzionamento
L’esempio seguente mostra i componenti principali: build, scan con Trivy, push e deploy in un cluster Kubernetes. Prestare attenzione ai secret definiti e a una configurazione sicura dei Runner.
stages:
- build
- scan
- test
- deploy
- verify
variables:
IMAGE_REGISTRY: registry.example.local
IMAGE_NAME: "$IMAGE_REGISTRY/myapp"
KUBE_CONTEXT: production
build:
stage: build
image: docker:24
services:
- docker:dind
script:
- docker build -t "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA" .
- docker push "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
only:
- main
scan:
stage: scan
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL --exit-code 1 --no-progress "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
allow_failure: false
deploy_canary:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl --context="$KUBE_CONTEXT" set image deployment/myapp myapp="$IMAGE_NAME:$CI_COMMIT_SHORT_SHA" --record
- kubectl --context="$KUBE_CONTEXT" rollout status deployment/myapp --timeout=120s
when: manual
only:
- main
verify_canary:
stage: verify
image: curlimages/curl:latest
script:
- /usr/local/bin/healthcheck.sh "$KUBE_CONTEXT" "myapp" || exit 1
allow_failure: false
Perché questo funziona: Build crea un’immagine immutabile; Scan interrompe la pipeline in caso di vulnerabilità critiche; Deploy usa kubectl per aggiornare la risorsa Deployment esistente; Verify invoca un controllo di integrità basato su metriche di runtime o smoke test. Errori in Scan/Verify impediscono la promozione automatica in produzione.
Image-Scanning: strumenti, policy e insidie
Scanner comuni sono Trivy (veloce, basato su CLI), Clair (server), Grype o il Container Scanning integrato di GitLabs (SAST/DAST). I scanner forniscono elenchi CVE, livelli di gravità e versioni con fix. Selezionate la definizione di policy con attenzione:
- Gradi di gravità bloccanti (p.es. CRITICAL/HIGH) per azioni di interruzione automatica.
- Allow-listing per vulnerabilità accettate ma sottoposte a valutazione (con processo di revisione).
- Aggiornamento regolare del database dello scanner (vulnerability feeds) – database obsoleti producono falsi negativi.
Insidie tipiche:
- Autenticazione mancante verso la registry: manca CI_JOB_TOKEN o deploy-keys.
- Il caching delle immagini nei Runners maschera problemi: testate gli scans su immagini pullate, non solo sui layer locali.
- Le versioni degli scanner variano nei risultati dei CVE scan – documentate le versioni per l’audit.
Strategie di deployment e rollback automatizzati
I rollback automatizzati presuppongono che i Deployments siano reversibili e osservabili. Strategie comuni:
- Blue/Green: ambiente parallelo completo, switch del traffico in caso di successo.
- Canary: quota di traffico al nuovo rilascio, metriche osservate decidono la promozione.
- Rolling update con readiness-probes: comportamento di default in Kubernetes, ma garanzia di sicurezza limitata senza monitoring.
Meccanismi di rollback in Kubernetes
In Kubernetes la procedura di rollback più semplice è kubectl rollout undo, che riattiva il ReplicaSet precedente. Presupposto è che i ReplicaSets siano conservati (default: sì, finché non vengono esplicitamente rimossi). Per Helm-deployments si usa helm rollback con release salvate.
# Rollback auf letzte Revision (kubectl)
kubectl --context=production rollout undo deployment/myapp
# Helm rollback auf Revision 2
helm --kube-context production rollback myapp 2
Quando ciò fallisce: i rollback sono inefficaci quando i passaggi di migrazione del database non possono essere annullati in modo compatibile o quando le modifiche di configurazione non sono reversibili. Pianificate le migrazioni del database come processi separati e controllati (es. migrazioni forward- e backward-compatibili).
Implementazione di un trigger di rollback automatico
Un rollback automatico non dovrebbe essere eseguito alla cieca. Buoni trigger sono:
- I test smoke (controlli degli endpoint, flusso di autenticazione, connettività al DB) falliscono.
- Il tasso di errore supera soglie definite (es. 5xx > X%).
- La latenza o il tasso di successo scende al di sotto dei valori SLA definiti.
Tecnicamente il trigger viene realizzato tramite un job di verifica nella pipeline o tramite monitoraggio esterno con webhook. Esempio di uno script di controllo dello stato che può essere utilizzato nella fase di verify:
#!/usr/bin/env bash
# healthcheck.sh: einfache Smoke-Checks für Canary
set -euo pipefail
KUBE_CONTEXT="$1"
DEPLOYMENT="$2"
NAMESPACE="default"
# Beispiel: 3 Versuche, 2 Sekunden Pause
for i in 1 2 3; do
POD=$(kubectl --context="$KUBE_CONTEXT" -n "$NAMESPACE" get pods -l app="$DEPLOYMENT" -o jsonpath='{.items[0].metadata.name}')
kubectl --context="$KUBE_CONTEXT" -n "$NAMESPACE" exec "$POD" -- /bin/sh -c 'curl -fsS --max-time 5 http://localhost:8080/healthz' && exit 0 || sleep 2
done
exit 1
Se questo script termina con codice di uscita 1, nella pipeline dovrebbe essere eseguito un job di rollback automatico oppure attivarsi un alert che innesca un’azione automatizzata del runbook.
Estensione pratica della pipeline: job di rollback
Aggiungete la .gitlab-ci.yml con un job di rollback dedicato, che viene attivato solo in caso di fallimento della fase di verify. È importante che i permessi per il rollback siano RESTrittivi (ruolo RBAC con privilegi minimi) e che l’azione di rollback sia idempotente.
rollback_on_verify_failure:
stage: deploy
image: bitnami/kubectl:latest
when: on_failure
script:
- kubectl --context="$KUBE_CONTEXT" rollout undo deployment/myapp || true
only:
- main
Nota: Usate when: on_failure in modo mirato – in pipeline complesse questo può generare effetti collaterali inattesi se falliscono più job. Testate il comportamento in un ambiente di staging.
Pipeline CI/CD con GitLab CI: Operazioni, scalabilità e governance
Scalabilità e governance sono, in ambiente di produzione, importanti quanto la logica della pipeline. Temi operativi rilevanti:
- Scalabilità dei runner: abilitate l’autoscaling dei GitLab Runner (es. executor Kubernetes o Docker Machine) per coprire i picchi di carico senza interventi manuali.
- Runner condivisi vs. specifici: i runner condivisi sono comodi, ma aumentano il rischio di competizione per le risorse. Usate runner dedicati per i job di deploy privilegiati.
- Audit e compliance: abilitate i log di audit in GitLab e conservate i report di scansione e le SBOM per le verifiche.
Esempio: estratto di una GitLab Runner config.toml per un Kubernetes-Executor con Autoscaling (rappresentazione semplificata):
[[runners]]
name = "k8s-runner"
url = "https://gitlab.example.local/"
token = ""
executor = "kubernetes"
[runners.kubernetes]
namespace = "gitlab-runner"
image = "alpine:3.18"
idle_timeout = 1800
poll_timeout = 180
Perché questo aiuta: l’executor Kubernetes crea un Pod per job e limita gli effetti collaterali dovuti a runner host condivisi. PRESTate attenzione a resource-requests/limits, affinché i pod dei job non esauriscano le risorse dei nodi.
Segreti, RBAC e principio del minimo privilegio
I segreti non devono mai finire nell’immagine. In GitLab usi Protected Variables (mascherate, disponibili solo nei branch protetti). Per i deploy nel cluster Kubernetes si dovrebbero usare ServiceAccounts con privilegi RBAC minimi — non token con permessi di cluster-admin.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get","list","watch","update","patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-binding
namespace: production
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: gitlab-runner
roleRef:
kind: Role
name: deployer
apiGroup: rbac.authorization.k8s.io
L’esempio Role/RoleBinding sopra consente al ServiceAccount solo azioni di deploy e rollback nel namespace „production“. Questa granularità riduce il rischio derivante da token CI compromessi.
SBOM, retention degli artefatti e governance della registry
Le SBOM rendono verificabili le dipendenze e le librerie incluse. Trivy può generare SBOM; collegatele come artefatto ai job di build. Definite una strategia di retention per artefatti e immagini: una Garbage-Collection troppo aggressiva può impedire i rollback, policy troppo permissive riempiono lo storage della registry.
# Trivy SBOM erzeugen
trivy image --format cyclonedx --output sbom.cdx.json registry.example.local/myapp:$CI_COMMIT_SHORT_SHA
Raccomandazione: conservate almeno le ultime N immagini per servizio (es. N=10) e le SBOM per i periodi di conservazione legali, se la compliance lo richiede.
Observability e integrazione degli alert con la CI
Le decisioni automatizzate si basano sulle metriche. Definite regole di alert chiare in Prometheus e collegate Alertmanager a un webhook che richiami un trigger di GitLab o crei un ticket. Esempio di una semplice Prometheus AlertRule (esempio semplificato):
groups:
- name: app.rules
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{job="myapp",status=~"5.."}[2m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "Hohe Fehlerquote bei myapp"
runbook: "https://wiki.example.local/runbooks/myapp-rollback"
Alertmanager può, all’attivazione, inviare un webhook a un endpoint di trigger CI. Assicuratevi che gli endpoint di trigger siano protetti e che solo alert autorizzati possano innescare azioni.
Garbage Collection, caching e note sulle prestazioni
La performance degli scanner dipende fortemente dalla disponibilità di rete e dalla strategia di cache locale. Evitate che i runner scarichino continuamente immagini grandi, usando una registry cache locale o un proxy. Inoltre usate Docker-in-Docker solo se l’isolamento dei runner non è ottenibile in altro modo; Kaniko, BuildKit o Podman sono spesso alternative più sicure per l’executor Kubernetes.
Strategia di test e validazione prima del rollout in produzione
Verificate ogni passaggio:
- Validare l’accesso di runner e registry con immagini dummy.
- Verificare gli aggiornamenti del DB degli scanner e gli exit code (Trivy –version, trivy db update).
- Eseguire ripetutamente deploy e rollback in staging; verificare gli storici di ReplicaSet/Helm release.
- Simulare i failure dei health check per verificare i rollback automatici.
# Trivy DB-Update (wichtig vor Scans)
trivy db update
Casi d’errore tipici e risoluzione dei problemi
Errore: i job di scansione richiedono molto tempo o scadono. Cause: database dello scanner obsoleto, proxy di rete che blocca l’accesso ai feed di vulnerabilità, grande cache dei layer delle immagini. Passi di verifica: controllare la versione dello scanner, testare l’accesso di rete, verificare l’esecuzione dello scanner sull’immagine in locale.
Errore: il rollback fallisce perché i ReplicaSets sono stati eliminati. Causa: garbage-collection/cluster-cleanup. Misure: configurare le policy del cluster in modo che i ReplicaSets/release precedenti siano conservati per un periodo definito.
Errore: incompatibilità del database durante il rollback. Causa: migrazioni che non possono essere annullate. Soluzione: migrazioni in due fasi (compatibili in avanti), utilizzare feature flag, pianificare strategie separate di rollback del database.
Runbook: Azioni rapide passo-fase in caso di incidente
- Verificare l’allarme: metriche, log, cronologia dei deploy.
- Isolare: ridurre immediatamente il traffico canary o ripristinare il servizio sulle repliche precedenti.
- Eseguire il rollback (kubectl rollout undo oder helm rollback).
- Post-mortem: analizzare la causa, i risultati dello scanner, la copertura dei test, le metriche.
- Lessons Learned: adattare pipeline/test/probe, distribuire una patch.
Conclusione: maturità operativa invece della sola automazione
Pipeline CI/CD automatizzate con GitLab CI, scansione delle immagini Docker integrata e processi di rollback chiaramente definiti riducono significativamente i rischi, ma richiedono disciplina: tag immagine immutabili, policy dello scanner pulite, decisioni basate sull’osservabilità e strategie di database compatibili con il rollback. Testate regolarmente i rollback in staging, documentate i runbook e mantenete i diritti di accesso RESTrittivi. Solo così l’automazione in esercizio diventa veramente resiliente e non una nuova fonte di errori.
Ulteriori azioni: avviate con un piccolo Proof-of-Concept: Build → Trivy-Scan → Canary-Deploy → Verify → Rollback, e ampliate la pipeline gradualmente con controlli di monitoring e compliance. Pianificate esercitazioni regolari (chaos test, rollback drill) e audit delle policy di runner/registry.
Per questo tema sono inoltre importanti la scansione delle immagini Docker e il canary deployment. L’articolo colloca questi aspetti in modo chiaro e mostra cosa conta nella pratica quotidiana.