Un deploy può sembrare riuscito e restare comunque fragile. Il caso tipico è una CI minima che carica l’artifact, riavvia il servizio e non verifica altro.
Qui lavoriamo su uno scenario concreto: build in GitLab CI, artifact versionato, rilascio su una VPS con systemd e rollback rapido. L’obiettivo è una mini checklist post-deploy. Pochi comandi, ma scelti bene.
Il punto non è “fare DevOps”. Il punto è capire, in due minuti, se il deploy ha introdotto drift, se l’artifact è quello giusto e se il rollback è davvero disponibile.
Prerequisiti
- Un runner GitLab CI o una pipeline equivalente.
- Un artifact firmato o almeno identificato con hash e commit SHA.
- Accesso SSH alla VPS.
- Un servizio gestito da systemd, con unit file dedicata.
- Un endpoint HTTP o una health route per il controllo finale.
Note: i comandi sotto assumono una release installata in /opt/app/releases/<versione> e un symlink stabile /opt/app/current.
Warning: se il deploy modifica anche configurazione o env, la verifica dell’artifact non basta. Serve un controllo di drift sulla configurazione attiva.
Step 1 — Blocca il riferimento dell’artifact prima di toccare il servizio
Prima di riavviare, devi sapere esattamente quale build stai installando. Il commit SHA e l’hash del pacchetto evitano ambiguità durante il rollback.
In GitLab CI, salva almeno nome file, SHA del commit e checksum. Se l’artifact è un tarball, meglio ancora se lo firmi o ne pubblichi il checksum nel job.
# nel job di build
sha256sum dist/app.tar.gz | tee dist/app.tar.gz.sha256
printf '%s\n' "$CI_COMMIT_SHA" > dist/commit.txt
# Output:
dist/app.tar.gz.sha256 e dist/commit.txt presenti tra gli artifact della pipeline.
Su server, verifica subito il pacchetto prima dell’estrazione.
cd /opt/app/incoming
sha256sum -c app.tar.gz.sha256
cat commit.txt
# Output:
app.tar.gz: OK e commit mostrato a video.
Perché conta: se il file è corrotto o sostituito, il problema non si scoprirà dopo il restart. Lo scopri qui, con il servizio ancora stabile.
Checklist rapida
- Checksum corrispondente.
- Commit coerente con la pipeline approvata.
- Nome release univoco, mai latest.
Step 2 — Verifica che il filesystem contenga solo la release attesa
Molti rollback falliscono perché la release vecchia è stata cancellata troppo presto. Mantieni almeno due release e un symlink stabile.
Controlla la struttura prima del switch. Questo riduce gli errori dovuti a rilasci parziali.
ls -la /opt/app/releases
readlink -f /opt/app/current
find /opt/app/releases -maxdepth 1 -type d -printf '%f\n' | sort
# Output:
due o più directory di release e /opt/app/current che punta alla release attiva.
Se la release nuova esiste ma manca un file atteso, non andare avanti. Il problema spesso nasce da artifact incompleto o exclude errato nella pipeline.
Note: un deploy con artifact parziali è peggiore di un deploy fermo. Almeno il servizio precedente resta recuperabile.
Step 3 — Confronta unit systemd, env e config con la release precedente
Qui cerchi drift. Il servizio può partire, ma con variabili diverse, limiti diversi o file di configurazione vecchi.
Prima controlla l’unit attiva e i drop-in. Poi confronta i file di configurazione rispetto alla release precedente.
systemctl cat app.service
systemctl show app.service -p FragmentPath -p DropInPaths -p Environment
cmp -s /opt/app/releases/previous/.env /opt/app/releases/current/.env; echo $?
# Output:
unit e drop-in leggibili, variabili attese presenti, codice di cmp pari a 0 se i file coincidono.
Se il file env deve cambiare tra release, il confronto non deve essere identico. In quel caso verifica solo le chiavi consentite.
grep -E '^(APP_ENV|APP_VERSION|API_BASE_URL)=' /opt/app/releases/current/.env
# Output:
sole variabili previste e valori coerenti con il deploy.
Warning: il drift più subdolo è quello “silenzioso”. Il servizio è online, ma legge una configurazione diversa da quella del repository.
Step 4 — Riavvia il servizio e controlla subito log e stato
Il restart non è la verifica. È solo il punto in cui la verifica diventa possibile.
Riavvia solo dopo i controlli precedenti. Subito dopo, leggi stato e ultimi log. Non aspettare il primo alert.
systemctl restart app.service
systemctl is-active app.service
systemctl status app.service --no-pager -l
journalctl -u app.service -n 30 --no-pager
# Output:
active come stato e nessun errore grave nei log.
Se il servizio entra in degraded, il problema può essere nel listener, nelle dipendenze o nella migrazione non completata. Fermati qui.
Verifica anche che il processo usi la release corretta.
pid=$(systemctl show -p MainPID --value app.service)
readlink -f /proc/$pid/exe 2>/dev/null || true
tr '\0' '\n' < /proc/$pid/environ | grep -E '^APP_VERSION='
# Output:
binary o launcher atteso e variabile versione coerente con la release appena deployata.
Step 5 — Esegui la health check applicativa, non solo il ping
Un TCP open non prova che l’app funzioni. Serve una route che tocchi almeno il path critico: DB, cache o backend esterno, se il flusso lo richiede.
Usa curl con timeout brevi. Se la risposta è lenta, il deploy è solo apparentemente riuscito.
curl -fsS --max-time 3 https://app.example.com/health
curl -fsS --max-time 3 https://app.example.com/ready
# Output:
HTTP 200 e payload atteso, ad esempio {"status":"ok"} o ready.
Se la route readiness fallisce ma la health risponde, hai trovato un problema di dipendenze o warm-up. Non forzare il traffico.
Per applicazioni con endpoint più ricco, controlla anche un campo versione.
curl -fsS https://app.example.com/health | jq -r '.version,.commit'
# Output:
versione e commit uguali a quelli della pipeline.
Step 6 — Verifica che l’artifact servito coincida con quello pubblicato
Questo è il controllo che chiude il cerchio. La release installata deve coincidere con quella annunciata dalla CI.
Se il deploy è file-based, confronta il contenuto del manifest o del file build-info. Se è un binario, usa una versione incorporata.
cat /opt/app/current/build-info.json
sha256sum /opt/app/current/app.tar.gz 2>/dev/null || true
# Output:
commit, timestamp e versione allineati al job di pipeline.
Se usi una pagina di diagnostica interna, è ancora meglio. Ti evita SSH su ambienti con accesso limitato.
Note: l’obiettivo non è collezionare dati. L’obiettivo è rispondere a una domanda semplice: “sto eseguendo proprio questo artifact?”
Step 7 — Confronta la configurazione attiva con quella desiderata per scoprire drift
Il drift non riguarda solo gli env. Può colpire unit file, sysctl, timer, limiti ulimit e file in /etc.
Una verifica minima utile confronta checksum o diff tra ciò che la pipeline ha distribuito e ciò che il server ha attivo.
diff -u /opt/app/releases/previous/config/app.yaml /opt/app/releases/current/config/app.yaml || true
systemd-delta --type=extended
# Output:
nessuna differenza inattesa nei file applicativi e nessun delta sorpresa sull’unit.
Se trovi delta non previsti, il server è già uscito dalla configurazione standard. Qui nasce il rischio di deploy non ripetibili.
Per infrastrutture più rigide, controlla anche i pacchetti installati.
dpkg -l | grep -E 'app-|libfoo|libbar'
# oppure
rpm -qa | grep -E 'app-|libfoo|libbar'
# Output:
solo versioni previste dal baseline dell’ambiente.
Verifica finale
La checklist finale deve stare in meno di tre minuti. Se richiede più tempo, qualcosa è troppo fragile o troppo manuale.
- Checksum dell’artifact valido.
- Release e commit allineati alla pipeline.
- systemd active senza errori recenti.
- Health e readiness rispondono con 200.
- Config attiva uguale o compatibile con quella desiderata.
- Rollback disponibile con la release precedente intatta.
Se vuoi un controllo ancora più concreto, salva l’esito in un file di audit.
printf '%s %s %s\n' "$(date -Is)" "$(readlink -f /opt/app/current)" "$(systemctl is-active app.service)" \
>> /var/log/app-postdeploy.log
# Output:
una riga audit leggibile, utile per incident review e change log.
Troubleshooting
1) app.service: Failed with result 'exit-code'
Causa: la nuova release parte con env o file mancanti, spesso dopo un artifact incompleto.
Fix: controlla i log e torna alla release precedente.
journalctl -u app.service -n 50 --no-pager
ln -sfn /opt/app/releases/previous /opt/app/current
systemctl restart app.service
# Output:
servizio riportato online sulla release precedente.
2) curl: (28) Connection timed out after 3001 milliseconds
Causa: il processo è avviato, ma la readiness resta bloccata su DB, cache o bootstrap lento.
Fix: verifica le dipendenze e aumenta solo se il ritardo è atteso.
systemctl status app.service --no-pager -l
ss -ltnp | grep ':443\|:80'
curl -fsS --max-time 10 https://app.example.com/ready
# Output:
diagnosi chiara sul collo di bottiglia e readiness eventualmente recuperata.
3) sha256sum: WARNING: 1 computed checksum did NOT match
Causa: artifact corrotto, troncato o sostituito durante il trasferimento.
Fix: elimina il pacchetto e rilancialo dalla pipeline o dal registro artifact.
rm -f /opt/app/incoming/app.tar.gz
# rilancia download o deploy job
sha256sum -c app.tar.gz.sha256
# Output:
checksum valido solo dopo un nuovo trasferimento corretto.
Conclusione
Un deploy affidabile non finisce con il restart. Finisce quando artifact, servizio, endpoint e configurazione raccontano la stessa storia.
La mini checklist qui sopra serve proprio a questo: ridurre il tempo tra “sembra tutto ok” e “sappiamo davvero che è ok”. Il prossimo passo concreto è automatizzare questi controlli in un job post-deploy separato, con exit code non ambiguo e rollback già pronto.
Se la tua pipeline non ha ancora un audit di rilascio, aggiungilo adesso. Bastano pochi comandi, ma devono essere sempre gli stessi.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.