0Pricing
DevOps Bootcamp · درس

برمجة موارد السحابة باستخدام CLI وjq

شغّل واجهات CLI لمزوّدي الخدمات السحابية بطريقة قابلة للتكرار وحلّل استجابات JSON لإنشاء الموارد وإزالتها

برمجة موارد السحابة باستخدام CLI وjq درس مجاني في DevOps Bootcamp على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DevOps Bootcamp، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.

أهمية كتابة نصوص سحابية قابلة للتنفيذ بأمان عدة مرات

في المستوى C2، لا تتعلق كتابة النصوص السحابية بالنقر على الأزرار، بل بكتابة كود يمكن تشغيله بأمان عدة مرات دون إنشاء موارد مكررة أو الفشل عند التشغيل الثاني.

يتحقق البرنامج النصي القابل للتنفيذ بأمان عدة مرات من وجود المورد مسبقًا قبل إنشائه. وهذا هو الأساس لأتمتة البنية التحتية الموثوقة.

  • تعيد واجهات سطر أوامر السحابة (AWS وGCP وAzure) بيانات بتنسيق JSON — لذا فإن تحليل هذه المخرجات أمر أساسي.
  • يُعد jq أداة Unix القياسية لتقسيم JSON وتصفيته وتحويله من البرامج النصية للصدفة.
  • يتيح الجمع بين CLI وjq والمنطق الشرطي كتابة نصوص توفير قوية وقابلة للتكرار.

على مدار هذا الدرس، ستوفّر حاويات S3 ومثيلات EC2 وأدوار IAM باستخدام AWS CLI كمرجع، مع أنماط تنتقل مباشرةً إلى gcloud وaz.

تثبيت واجهات CLI السحابية والتحقق منها

قبل كتابة النصوص، تأكد من توفر الأدوات الصحيحة. ثبّت الإصدارات دائمًا في CI لتجنب اختلاف البيئات بمرور الوقت.

يتحقق المقطع أدناه من AWS CLI v2 وjq وGCP SDK، ولا يثبت إلا ما هو مفقود — وهو نمط مفيد في نصوص التمهيد للأجهزة الافتراضية أو الحاويات الجديدة.

#!/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."

الاستعلام عن الموارد الموجودة باستخدام jq

الخطوة الأولى في أي برنامج نصي قابل للتنفيذ بأمان عدة مرات هي إجراء قراءة — أي سؤال API عما إذا كان المورد موجودًا مسبقًا، ثم التفرع وفقًا لذلك.

يعيد AWS CLI دائمًا بيانات بتنسيق JSON. ويتيح لك jq استخراج الحقل الذي تحتاج إليه بدقة:

  • jq -r '.Buckets[].Name' — مخرجات نصية خام، مع اسم حاوية واحد في كل سطر.
  • jq -e — ينتهي برمز الخروج 1 إذا أنتج التعبير null أو false، مما يجعله مثاليًا لحواجز if.
  • jq '.[] | select(.Name == env.BUCKET)' — التصفية باستخدام متغير صدفة عبر env.

يسرد المقطع أدناه جميع حاويات S3 ويتحقق مما إذا كانت الحاوية المستهدفة موجودة مسبقًا.

#!/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."
fi

إنشاء حاوية S3 بطريقة قابلة للتنفيذ بأمان عدة مرات

بعد إجراء فحص الوجود، ضع عملية الإنشاء داخل حارس. تتبع وظيفة سحابية جيدة التنظيم هذا النمط:

  1. قراءة الحالة الحالية من API.
  2. مقارنة الحالة المطلوبة بالحالة الفعلية.
  3. التصرف فقط عند وجود اختلاف.

لاحظ الخيار --create-bucket-configuration — فهو مطلوب لجميع المناطق باستثناء us-east-1. ويؤدي تثبيت المنطقة داخل البرنامج النصي إلى تجنب حالات الفشل الصامتة عند عدم ضبط AWS_DEFAULT_REGION.

#!/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"

تحليل JSON المتداخل: حالة مثيل EC2

تكون استجابات EC2 متداخلة بعمق. ينجح كل من اجتياز المسارات باستخدام jq و--query (وهو JMESPath المدمج في AWS CLI)، لكن jq أقوى في المنطق المعقد.

أنماط jq الأساسية لـ EC2:

  • .Reservations[].Instances[] — تسطيح بنية المصفوفتين المتداخلتين.
  • select(.State.Name == "running") — التصفية حسب الحالة.
  • .Tags[] | select(.Key == "Name") | .Value — استخراج قيمة وسم.

يعثر المقطع على مثيل قيد التشغيل باستخدام وسم Name ويعيد معرّفه وعنوان IP الخاص به.

#!/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"

توفير دور IAM بطريقة قابلة للتنفيذ بأمان عدة مرات

موارد IAM عامة ويجب عدم تكرارها. يعيد AWS رمز خطأ محددًا — EntityAlreadyExists — عند محاولة إنشاء دور موجود مسبقًا. ويُعد التقاط هذا الرمز نمطًا أنظف لضمان قابلية التنفيذ عدة مرات من استدعاء يسرد الموارد قبل الفحص عند التعامل مع IAM على نطاق واسع.

يوضح البرنامج النصي أدناه ما يلي:

  • التقاط رمز خروج CLI باستخدام || true لمنع set -e من إيقاف التنفيذ.
  • تحليل JSON الخاص برسالة الخطأ التي يكتبها AWS إلى stderr باستخدام استبدال العملية.
  • إرفاق سياسة فقط إذا لم تكن مرفقة مسبقًا.
#!/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 المتقدم: التحويلات وعمليات map وtoentries

تحتوي استجابات البنية التحتية الفعلية على عشرات الحقول. تتيح لك تحويلات jq إعادة تشكيل المخرجات لتناسب الأدوات اللاحقة أو السجلات أو ملفات الإعدادات.

الأنماط المتقدمة الأساسية:

  • map(select(...)) — تصفية مصفوفة دون فقدان غلاف المصفوفة.
  • to_entries | map(select(.value != null)) — إزالة الحقول ذات القيمة null قبل الكتابة إلى ملف إعدادات.
  • [.[] | {id: .InstanceId, ip: .PrivateIpAddress}] — إسقاط البيانات إلى بنية جديدة.
  • @csv و@tsv و@base64 — محوّلات تنسيق مدمجة.

يستخرج المقطع أدناه جميع المثيلات قيد التشغيل ويكتب ملف جرد بتنسيق 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"

انتظار العمليات غير المتزامنة: الاستطلاع باستخدام jq

العمليات السحابية غير متزامنة. يؤدي إنشاء مثيل EC2 إلى إرجاع النتيجة فورًا مع الحالة pending. يجب أن تستطلع البرامج النصية الموثوقة الحالة حتى الوصول إلى الحالة المطلوبة قبل المتابعة.

يستخدم النمط أدناه حلقة until مع تراجع أُسّي. يوفر AWS CLI أيضًا أوامر فرعية wait (مثل aws ec2 wait instance-running)، لكن الاستطلاع المكتوب يدويًا يمنحك تحكمًا مخصصًا في المهلة وسجلات أكثر تفصيلًا.

#!/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."

نمط متعدد السحب: نظائر GCP وAzure

ينتقل نمط القراءة ثم التصرف القابل للتنفيذ بأمان عدة مرات مباشرةً إلى واجهات CLI السحابية الأخرى. يعيد كل من gcloud وaz بيانات JSON ويدعم التصفية:

  • GCP: gcloud ... --format='json' — مرّر المخرجات إلى jq تمامًا كما تفعل مع AWS. استخدم gcloud ... --quiet لمنع المطالبات في البرامج النصية.
  • Azure: az ... --output json — النمط نفسه. يعيد az group exists سلسلة منطقية عادية (true/false)، مما يلغي الحاجة إلى jq في الحالات البسيطة.

يوضح المقطع إنشاء مجموعة موارد بطريقة قابلة للتنفيذ بأمان عدة مرات في Azure وإنشاء حاوية GCS في GCP جنبًا إلى جنب باستخدام نمط الحارس نفسه.

#!/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
fi

الإزالة: تدمير الموارد بأمان

تُعد نصوص التدمير مهمة بقدر نصوص الإنشاء. تتضمن عملية الإزالة الآمنة ما يلي:

  • سرد الموارد قبل حذف أي شيء وطباعة ملخص لمراجعته من قِبل الإنسان.
  • قبول الخيار --dry-run حتى يتمكن المشغلون من تأكيد الخطة دون تنفيذها.
  • الحذف بترتيب التبعيات الصحيح (مثل إنهاء المثيلات قبل حذف مجموعات الأمان).

ينهي المقطع أدناه جميع مثيلات EC2 الموسومة بالوسم Env=staging مع استخدام حارس التشغيل التجريبي.

#!/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."

من البداية إلى النهاية: سكربت التهيئة الشامل للبنية التحتية القابل للتكرار بأمان

بتجميع كل ذلك معًا: ينسّق سكربت التهيئة بمستوى جاهز للإنتاج عدة موارد بالترتيب الصحيح، ويكون قابلًا للتكرار بأمان بالكامل، ويُصدر سجلات منظمة يمكن لنظام CI تحليلها.

أهم الممارسات الموضحة:

  • التسجيل المنظم عبر المساعد log() الذي يضيف بادئات [INFO] و[WARN] و[ERROR].
  • ملف الحالة — اكتب معرّفات الموارد التي أُنشئت في ملف حالة بتنسيق JSON، حتى تشترك عمليات التشغيل اللاحقة وسكربتات الإزالة في المراجع نفسها.
  • اعتراض الأخطاء — يلتقط trap عمليات الخروج غير المتوقعة ويُبلغ عن رقم السطر الذي وقع فيه الخطأ.
#!/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 .)"

فحص المعرفة: حارس التكرار الآمن باستخدام jq

اختبر مدى فهمك لبرمجة السحابة النصية القابلة للتكرار بأمان باستخدام jq.

مراجعة: برمجة موارد السحابة عبر CLI وjq

غطّى هذا الدرس دورة الحياة الكاملة لأتمتة السحابة القابلة للتكرار بأمان باستخدام سكربتات الصدفة وواجهات CLI السحابية وjq.

المبادئ الأساسية:

  • القراءة قبل الكتابة — استعلم دائمًا عن الحالة الحالية أولًا، ولا تنفّذ سوى التغييرات الفعلية.
  • استخدام jq -e كحواجز تحقق — استخدم وضع حالة الخروج لتوجيه فروع if اعتمادًا على استجابات JSON.
  • دلالات رموز الأخطاء — التقط رموز الأخطاء الخاصة بمزوّد الخدمة، مثل EntityAlreadyExists، بدلًا من سرد الموارد مسبقًا عندما يكون ذلك أكثر كفاءة.
  • استطلاع الحالة غير المتزامنة — استخدم حلقات until مع مهلات زمنية، ولا تفترض أبدًا أن المورد أصبح جاهزًا فور إنشائه.
  • ملفات الحالة — اكتب معرّفات الموارد في ملف JSON مشترك، حتى تستخدم كل مرحلة من مراحل السكربت وعمليات الإزالة المراجع نفسها.
  • خيارات التشغيل التجريبي — وفّر دائمًا الخيار --dry-run لتمكين المشغّل من المراجعة الآمنة قبل تنفيذ الإجراءات التدميرية.

تشكل هذه الأنماط، إلى جانب ترويسة set -euo pipefail الصارمة واعتراض ERR، أساس برمجة البنية التحتية النصية بمستوى جاهز للإنتاج في المستوى C2.

الأسئلة الشائعة

هل درس «برمجة موارد السحابة باستخدام CLI وjq» مجاني؟

نعم — نص درس «برمجة موارد السحابة باستخدام CLI وjq» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة DevOps Bootcamp، انتقل إلى CoddyKit PRO. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.

ماذا ستتعلم في «برمجة موارد السحابة باستخدام CLI وjq»؟

شغّل واجهات CLI لمزوّدي الخدمات السحابية بطريقة قابلة للتكرار وحلّل استجابات JSON لإنشاء الموارد وإزالتها تتمرن على DevOps Bootcamp مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ DevOps Bootcamp؟

لا تُشترط خبرة سابقة. DevOps Bootcamp على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «برمجة موارد السحابة باستخدام CLI وjq»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس DevOps Bootcamp هذا؟

نعم. كل درس في DevOps Bootcamp يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. كتابة Dockerfiles خفيفة ونقاط دخول Shell
  2. إنشاء قوالب الإعدادات باستخدام envsubst وheredocs
  3. برمجة موارد السحابة باستخدام CLI وjq
  4. فحوصات الصحة وبوابات الجاهزية وحلقات الانتظار
← العودة إلى DevOps Bootcamp