Cloud-Ressourcen per CLI und jq skripten
Steuern Sie Cloud-Provider-CLIs idempotent und analysieren Sie JSON-Antworten, um Ressourcen bereitzustellen und wieder zu entfernen.
Cloud-Ressourcen per CLI und jq skripten ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Warum idempotentes Cloud-Scripting wichtig ist
Auf C2-Niveau geht es beim Cloud-Scripting nicht darum, Schaltflächen anzuklicken, sondern Code zu schreiben, der mehrfach sicher ausgeführt werden kann, ohne doppelte Ressourcen zu erzeugen oder beim zweiten Durchlauf fehlzuschlagen.
Ein idempotentes Skript prüft vor dem Erstellen, ob eine Ressource bereits vorhanden ist. Das ist der Grundpfeiler zuverlässiger Infrastrukturautomatisierung.
- Cloud-CLIs (AWS, GCP, Azure) geben JSON zurück – die Auswertung dieser Ausgabe ist unverzichtbar.
jqist das Standard-Unix-Tool zum Ausschneiden, Filtern und Transformieren von JSON in Shell-Skripten.- Durch die Kombination aus CLI, jq und bedingter Logik können Sie robuste, wiederholbar ausführbare Provisioning-Skripte schreiben.
Im Verlauf dieser Lektion stellen Sie S3-Buckets, EC2-Instanzen und IAM-Rollen mit der AWS CLI als Referenz bereit. Die Muster lassen sich direkt auf gcloud und az übertragen.
Cloud-CLIs installieren und überprüfen
Prüfen Sie vor dem Skripting, ob die richtigen Tools vorhanden sind. Fixieren Sie in CI immer die Versionen, um Abweichungen zwischen Umgebungen zu vermeiden.
Das folgende Snippet prüft auf AWS CLI v2, jq und das GCP SDK und installiert nur, was fehlt – ein nützliches Muster für Bootstrap-Skripte auf neuen VMs oder in Containern.
#!/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."Vorhandene Ressourcen mit jq abfragen
Der erste Schritt jedes idempotenten Skripts ist ein Lesen: Fragen Sie die API, ob die Ressource bereits vorhanden ist, und verzweigen Sie anschließend entsprechend.
Die AWS CLI gibt immer JSON zurück. Mit jq können Sie genau das benötigte Feld extrahieren:
jq -r '.Buckets[].Name'– rohe Zeichenkettenausgabe, ein Bucketname pro Zeile.jq -e– wird mit Code 1 beendet, wenn der Ausdrucknulloderfalseergibt, und eignet sich daher ideal fürif-Bedingungen.jq '.[] | select(.Name == env.BUCKET)'– filtert mithilfe vonenvanhand einer Shell-Variablen.
Das folgende Snippet listet alle S3-Buckets auf und prüft, ob ein Ziel-Bucket bereits vorhanden ist.
#!/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."
fiIdempotentes Erstellen von S3-Buckets
Nachdem die Existenzprüfung eingerichtet ist, kapseln Sie das Erstellen in einer Bedingung. Eine gut strukturierte Cloud-Funktion folgt diesem Muster:
- Lesen Sie den aktuellen Zustand über die API.
- Vergleichen Sie den gewünschten Zustand mit dem tatsächlichen Zustand.
- Handeln Sie nur bei einer Abweichung.
Beachten Sie das Flag --create-bucket-configuration – es ist für alle Regionen außer us-east-1 erforderlich. Wenn Sie die Region im Skript fest codieren, vermeiden Sie stille Fehler, falls AWS_DEFAULT_REGION nicht gesetzt ist.
#!/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"Verschachteltes JSON analysieren: EC2-Instanzstatus
EC2-Antworten sind tief verschachtelt. Sowohl die Pfadnavigation von jq als auch --query (JMESPath, nativ in der AWS CLI) funktionieren – für komplexe Logik ist jq jedoch leistungsfähiger.
Wichtige jq-Muster für EC2:
.Reservations[].Instances[]– glättet die Struktur aus zwei verschachtelten Arrays.select(.State.Name == "running")– filtert nach Status..Tags[] | select(.Key == "Name") | .Value– extrahiert einen Tag-Wert.
Das Snippet sucht anhand ihres Name-Tags eine laufende Instanz und gibt deren ID und private IP zurück.
#!/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"Idempotentes Bereitstellen von IAM-Rollen
IAM-Ressourcen sind global und dürfen nicht dupliziert werden. AWS gibt den spezifischen Fehlercode EntityAlreadyExists zurück, wenn Sie versuchen, eine bereits vorhandene Rolle zu erstellen. Das Abfangen dieses Codes ist bei IAM im großen Maßstab ein saubereres Idempotenzmuster als ein vorheriger Listenaufruf.
Das folgende Skript demonstriert:
- Das Erfassen des CLI-Exitcodes mit
|| true, damitset -enicht zum Abbruch führt. - Das Analysieren der JSON-Fehlermeldung, die AWS über stderr ausgibt, mithilfe einer Prozesssubstitution.
- Das Anhängen einer Policy nur dann, wenn sie noch nicht angehängt ist.
#!/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 für Fortgeschrittene: Transformationen, Maps und toentries
Antworten aus der Infrastruktur enthalten Dutzende Felder. Mit jq-Transformationen können Sie die Ausgabe für nachgelagerte Tools, Logs oder Konfigurationsdateien umformen.
Wichtige fortgeschrittene Muster:
map(select(...))– filtert ein Array, ohne den Array-Wrapper zu entfernen.to_entries | map(select(.value != null))– entfernt Nullfelder, bevor in eine Konfiguration geschrieben wird.[.[] | {id: .InstanceId, ip: .PrivateIpAddress}]– bildet eine neue Struktur.@csv,@tsv,@base64– integrierte Formatkonverter.
Das folgende Snippet extrahiert alle laufenden Instanzen und schreibt eine TSV-Inventardatei.
#!/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"Auf asynchrone Vorgänge warten: Polling mit jq
Cloud-Vorgänge laufen asynchron ab. Beim Erstellen einer EC2-Instanz wird sofort der Status pending zurückgegeben. Zuverlässige Skripte müssen so lange abfragen, bis der gewünschte Status erreicht ist, bevor sie fortfahren.
Das folgende Muster verwendet eine until-Schleife mit exponentiellem Backoff. Die AWS CLI stellt auch wait-Unterbefehle bereit (z. B. aws ec2 wait instance-running), aber selbst implementiertes Polling ermöglicht eine individuelle Timeout-Steuerung und ausführlichere Protokollierung.
#!/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."Multi-Cloud-Muster: Entsprechungen für GCP und Azure
Das idempotente Muster „Lesen, dann handeln“ lässt sich direkt auf andere Cloud-CLIs übertragen. Sowohl gcloud als auch az geben JSON zurück und unterstützen Filter:
- GCP:
gcloud ... --format='json'– leiten Sie die Ausgabe genau wie bei AWS anjqweiter. Verwenden Siegcloud ... --quiet, um Eingabeaufforderungen in Skripten zu unterdrücken. - Azure:
az ... --output json– dasselbe Muster.az group existsgibt eine einfache boolesche Zeichenkette (true/false) zurück, sodassjqin einfachen Fällen nicht benötigt wird.
Das Snippet zeigt nebeneinander das idempotente Erstellen einer Ressourcengruppe in Azure und eines GCS-Buckets in GCP, jeweils mit demselben Absicherungsmuster.
#!/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: Ressourcen sicher zerstören
Skripte zum Zerstören sind ebenso wichtig wie Skripte zum Erstellen. Ein sicherer Teardown:
- Listet Ressourcen vor dem Löschen auf und gibt eine Zusammenfassung zur menschlichen Prüfung aus.
- Akzeptiert ein
--dry-run-Flag, damit Operatoren den Plan bestätigen können, ohne Änderungen vorzunehmen. - Löscht in der richtigen Abhängigkeitsreihenfolge (z. B. Instanzen beenden, bevor Sicherheitsgruppen gelöscht werden).
Das folgende Snippet beendet alle EC2-Instanzen mit dem Tag Env=staging und verwendet dabei eine Dry-Run-Absicherung.
#!/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: Idempotentes Infrastruktur-Bootstrap-Skript
Alles zusammengeführt: Ein produktionsreifes Bootstrap-Skript orchestriert mehrere Ressourcen in der richtigen Reihenfolge, ist vollständig idempotent und gibt strukturierte Protokolle aus, die ein CI-System verarbeiten kann.
Gezeigte zentrale Vorgehensweisen:
- Strukturierte Protokollierung über einen
log()-Helper, der[INFO],[WARN]und[ERROR]voranstellt. - Zustandsdatei — Schreiben Sie die IDs erstellter Ressourcen in eine JSON-Zustandsdatei, damit nachfolgende Ausführungen und Teardown-Skripte dieselben Referenzen verwenden.
- Fehlerbehandlung —
trapfängt unerwartete Abbrüche ab und meldet die Nummer der fehlerhaften Zeile.
#!/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 .)"Wissenscheck: Idempotenzschutz mit jq
Testen Sie Ihr Verständnis idempotenter Cloud-Skripterstellung mit jq.
Rückblick: Cloud-Ressourcen per CLI und jq skripten
In dieser Lektion haben Sie den vollständigen Lebenszyklus einer idempotenten Cloud-Automatisierung mit Shell-Skripten, Cloud-CLIs und jq behandelt.
Zentrale Prinzipien:
- Vor dem Schreiben lesen — Fragen Sie immer zuerst den vorhandenen Zustand ab und wenden Sie nur die Änderungen an.
jq -efür Prüfungen — Verwenden Sie den Exit-Status-Modus, umif-Verzweigungen anhand von JSON-Antworten zu steuern.- Bedeutung von Fehlercodes — Fangen Sie anbieterspezifische Fehlercodes wie
EntityAlreadyExistsab, anstatt Ressourcen vorher aufzulisten, wenn dies effizienter ist. - Asynchronen Zustand abfragen — Verwenden Sie
until-Schleifen mit Timeouts und nehmen Sie niemals an, dass eine Ressource direkt nach ihrer Erstellung bereit ist. - Zustandsdateien — Schreiben Sie Ressourcen-IDs in eine gemeinsam genutzte JSON-Datei, damit jede Phase des Skripts und das Teardown dieselben Referenzen verwenden.
- Dry-Run-Flags — Unterstützen Sie immer
--dry-run, damit Bediener Aktionen vor potenziell destruktiven Änderungen sicher überprüfen können.
Diese Muster bilden — zusammen mit einem strikt gesetzten set -euo pipefail-Header und einem ERR-Trap — die Grundlage für produktionsreife Infrastruktur-Skripterstellung auf C2-Niveau.
Häufig gestellte Fragen
Ist die Lektion „Cloud-Ressourcen per CLI und jq skripten“ kostenlos?
Ja — der vollständige Text von „Cloud-Ressourcen per CLI und jq skripten“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Cloud-Ressourcen per CLI und jq skripten“?
Steuern Sie Cloud-Provider-CLIs idempotent und analysieren Sie JSON-Antworten, um Ressourcen bereitzustellen und wieder zu entfernen. Du übst Linux Command Line & Bash Scripting Mastery mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Linux Command Line & Bash Scripting Mastery zu starten?
Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Cloud-Ressourcen per CLI und jq skripten“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?
Ja. Jede Linux Command Line & Bash Scripting Mastery-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Schlanke Dockerfiles und Shell-Entrypoints schreiben
- Konfigurationen mit envsubst und Heredocs templatisieren
- Cloud-Ressourcen per CLI und jq skripten
- Health-Probes, Readiness-Gates und Warteschleifen