Gestire risorse cloud tramite CLI e jq
Gestisca in modo idempotente le CLI dei provider cloud e analizzi le risposte JSON per creare e rimuovere risorse.
Gestire risorse cloud tramite CLI e jq è una lezione DevOps Bootcamp gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp include 4 lezioni in totale.
Perché gli script cloud idempotenti sono importanti
A livello C2, lo scripting cloud non consiste nel fare clic sui pulsanti, ma nello scrivere codice che possa essere eseguito in sicurezza più volte senza creare risorse duplicate o fallire alla seconda esecuzione.
Uno script idempotente verifica se una risorsa esiste già prima di crearla. Questo è il fondamento dell'automazione affidabile dell'infrastruttura.
- Le CLI cloud (AWS, GCP, Azure) restituiscono JSON: analizzare questo output è essenziale.
jqè lo strumento Unix standard per estrarre, filtrare e trasformare JSON dagli script shell.- Combinando CLI, jq e logica condizionale è possibile scrivere script di provisioning robusti e ripetibili.
Nel corso di questa lezione eseguirà il provisioning di bucket S3, istanze EC2 e ruoli IAM usando AWS CLI come riferimento, con pattern direttamente applicabili a gcloud e az.
Installare e verificare le CLI cloud
Prima di scrivere gli script, verifichi che siano presenti gli strumenti corretti. In CI, blocchi sempre le versioni per evitare differenze tra gli ambienti.
Il frammento seguente verifica la presenza di AWS CLI v2, jq e GCP SDK, installando solo ciò che manca: un pattern utile negli script di bootstrap per nuove VM o nuovi container.
#!/usr/bin/env bash
set -euo pipefail
check_or_install() {
local cmd="$1"
local install_cmd="$2"
if ! command -v "$cmd" &>/dev/null; then
echo "[INFO] $cmd not found — installing..."
eval "$install_cmd"
else
echo "[OK] $cmd $("$cmd" --version 2>&1 | head -1)"
fi
}
# AWS CLI v2
check_or_install aws \
'curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o /tmp/awscliv2.zip && unzip -q /tmp/awscliv2.zip -d /tmp && sudo /tmp/aws/install'
# jq
check_or_install jq \
'sudo apt-get install -y jq 2>/dev/null || sudo yum install -y jq'
# gcloud (optional)
check_or_install gcloud \
'echo "Install gcloud SDK manually from https://cloud.google.com/sdk"'
echo "All prerequisites satisfied."Interrogare le risorse esistenti con jq
Il primo passo di qualsiasi script idempotente è una lettura: chiedere all'API se la risorsa esiste già e quindi scegliere il ramo da seguire.
AWS CLI restituisce sempre JSON. jq consente di estrarre esattamente il campo necessario:
jq -r '.Buckets[].Name'— restituisce stringhe senza elaborazione, con un nome di bucket per riga.jq -e— termina con il codice 1 se l'espressione producenullofalse, perciò è ideale nelle condizioniif.jq '.[] | select(.Name == env.BUCKET)'— filtra usando una variabile della shell tramiteenv.
Il frammento seguente elenca tutti i bucket S3 e verifica se esiste già un bucket di destinazione.
#!/usr/bin/env bash
set -euo pipefail
BUCKET="my-devops-artifacts-$(date +%Y%m)"
echo "Fetching existing S3 buckets..."
EXISTING=$(aws s3api list-buckets --output json)
# Extract names as newline-separated list
echo "$EXISTING" | jq -r '.Buckets[].Name'
# Check if target bucket exists
if echo "$EXISTING" | jq -e --arg b "$BUCKET" '.Buckets[] | select(.Name == $b)' > /dev/null 2>&1; then
echo "[EXISTS] Bucket $BUCKET already present — skipping creation."
else
echo "[MISSING] Bucket $BUCKET not found — will create."
fiCreazione idempotente di bucket S3
Una volta predisposto il controllo di esistenza, inserisca la creazione in una condizione. Una funzione cloud ben strutturata segue questo pattern:
- Leggere lo stato corrente dall'API.
- Confrontare lo stato desiderato con quello effettivo.
- Agire solo sulla differenza.
Noti il flag --create-bucket-configuration: è obbligatorio in tutte le regioni tranne us-east-1. Specificare la regione direttamente nello script evita errori silenziosi quando AWS_DEFAULT_REGION non è impostata.
#!/usr/bin/env bash
set -euo pipefail
REGION="eu-west-1"
BUCKET="my-devops-artifacts-$(date +%Y%m)"
ensure_bucket() {
local bucket="$1"
local region="$2"
local existing
existing=$(aws s3api list-buckets --query 'Buckets[].Name' --output json)
if echo "$existing" | jq -e --arg b "$bucket" 'index($b) != null' > /dev/null 2>&1; then
echo "[SKIP] Bucket $bucket already exists."
return 0
fi
echo "[CREATE] Creating bucket $bucket in $region..."
aws s3api create-bucket \
--bucket "$bucket" \
--region "$region" \
--create-bucket-configuration LocationConstraint="$region"
# Enable versioning immediately after creation
aws s3api put-bucket-versioning \
--bucket "$bucket" \
--versioning-configuration Status=Enabled
echo "[DONE] Bucket $bucket created with versioning enabled."
}
ensure_bucket "$BUCKET" "$REGION"Analizzare JSON annidato: stato di un'istanza EC2
Le risposte di EC2 sono profondamente annidate. Funzionano sia il percorso attraverso i dati con jq sia --query (JMESPath, integrato nativamente in AWS CLI), ma jq è più potente per la logica complessa.
Pattern fondamentali di jq per EC2:
.Reservations[].Instances[]— appiattisce la struttura con due array annidati.select(.State.Name == "running")— filtra in base allo stato..Tags[] | select(.Key == "Name") | .Value— estrae il valore di un tag.
Il frammento individua un'istanza in esecuzione tramite il tag Name e restituisce il suo ID e l'indirizzo IP privato.
#!/usr/bin/env bash
set -euo pipefail
INSTANCE_NAME="web-server-prod"
RESULT=$(aws ec2 describe-instances \
--filters \
"Name=tag:Name,Values=${INSTANCE_NAME}" \
"Name=instance-state-name,Values=running" \
--output json)
# Extract instance ID and private IP using jq
INSTANCE_ID=$(echo "$RESULT" | jq -r \
'.Reservations[].Instances[] | .InstanceId')
PRIVATE_IP=$(echo "$RESULT" | jq -r \
'.Reservations[].Instances[] | .PrivateIpAddress')
if [[ -z "$INSTANCE_ID" ]]; then
echo "[WARN] No running instance named '$INSTANCE_NAME' found."
exit 1
fi
echo "Instance ID : $INSTANCE_ID"
echo "Private IP : $PRIVATE_IP"Provisioning idempotente di un ruolo IAM
Le risorse IAM sono globali e non devono essere duplicate. AWS restituisce uno specifico codice di errore, EntityAlreadyExists, quando si tenta di creare un ruolo che esiste già. Intercettare quel codice è un pattern di idempotenza più efficiente di una chiamata preliminare per elencare le risorse quando si lavora con IAM su larga scala.
Lo script seguente mostra come:
- Acquisire il codice di uscita della CLI con
|| trueper impedire cheset -einterrompa l'esecuzione. - Analizzare il JSON del messaggio di errore che AWS scrive su stderr usando la sostituzione di processo.
- Collegare una policy solo se non è già collegata.
#!/usr/bin/env bash
set -euo pipefail
ROLE_NAME="DevOpsDeployRole"
POLICY_ARN="arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
TRUST_POLICY='{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}'
# Attempt creation; ignore EntityAlreadyExists
CREATE_OUTPUT=$(aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document "$TRUST_POLICY" \
--output json 2>&1) || {
if echo "$CREATE_OUTPUT" | grep -q 'EntityAlreadyExists'; then
echo "[SKIP] Role $ROLE_NAME already exists."
else
echo "[ERROR] Unexpected error: $CREATE_OUTPUT" >&2
exit 1
fi
}
# Attach policy (attach-role-policy is idempotent by default)
aws iam attach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "$POLICY_ARN"
echo "[OK] Role $ROLE_NAME ready with policy $POLICY_ARN."jq avanzato: trasformazioni, mappe e toentries
Le risposte reali dell'infrastruttura contengono decine di campi. Le trasformazioni di jq consentono di rimodellare l'output per gli strumenti a valle, i log o i file di configurazione.
Pattern avanzati essenziali:
map(select(...))— filtra un array senza rimuovere il contenitore dell'array.to_entries | map(select(.value != null))— rimuove i campi null prima di scrivere una configurazione.[.[] | {id: .InstanceId, ip: .PrivateIpAddress}]— proietta i dati in una nuova struttura.@csv,@tsv,@base64— convertitori di formato integrati.
Il frammento seguente estrae tutte le istanze in esecuzione e scrive un file di inventario TSV.
#!/usr/bin/env bash
set -euo pipefail
OUTPUT_FILE="/tmp/ec2_inventory.tsv"
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--output json \
| jq -r '
["InstanceId", "Name", "PrivateIp", "Type", "AZ"],
[
.Reservations[].Instances[] | [
.InstanceId,
(.Tags // [] | map(select(.Key == "Name")) | .[0].Value // "(none)"),
(.PrivateIpAddress // "N/A"),
.InstanceType,
.Placement.AvailabilityZone
]
][]
| @tsv' > "$OUTPUT_FILE"
echo "Inventory written to $OUTPUT_FILE:"
column -t "$OUTPUT_FILE"Attendere le operazioni asincrone: polling con jq
Le operazioni cloud sono asincrone. La creazione di un'istanza EC2 restituisce immediatamente lo stato pending. Gli script affidabili devono eseguire il polling fino al raggiungimento dello stato desiderato prima di continuare.
Il pattern seguente utilizza un ciclo until con back-off esponenziale. AWS CLI offre anche i sottocomandi wait (ad esempio aws ec2 wait instance-running), ma un polling scritto manualmente consente di controllare in modo personalizzato il timeout e di ottenere log più dettagliati.
#!/usr/bin/env bash
set -euo pipefail
INSTANCE_ID="i-0abcdef1234567890"
MAX_WAIT=300 # seconds
INTERVAL=10
ELAPSED=0
echo "Waiting for instance $INSTANCE_ID to reach 'running' state..."
while true; do
STATE=$(aws ec2 describe-instances \
--instance-ids "$INSTANCE_ID" \
--output json \
| jq -r '.Reservations[0].Instances[0].State.Name')
echo " [$(date +%T)] state = $STATE"
[[ "$STATE" == "running" ]] && break
if [[ "$STATE" == "terminated" || "$STATE" == "shutting-down" ]]; then
echo "[FATAL] Instance entered terminal state: $STATE" >&2
exit 1
fi
if (( ELAPSED >= MAX_WAIT )); then
echo "[TIMEOUT] Instance did not reach 'running' after ${MAX_WAIT}s." >&2
exit 1
fi
sleep "$INTERVAL"
(( ELAPSED += INTERVAL ))
done
echo "[OK] Instance $INSTANCE_ID is running."Pattern multi-cloud: equivalenti per GCP e Azure
Il pattern idempotente di lettura e azione si applica direttamente alle altre CLI cloud. Sia gcloud sia az restituiscono JSON e supportano il filtraggio:
- GCP:
gcloud ... --format='json'— lo si può passare ajqesattamente come con AWS. Utilizzigcloud ... --quietper sopprimere le richieste di conferma negli script. - Azure:
az ... --output json— il pattern è identico.az group existsrestituisce una semplice stringa booleana (true/false), evitando di dover usare jq nei casi semplici.
Il frammento mostra, affiancate, la creazione idempotente di un gruppo di risorse in Azure e di un bucket GCS in GCP, usando lo stesso pattern di controllo.
#!/usr/bin/env bash
set -euo pipefail
# --- Azure: idempotent resource group ---
RG="devops-rg"
LOCATION="westeurope"
if [[ $(az group exists --name "$RG") == "true" ]]; then
echo "[SKIP] Azure resource group $RG already exists."
else
echo "[CREATE] Creating Azure resource group $RG..."
az group create --name "$RG" --location "$LOCATION" --output json \
| jq '{name: .name, location: .location, provisioningState: .properties.provisioningState}'
fi
# --- GCP: idempotent GCS bucket ---
GCS_BUCKET="gs://devops-artifacts-prod"
PROJECT="my-gcp-project"
if gcloud storage buckets describe "$GCS_BUCKET" \
--project="$PROJECT" --format='value(name)' &>/dev/null; then
echo "[SKIP] GCS bucket $GCS_BUCKET already exists."
else
echo "[CREATE] Creating GCS bucket $GCS_BUCKET..."
gcloud storage buckets create "$GCS_BUCKET" \
--project="$PROJECT" \
--location=EU \
--uniform-bucket-level-access
fiTeardown: eliminazione sicura delle risorse
Gli script di eliminazione sono importanti quanto quelli di creazione. Un teardown sicuro:
- Elenca le risorse prima di eliminare qualsiasi elemento e stampa un riepilogo per la revisione umana.
- Accetta un flag
--dry-run, così gli operatori possono confermare il piano senza eseguire alcuna azione. - Elimina le risorse nell'ordine corretto delle dipendenze (ad esempio, termina le istanze prima di eliminare i gruppi di sicurezza).
Il frammento seguente termina tutte le istanze EC2 con il tag Env=staging usando un controllo dry-run.
#!/usr/bin/env bash
set -euo pipefail
DRY_RUN="${1:-}"
echo "Finding staging EC2 instances..."
INSTANCE_IDS=$(aws ec2 describe-instances \
--filters \
"Name=tag:Env,Values=staging" \
"Name=instance-state-name,Values=running,stopped" \
--output json \
| jq -r '[.Reservations[].Instances[].InstanceId] | @sh')
if [[ -z "$INSTANCE_IDS" ]]; then
echo "[INFO] No staging instances found. Nothing to do."
exit 0
fi
echo "Instances to terminate: $INSTANCE_IDS"
if [[ "$DRY_RUN" == "--dry-run" ]]; then
echo "[DRY-RUN] No changes made."
exit 0
fi
read -rp "Terminate these instances? [yes/N]: " CONFIRM
[[ "$CONFIRM" != "yes" ]] && { echo "Aborted."; exit 0; }
# shellcheck disable=SC2086
aws ec2 terminate-instances --instance-ids $INSTANCE_IDS --output json \
| jq '.TerminatingInstances[] | {id: .InstanceId, state: .CurrentState.Name}'
echo "[DONE] Termination initiated."End-to-end: script idempotente di bootstrap dell'infrastruttura
Mettere tutto insieme: uno script di bootstrap pronto per la produzione orchestra più risorse nell'ordine corretto, è completamente idempotente e genera log strutturati che un sistema CI può analizzare.
Procedure chiave illustrate:
- Logging strutturato tramite un helper
log()che antepone[INFO],[WARN],[ERROR]. - File di stato — scrivere gli ID delle risorse create in un file di stato JSON, in modo che le esecuzioni successive e gli script di teardown condividano gli stessi riferimenti.
- Trap degli errori —
trapintercetta le uscite impreviste e segnala il numero della riga che ha causato l'errore.
#!/usr/bin/env bash
set -euo pipefail
STATE_FILE="/tmp/infra_state.json"
REGION="eu-west-1"
BUCKET="devops-bootstrap-$(date +%Y%m)"
ROLE="BootstrapRole"
log() { echo "[$(date -u +%T)] [$1] ${*:2}"; }
trap 'log ERROR "Script failed at line $LINENO"' ERR
# Initialize state
[[ -f "$STATE_FILE" ]] || echo '{}' > "$STATE_FILE"
# --- Step 1: S3 bucket ---
EXISTING_BUCKETS=$(aws s3api list-buckets --query 'Buckets[].Name' --output json)
if echo "$EXISTING_BUCKETS" | jq -e --arg b "$BUCKET" 'index($b) != null' > /dev/null; then
log INFO "Bucket $BUCKET exists — skipping."
else
aws s3api create-bucket --bucket "$BUCKET" --region "$REGION" \
--create-bucket-configuration LocationConstraint="$REGION" > /dev/null
log INFO "Bucket $BUCKET created."
fi
# Update state file
jq --arg b "$BUCKET" '.bucket = $b' "$STATE_FILE" > /tmp/_state_tmp && mv /tmp/_state_tmp "$STATE_FILE"
# --- Step 2: IAM role ---
if aws iam get-role --role-name "$ROLE" &>/dev/null; then
log INFO "Role $ROLE exists — skipping."
else
aws iam create-role --role-name "$ROLE" \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \
--output json | jq '{RoleName: .Role.RoleName, Arn: .Role.Arn}'
log INFO "Role $ROLE created."
fi
jq --arg r "$ROLE" '.role = $r' "$STATE_FILE" > /tmp/_state_tmp && mv /tmp/_state_tmp "$STATE_FILE"
log INFO "Bootstrap complete. State: $(cat "$STATE_FILE" | jq -c .)"Verifica delle conoscenze: controllo di idempotenza con jq
Verifichi la propria comprensione dello scripting cloud idempotente con jq.
Riepilogo: scripting delle risorse cloud tramite CLI e jq
Questa lezione ha trattato l'intero ciclo di vita dell'automazione cloud idempotente tramite script shell, CLI cloud e jq.
Principi fondamentali:
- Leggere prima di scrivere — interrogare sempre prima lo stato esistente; agire soltanto sulle differenze.
- jq -e per i controlli — usare la modalità basata sul codice di uscita per pilotare i rami
ifa partire dalle risposte JSON. - Semantica dei codici di errore — intercettare i codici di errore specifici del provider, ad esempio
EntityAlreadyExists, invece di elencare prima le risorse quando è più efficiente. - Eseguire il polling dello stato asincrono — usare cicli
untilcon timeout; non dare mai per scontato che una risorsa sia pronta subito dopo la creazione. - File di stato — scrivere gli ID delle risorse in un file JSON condiviso, così che ogni fase dello script e il teardown condividano gli stessi riferimenti.
- Flag dry-run — supportare sempre
--dry-runper consentire all'operatore di esaminare in sicurezza le azioni distruttive prima di eseguirle.
Questi pattern — combinati con un'intestazione rigorosa set -euo pipefail e un trap ERR — costituiscono la base per lo scripting dell'infrastruttura di livello production-grade al livello C2.
Domande Frequenti
La lezione «Gestire risorse cloud tramite CLI e jq» è gratuita?
Sì — il testo completo di «Gestire risorse cloud tramite CLI e jq» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp include 4 lezioni in totale.
Cosa imparerò in «Gestire risorse cloud tramite CLI e jq»?
Gestisca in modo idempotente le CLI dei provider cloud e analizzi le risposte JSON per creare e rimuovere risorse. Eserciti DevOps Bootcamp con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare DevOps Bootcamp?
Non è richiesta alcuna esperienza precedente. DevOps Bootcamp su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Gestire risorse cloud tramite CLI e jq»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione DevOps Bootcamp?
Sì. Ogni lezione DevOps Bootcamp include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Scrivere Dockerfile essenziali ed entrypoint shell
- Creare template di configurazione con envsubst e heredoc
- Gestire risorse cloud tramite CLI e jq
- Probe di salute, controlli di readiness e cicli di attesa