أتمتة تقرير تكلفة AWS اليومي على Slack
لو بتفتح AWS Console أول الشهر وبتكتشف فاتورة أعلى بـ 300 دولار من المتوقع، المشكلة مش في AWS — المشكلة إنك بتشوف الأرقام متأخر 30 يوم. التقرير اليومي بيوقف المفاجآت دي في 24 ساعة بدل 30.
المشكلة باختصار
Cost Explorer عند AWS بيحدّث الأرقام كل 24 ساعة تقريبًا. Budgets Alerts الرسمية بتصرفك لمّا تتعدّى حد معيّن، لكنها بتعيد التقييم كل 8–12 ساعة ومش بتديك breakdown بالخدمة. لو EC2 instance فضي اشتغل غلط، أو NAT Gateway بيستنزف 4 دولار في اليوم، الـ Budgets مش هتكشفها غير بعد ما الرقم يتراكم.
الحل اللي هنشرحه: Lambda function بتشتغل كل يوم الساعة 9 صباحًا، بتسحب تكلفة أمس مجزّأة بالخدمة، وبتبعتها على Slack. التكلفة الإجمالية للأتمتة: أقل من دولار في الشهر.
ليه يومي بدل شهري؟
تخيّل عندك موقع بيستقبل 50K زائر/يوم، وشغلت CloudFront distribution جديدة بإعداد غلط. الإعداد ده بيخلّي الـ cache hit ratio يبقى 20% بدل 85%، والـ origin بيتحمّل ضغط زيادة. النتيجة: فاتورة data transfer بتزيد من حوالي 12 دولار/يوم إلى 47 دولار/يوم.
بدون تقرير يومي، أنت هتكتشف الموضوع بعد 28 يوم وأنت بتدفع زيادة تقديرية حوالي 980 دولار. بتقرير يومي، هتلاحظ القفزة تاني يوم وتعدّل الإعداد قبل ما الرقم يتراكم.
المفهوم بأسلوب بسيط الأول
فكّر في التقرير اليومي زي كشف حساب البنك. لو البنك بيبعتلك كشف كل 30 يوم، وفيه مصاريف غريبة، الضرر وقع. لو بيبعتلك SMS بعد كل عملية، بتوقف الخطأ في ثواني. التقرير اليومي لـ AWS هو نفس الفكرة بالظبط، بس للفاتورة السحابية.
بشكل أدق: AWS Cost Explorer API بيعرض بيانات التكلفة بدقّة DAILY أو HOURLY. Lambda بتستدعي الـ API، تجمع النتايج، وتبعتها على Slack Webhook. EventBridge بيشغّل Lambda على cron يومي.
الحل — 5 خطوات
- فعّل Cost Explorer من حساب Billing (مستخدم مش admin مش هيقدر).
- اعمل IAM role لـ Lambda فيها صلاحية
ce:GetCostAndUsageوlogs:CreateLogStream. - اعمل Slack Incoming Webhook من channel إداري.
- ارفع الـ Lambda function بالكود اللي تحت.
- اربطها بـ EventBridge schedule يومية.
السكربت الكامل (Python 3.12)
import boto3
import json
import os
from datetime import date, timedelta
from urllib import request
ce = boto3.client("ce")
WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
THRESHOLD = float(os.environ.get("SPIKE_PCT", "30"))
def lambda_handler(event, context):
today = date.today()
yday = today - timedelta(days=1)
prev = today - timedelta(days=2)
def fetch(start, end):
r = ce.get_cost_and_usage(
TimePeriod={"Start": str(start), "End": str(end)},
Granularity="DAILY",
Metrics=["UnblendedCost"],
GroupBy=[{"Type": "DIMENSION", "Key": "SERVICE"}],
)
return {
g["Keys"][0]: float(g["Metrics"]["UnblendedCost"]["Amount"])
for g in r["ResultsByTime"][0]["Groups"]
}
curr = fetch(yday, today)
base = fetch(prev, yday)
rows = sorted(curr.items(), key=lambda x: -x[1])
total = sum(curr.values())
lines = [f"*AWS cost — {yday}*", f"Total: *${total:.2f}*", ""]
for svc, amt in rows[:8]:
if amt < 0.01:
continue
prev_amt = base.get(svc, 0) or 0.001
pct = ((amt - prev_amt) / prev_amt) * 100
flag = " :rotating_light:" if pct > THRESHOLD and amt > 1 else ""
lines.append(f"- {svc}: ${amt:.2f} ({pct:+.0f}%){flag}")
payload = {"text": "\n".join(lines)}
req = request.Request(
WEBHOOK,
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
)
request.urlopen(req, timeout=10).read()
return {"ok": True, "total": total}
السكربت بيقارن تكلفة أمس بأول أمس لكل خدمة. لو في قفزة أعلى من 30% على خدمة تكلفتها أكتر من دولار، بيحط علم أحمر. ده بيخلّي الفريق يشوف السبب بدل ما يشوف رقم كلي بس.
النشر من CLI
zip function.zip lambda_function.py
aws lambda create-function \
--function-name aws-daily-cost \
--runtime python3.12 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::ACCOUNT_ID:role/lambda-cost-report \
--zip-file fileb://function.zip \
--environment "Variables={SLACK_WEBHOOK_URL=https://hooks.slack.com/...,SPIKE_PCT=30}" \
--timeout 30
# يشتغل كل يوم 9 صباحًا UTC (12 ظهر بتوقيت القاهرة)
aws events put-rule \
--name daily-aws-cost \
--schedule-expression "cron(0 9 * * ? *)"
aws events put-targets \
--rule daily-aws-cost \
--targets "Id"="1","Arn"="arn:aws:lambda:REGION:ACCOUNT_ID:function:aws-daily-cost"
الـ trade-offs اللي لازم تعرفها
Cost Explorer API مش مجاني. كل استدعاء بيكلّف 0.01 دولار حسب AWS. لو بتنادي الـ API مرتين كل تشغيل (current + baseline)، التكلفة الشهرية: 2 × 30 = 60 طلب × 0.01 = 0.60 دولار. Lambda نفسها: أقل من سنت في الشهر لأن Free Tier بيغطي أول مليون طلب. المجموع: حوالي 0.60 دولار/شهر.
بتكسب: رؤية يومية بالخدمة، اكتشاف spikes خلال 24 ساعة، breakdown قابل للقراءة بدل فاتورة شهرية مبهمة. بتخسر: 60 سنت شهريًا، و12 ثانية من وقت تنفيذ Lambda.
الافتراض هنا: حسابك AWS أقل من 50 خدمة نشطة، ومستعمل region واحد أو اتنين. لو عندك 20 account عبر AWS Organizations، لازم تستخدم GetCostAndUsage من الـ payer account مع Filter على LINKED_ACCOUNT، والمنطق يبقى أعقد.
متى لا تستخدم هذه الطريقة
لو فاتورتك الشهرية أقل من 50 دولار، الـ ROI مش مبرر — Budgets Alerts الرسمية كفاية. لو بتستخدم أكتر من 5 accounts، ابني الحل على AWS Cost and Usage Reports (CUR) + Athena بدل Cost Explorer API، لأن CUR بيديك granularity أعلى وبسعر أقل لكل استعلام. لو فريقك مش بيقرأ Slack يوميًا، التقرير هيبقى noise — وجّهه لقناة مخصّصة وخلي بس التنبيهات الحمراء تترفع لقناة عامة.
الخطوة التالية
افتح AWS Billing Console ثم Cost Explorer واعمل Enable الآن (بياخد 24 ساعة يبدأ يجمع بيانات). بعدها انسخ السكربت فوق، عدّل SLACK_WEBHOOK_URL، وارفعه. بعد يومين هتبدأ تشوف التقرير اليومي. لو شفت spike أحمر على خدمة مش عارفها، استخدم ce.get_cost_and_usage مع GroupBy على USAGE_TYPE للخدمة دي تحديدًا — هتكشف السبب في دقيقة.
مصادر
- AWS Cost Explorer API — GetCostAndUsage documentation.
- تسعير Cost Explorer API (0.01 دولار لكل طلب) — AWS Cost Management Pricing.
- تسعير Lambda (Free Tier يغطي أول مليون طلب شهريًا) — AWS Lambda Pricing.
- EventBridge Schedules بـ cron expression — EventBridge Scheduled Rules.
- Slack Incoming Webhooks — Slack API Webhooks.
- AWS Cost and Usage Report (CUR) + Athena — Query CUR with Amazon Athena.