Criação de scripts para recursos de nuvem com CLI e jq
Controle CLIs de provedores de nuvem de forma idempotente e analise respostas JSON para provisionar e desmontar recursos.
Criação de scripts para recursos de nuvem com CLI e jq é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.
Por que a criação de scripts idempotentes para a nuvem importa
No nível C2, criar scripts para a nuvem não significa clicar em botões — significa escrever código que possa ser executado com segurança várias vezes sem criar recursos duplicados nem falhar na segunda execução.
Um script idempotente verifica se um recurso já existe antes de criá-lo. Esse é o fundamento da automação confiável da infraestrutura.
- As CLIs de nuvem (AWS, GCP, Azure) retornam JSON — analisar essa saída é essencial.
jqé a ferramenta Unix padrão para recortar, filtrar e transformar JSON em scripts de shell.- Combinar CLI, jq e lógica condicional permite escrever scripts de provisionamento robustos e repetíveis.
Ao longo desta lição, você provisionará depósitos S3, instâncias EC2 e funções IAM usando a AWS CLI como referência, com padrões que podem ser transferidos diretamente para gcloud e az.
Instalando e verificando CLIs de nuvem
Antes de criar scripts, confirme se as ferramentas corretas estão disponíveis. No CI, fixe sempre as versões para evitar diferenças entre os ambientes.
O trecho abaixo verifica a AWS CLI v2, o jq e o SDK do GCP, instalando apenas o que estiver faltando — um padrão útil em scripts de inicialização para máquinas virtuais ou contêineres novos.
#!/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."Consultando recursos existentes com jq
O primeiro passo de qualquer script idempotente é uma leitura — consulte a API para saber se o recurso já existe e, em seguida, escolha o caminho adequado.
A AWS CLI sempre retorna JSON. O jq permite extrair exatamente o campo de que você precisa:
jq -r '.Buckets[].Name'— saída como cadeia de caracteres bruta, com um nome de depósito por linha.jq -e— termina com o código 1 se a expressão produzirnulloufalse, sendo ideal para proteções comif.jq '.[] | select(.Name == env.BUCKET)'— filtre usando uma variável do shell por meio deenv.
O trecho abaixo lista todos os depósitos do S3 e verifica se um depósito de destino já existe.
#!/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."
fiCriação idempotente de depósitos S3
Com a verificação de existência implementada, envolva a criação em uma proteção. Uma função de nuvem bem estruturada segue este padrão:
- Leia o estado atual na API.
- Compare o estado desejado com o estado real.
- Aja somente sobre a diferença.
Observe a opção --create-bucket-configuration — ela é necessária em todas as regiões, exceto us-east-1. Fixar a região no script evita falhas silenciosas quando AWS_DEFAULT_REGION não está definida.
#!/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"Analisando JSON aninhado: estado da instância EC2
As respostas do EC2 são profundamente aninhadas. A navegação por caminhos do jq e --query (JMESPath, nativo da AWS CLI) funcionam — mas o jq é mais poderoso para lógicas complexas.
Padrões importantes de jq para EC2:
.Reservations[].Instances[]— achate a estrutura de matriz dupla.select(.State.Name == "running")— filtre pelo estado..Tags[] | select(.Key == "Name") | .Value— extraia o valor de uma etiqueta.
O trecho encontra uma instância em execução pela etiqueta Name e retorna seu ID e IP privado.
#!/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"Provisionamento idempotente de funções IAM
Os recursos do IAM são globais e não devem ser duplicados. A AWS retorna um código de erro específico — EntityAlreadyExists — quando você tenta criar uma função que já existe. Capturar esse código é um padrão de idempotência mais limpo do que fazer uma chamada de pré-verificação para listar recursos ao trabalhar com IAM em grande escala.
O script abaixo demonstra:
- Capturar o código de saída da CLI com
|| truepara impedir queset -einterrompa a execução. - Analisar o JSON da mensagem de erro que a AWS grava na saída de erro padrão usando substituição de processo.
- Anexar uma política somente se ela ainda não estiver anexada.
#!/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 avançado: transformações, mapeamentos e toentries
As respostas reais da infraestrutura contêm dezenas de campos. As transformações do jq permitem remodelar a saída para ferramentas posteriores, registros ou arquivos de configuração.
Padrões avançados essenciais:
map(select(...))— filtre uma matriz sem perder o contêiner da matriz.to_entries | map(select(.value != null))— remova campos nulos antes de gravar em uma configuração.[.[] | {id: .InstanceId, ip: .PrivateIpAddress}]— projete os dados em uma nova estrutura.@csv,@tsv,@base64— conversores de formato integrados.
O trecho abaixo extrai todas as instâncias em execução e grava um arquivo de inventário 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"Aguardando operações assíncronas: consulta repetida com jq
As operações de nuvem são assíncronas. A criação de uma instância EC2 retorna imediatamente com o estado pending. Scripts confiáveis precisam consultar repetidamente até que o estado desejado seja alcançado antes de continuar.
O padrão abaixo usa um laço until com recuo exponencial. A AWS CLI também fornece subcomandos wait (por exemplo, aws ec2 wait instance-running), mas a consulta repetida implementada manualmente oferece controle personalizado do tempo limite e registros mais detalhados.
#!/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."Padrão multinuvem: equivalentes de GCP e Azure
O padrão idempotente de ler e depois agir pode ser aplicado diretamente a outras CLIs de nuvem. Tanto gcloud quanto az retornam JSON e oferecem suporte a filtros:
- GCP:
gcloud ... --format='json'— canalize parajqexatamente como faria com a AWS. Usegcloud ... --quietpara suprimir perguntas de confirmação nos scripts. - Azure:
az ... --output json— o padrão é idêntico.az group existsretorna uma cadeia booleana simples (true/false), dispensando o jq em casos simples.
O trecho mostra, lado a lado, a criação idempotente de um grupo de recursos no Azure e de um depósito GCS no GCP usando o mesmo padrão de proteção.
#!/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
fiDestruição: remoção segura de recursos
Os scripts de destruição são tão importantes quanto os de criação. Uma remoção segura:
- Lista os recursos antes de excluir qualquer coisa e exibe um resumo para análise humana.
- Aceita uma opção
--dry-runpara que os operadores confirmem o plano sem executá-lo. - Exclui os recursos na ordem correta de dependência (por exemplo, encerra as instâncias antes de excluir os grupos de segurança).
O trecho abaixo encerra todas as instâncias EC2 marcadas com Env=staging usando uma proteção de simulação.
#!/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 ponta a ponta: script de inicialização de infraestrutura idempotente
Reunindo tudo: um script de inicialização pronto para produção orquestra vários recursos na ordem correta, é totalmente idempotente e emite registros estruturados que um sistema de integração contínua consegue analisar.
Práticas principais demonstradas:
- Registro estruturado por meio de um auxiliar
log()que acrescenta os prefixos[INFO],[WARN],[ERROR]. - Arquivo de estado — grave os IDs dos recursos criados em um arquivo JSON de estado para que as execuções subsequentes e os scripts de desmontagem compartilhem as mesmas referências.
- Captura de erros —
trapcaptura saídas inesperadas e informa o número da linha que falhou.
#!/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ção de conhecimentos: proteção de idempotência com jq
Teste seus conhecimentos sobre a criação de scripts idempotentes para a nuvem com jq.
Recapitulação: criação de scripts para recursos de nuvem via CLI e jq
Esta lição abordou todo o ciclo de vida da automação idempotente de recursos de nuvem usando scripts de shell, interfaces de linha de comando da nuvem e jq.
Princípios fundamentais:
- Leia antes de escrever — sempre consulte primeiro o estado existente; aja apenas sobre as diferenças.
- jq -e para verificações — use o modo de status de saída para controlar ramificações de
ifa partir de respostas JSON. - Semântica dos códigos de erro — capture códigos de erro específicos do provedor, como
EntityAlreadyExists, em vez de fazer uma listagem prévia quando isso for mais eficiente. - Consulte periodicamente o estado assíncrono — use laços
untilcom limites de tempo; nunca presuma que um recurso está pronto imediatamente após a criação. - Arquivos de estado — grave os IDs dos recursos em um arquivo JSON compartilhado para que cada fase do script e a desmontagem compartilhem as mesmas referências.
- Sinalizadores de simulação — sempre ofereça suporte a
--dry-runpara uma revisão segura pelo operador antes de ações destrutivas.
Esses padrões — combinados com um cabeçalho rigoroso set -euo pipefail e uma captura de ERR — formam a base da criação de scripts de infraestrutura prontos para produção em nível C2.
Perguntas Frequentes
A aula “Criação de scripts para recursos de nuvem com CLI e jq” é grátis?
Sim — o texto completo de “Criação de scripts para recursos de nuvem com CLI e jq” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.
O que vou aprender em “Criação de scripts para recursos de nuvem com CLI e jq”?
Controle CLIs de provedores de nuvem de forma idempotente e analise respostas JSON para provisionar e desmontar recursos. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?
Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Criação de scripts para recursos de nuvem com CLI e jq”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?
Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Dockerfiles enxutos e pontos de entrada do Shell
- Criação de modelos de configurações com envsubst e heredocs
- Criação de scripts para recursos de nuvem com CLI e jq
- Sondagens de integridade, barreiras de prontidão e loops de espera