Scripter des ressources cloud avec la CLI et jq
Pilotez les CLI des fournisseurs cloud de manière idempotente et analysez les réponses JSON pour provisionner et supprimer des ressources.
Scripter des ressources cloud avec la CLI et jq est une leçon Linux Command Line & Bash Scripting Mastery gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Linux Command Line & Bash Scripting Mastery, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.
Pourquoi les scripts infonuagiques idempotents sont importants
Au niveau C2, les scripts infonuagiques ne consistent pas à cliquer sur des boutons : il s'agit d'écrire du code qui peut être exécuté en toute sécurité plusieurs fois sans créer de ressources en double ni échouer lors de la deuxième exécution.
Un script idempotent vérifie si une ressource existe déjà avant de la créer. C'est la pierre angulaire d'une automatisation fiable de l'infrastructure.
- Les CLI cloud (AWS, GCP, Azure) renvoient du JSON — l'analyse de cette sortie est essentielle.
jqest l'outil Unix standard pour découper, filtrer et transformer le JSON depuis des scripts d'interpréteur de commandes.- La combinaison de CLI, jq et de logique conditionnelle permet d'écrire des scripts de provisionnement robustes et répétables.
Tout au long de cette leçon, vous allez provisionner des compartiments S3, des instances EC2 et des rôles IAM à l'aide d'AWS CLI comme référence, avec des modèles qui se transposent directement à gcloud et az.
Installation et vérification des CLI cloud
Avant de créer des scripts, vérifiez que les bons outils sont présents. Dans l'intégration continue, épinglez toujours les versions pour éviter les divergences entre les environnements.
L'extrait ci-dessous vérifie la présence d'AWS CLI v2, de jq et du SDK GCP, et n'installe que ce qui manque — un modèle utile dans les scripts d'initialisation de machines virtuelles ou de conteneurs vierges.
#!/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."Interrogation des ressources existantes avec jq
La première étape de tout script idempotent est une lecture — demandez à l'API si la ressource existe déjà, puis choisissez la marche à suivre.
AWS CLI renvoie toujours du JSON. jq vous permet d'extraire exactement le champ dont vous avez besoin :
jq -r '.Buckets[].Name'— sortie de chaîne brute, un nom de compartiment par ligne.jq -e— se termine avec le code 1 si l'expression produitnulloufalse, ce qui le rend idéal pour les conditionsif.jq '.[] | select(.Name == env.BUCKET)'— filtrer à l'aide d'une variable de l'interpréteur de commandes viaenv.
L'extrait ci-dessous répertorie tous les compartiments S3 et vérifie si un compartiment cible existe déjà.
#!/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."
fiCréation idempotente d'un compartiment S3
Une fois la vérification d'existence en place, encapsulez la création dans une condition de garde. Une fonction infonuagique bien structurée suit ce modèle :
- Lisez l'état actuel depuis l'API.
- Comparez l'état souhaité à l'état réel.
- N'agissez que sur la différence.
Notez l'option --create-bucket-configuration — elle est requise dans toutes les régions sauf us-east-1. Inscrire la région en dur dans le script évite les échecs silencieux lorsque AWS_DEFAULT_REGION n'est pas définie.
#!/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"Analyse de JSON imbriqué : état d'une instance EC2
Les réponses EC2 sont profondément imbriquées. Le parcours de chemins avec jq et --query (JMESPath, intégré à AWS CLI) fonctionnent tous les deux — mais jq est plus puissant pour les logiques complexes.
Motifs jq essentiels pour EC2 :
.Reservations[].Instances[]— aplatir la structure à deux tableaux.select(.State.Name == "running")— filtrer par état..Tags[] | select(.Key == "Name") | .Value— extraire la valeur d'une étiquette.
L'extrait trouve une instance en cours d'exécution grâce à son étiquette Name et renvoie son ID ainsi que son adresse IP privée.
#!/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"Provisionnement idempotent d'un rôle IAM
Les ressources IAM sont globales et ne doivent pas être dupliquées. AWS renvoie un code d'erreur spécifique — EntityAlreadyExists — lorsque vous tentez de créer un rôle qui existe déjà. Intercepter ce code constitue un modèle d'idempotence plus propre qu'un appel préalable de liste lorsqu'il s'agit d'IAM à grande échelle.
Le script ci-dessous illustre les opérations suivantes :
- Capturer le code de sortie de la CLI avec
|| trueafin d'empêcherset -ed'interrompre l'exécution. - Analyser le message d'erreur JSON qu'AWS écrit sur la sortie d'erreur standard à l'aide d'une substitution de processus.
- Attacher une politique uniquement si elle ne l'est pas déjà.
#!/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 avancé : transformations, mappages et toentries
Les réponses réelles de l'infrastructure contiennent des dizaines de champs. Les transformations de jq vous permettent de remodeler la sortie pour les outils en aval, les journaux ou les fichiers de configuration.
Motifs avancés essentiels :
map(select(...))— filtrer un tableau sans perdre son enveloppe.to_entries | map(select(.value != null))— supprimer les champs nuls avant l'écriture dans une configuration.[.[] | {id: .InstanceId, ip: .PrivateIpAddress}]— projeter les données dans une nouvelle structure.@csv,@tsv,@base64— convertisseurs de formats intégrés.
L'extrait ci-dessous extrait toutes les instances en cours d'exécution et écrit un fichier d'inventaire 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"Attente des opérations asynchrones : interrogation répétée avec jq
Les opérations infonuagiques sont asynchrones. La création d'une instance EC2 renvoie immédiatement avec l'état pending. Les scripts fiables doivent interroger jusqu'à ce que l'état souhaité soit atteint avant de continuer.
Le modèle ci-dessous utilise une boucle until avec une temporisation exponentielle. AWS CLI fournit également des sous-commandes wait (par exemple aws ec2 wait instance-running), mais une interrogation écrite manuellement vous offre un contrôle personnalisé du délai d'expiration et une journalisation plus riche.
#!/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."Modèle multicloud : équivalents GCP et Azure
Le modèle idempotent de lecture puis d'action se transpose directement à d'autres CLI cloud. gcloud et az renvoient tous deux du JSON et prennent en charge le filtrage :
- GCP :
gcloud ... --format='json'— transmettez les données àjqexactement comme avec AWS. Utilisezgcloud ... --quietpour supprimer les invites dans les scripts. - Azure :
az ... --output json— même modèle.az group existsrenvoie une chaîne booléenne simple (true/false), ce qui évite d'avoir besoin de jq dans les cas simples.
L'extrait montre côte à côte la création idempotente d'un groupe de ressources dans Azure et la création d'un compartiment GCS dans GCP, en utilisant le même modèle de garde.
#!/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
fiDémantèlement : destruction sûre des ressources
Les scripts de destruction sont aussi importants que ceux de création. Un démantèlement sûr :
- répertorie les ressources avant toute suppression et affiche un récapitulatif à examiner par une personne ;
- accepte une option
--dry-runafin que les opérateurs puissent confirmer le plan sans l'exécuter ; - supprime les ressources dans l'ordre correct des dépendances (par exemple, terminer les instances avant de supprimer les groupes de sécurité).
L'extrait ci-dessous met fin à toutes les instances EC2 portant l'étiquette Env=staging, avec une condition de simulation.
#!/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."De bout en bout : script d’amorçage d’infrastructure idempotent
Nous rassemblons tous les éléments : un script d’amorçage de niveau production orchestre plusieurs ressources dans le bon ordre, est entièrement idempotent et émet des journaux structurés qu’un système d’intégration continue peut analyser.
Principales pratiques mises en œuvre :
- Journalisation structurée au moyen d’un utilitaire
log()qui ajoute les préfixes[INFO],[WARN]et[ERROR]. - Fichier d’état — écrivez les identifiants des ressources créées dans un fichier d’état JSON afin que les exécutions ultérieures et les scripts de démontage partagent les mêmes références.
- Piège à erreurs —
trapintercepte les sorties inattendues et indique le numéro de la ligne en échec.
#!/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 .)"Contrôle des connaissances : garde d’idempotence de jq
Testez votre compréhension de l’écriture de scripts infonuagiques idempotents avec jq.
Récapitulatif : automatisation des ressources infonuagiques par la CLI et jq
Cette leçon a couvert tout le cycle de vie de l’automatisation infonuagique idempotente au moyen de scripts shell, de CLI infonuagiques et de jq.
Principes fondamentaux :
- Lire avant d’écrire — interrogez toujours d’abord l’état existant ; n’agissez que sur les différences.
- jq -e pour les garde-fous — utilisez le mode fondé sur le statut de sortie pour piloter les branches
ifà partir des réponses JSON. - Sémantique des codes d’erreur — interceptez les codes d’erreur propres au fournisseur, par exemple
EntityAlreadyExists, plutôt que d’effectuer une liste préalable lorsque cette méthode est plus efficace. - Interroger l’état asynchrone — utilisez des boucles
untilavec des délais d’expiration ; ne supposez jamais qu’une ressource est prête immédiatement après sa création. - Fichiers d’état — écrivez les identifiants des ressources dans un fichier JSON partagé afin que chaque phase du script et le démontage partagent les mêmes références.
- Options d’exécution à blanc — prenez toujours en charge
--dry-runpour permettre à l’opérateur d’effectuer une vérification sûre avant les actions destructrices.
Ces modèles, associés à un en-tête strict set -euo pipefail et à un piège ERR, constituent le fondement de l’écriture de scripts d’infrastructure de niveau production au niveau C2.
Questions Fréquemment Posées
La leçon « Scripter des ressources cloud avec la CLI et jq » est-elle gratuite ?
Oui — le texte complet de « Scripter des ressources cloud avec la CLI et jq » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Linux Command Line & Bash Scripting Mastery, passe à CoddyKit PRO. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Scripter des ressources cloud avec la CLI et jq » ?
Pilotez les CLI des fournisseurs cloud de manière idempotente et analysez les réponses JSON pour provisionner et supprimer des ressources. Tu pratiques Linux Command Line & Bash Scripting Mastery avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Linux Command Line & Bash Scripting Mastery ?
Aucune expérience préalable n'est requise. Linux Command Line & Bash Scripting Mastery sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Scripter des ressources cloud avec la CLI et jq » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Linux Command Line & Bash Scripting Mastery ?
Oui. Chaque leçon Linux Command Line & Bash Scripting Mastery inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Écrire des Dockerfiles légers et des points d’entrée Shell
- Créer des modèles de configuration avec envsubst et des heredocs
- Scripter des ressources cloud avec la CLI et jq
- Sondes d’état, barrières de disponibilité et boucles d’attente