سیریز A کے آغاز کے لیے AWS FinOps گائیڈ: 8 لاگت کے نمونے جو پروڈکٹ-مارکیٹ فٹ ہونے کے بعد ظاہر ہوتے ہیں

آپ نے اپنی سیریز A کو بڑھایا۔ انجینئرنگ ٹیم کو تیزی سے بھرتی کر لیا گیا۔ خصوصیات تیزی سے فراہم کی جاتی ہیں۔ اور کہیں 6 اور 12 ماہ کے بعد، کوئی AWS Cost Explorer کا اسکرین شاٹ لے کر گزرا جس نے صرف لائن کو اوپر جاتے ہوئے دکھایا۔

وہ لائنیں بے ترتیب نہیں ہیں۔ یہ ایک پیٹرن کی پیروی کرتا ہے. ترقی کے ایک ہی مرحلے پر وہی آٹھ نمونے تقریباً ہر کمپنی میں سامنے آئے جن کا میں نے آڈٹ کیا۔

یہ گائیڈ تمام آٹھوں کے نام بتاتا ہے، آپ کو ظاہر کرتا ہے کہ کہاں دیکھنا ہے، اور ہر ایک کے لیے اصلاحات فراہم کرتا ہے۔ جب تک آپ کتاب پڑھنا ختم کر لیں گے، آپ کو معلوم ہو جائے گا کہ آپ کے رن وے کو کیا لیکس کر رہے ہیں اور اس ہفتے اس کے بارے میں کیا کرنا ہے۔

انڈیکس

یہ گائیڈ کس کے لیے ہے۔

یہ گائیڈ انجینئرز، CTOs، اور سیریز A کمپنیوں کے تکنیکی شریک بانی کے لیے لکھی گئی ہے۔ عام طور پر، 15 سے 80 انجینئرز ہوتے ہیں، AWS بلنگ \(20,000 سے \)150,000 ماہانہ ہے، اور فنانس ٹیم نے حال ہی میں انفراسٹرکچر لائن میں دلچسپی لینا شروع کی ہے۔

ایک سرشار FinOps ٹیم کی ضرورت نہیں ہے۔ آپ کو ہفتے میں ایک دوپہر کے لیے اس گائیڈ میں ایک انجینئر اور آٹھ نمونوں کی ضرورت ہوگی۔

شروع کرنے سے پہلے آپ کو کیا ضرورت ہے:

  • Cost Explorer کو فعال کرکے AWS اکاؤنٹ تک رسائی حاصل کریں۔

  • AWS CLI v2 کنفیگریشن (aws configure)

  • EC2، RDS، EBS اور S3 کا بنیادی علم

  • بک مارک لاگت ایکسپلورر – آپ اسے بار بار استعمال کریں گے۔

تمام ترامیم کو مکمل کرنے کا تخمینہ وقت: انجینئرنگ کے آٹھ سے 20 گھنٹے کا وقت دو سپرنٹ میں پھیلا ہوا ہے۔ اسے پڑھنے میں تقریباً 20 منٹ لگتے ہیں۔ سب سے زیادہ ROI طے کرنے میں (پیٹرن 3) تقریباً 30 منٹ لگتے ہیں۔

شروع کرنے سے پہلے: ایک بیس لائن سیٹ کرنا

اس قدم کو مت چھوڑیں۔ معیار کے بغیر اصلاح محض اندازہ لگانا ہے۔ کسی بھی چیز کو چھونے سے پہلے، درج ذیل کمانڈ کو چلائیں:

# Pull last month's AWS cost breakdown by service
# This becomes your before number — save it somewhere
aws ce get-cost-and-usage \
  --time-period Start=\((date -d 'last month' +%Y-%m-01),End=\)(date +%Y-%m-01) \
  --granularity MONTHLY \
  --group-by Type=DIMENSION,Key=SERVICE \
  --metrics UnblendedCost \
  --query 'ResultsByTime[0].Groups[*].{Service:Keys[0],Cost:Metrics.UnblendedCost.Amount}' \
  --output table | sort -k3 -rn

پھر آؤٹ پٹ کو اسکرین شاٹ کریں۔ فائل کا نام بتائیں aws-baseline-YYYY-MM.png. ہر ترمیم کے بعد، آپ اصل بچت دیکھنے کے لیے ان کا موازنہ کر سکتے ہیں۔

سیریز A کی عمومی خرابی اس طرح ہے:

AWS خدمات بل کا % ضائع کرنے کی صلاحیت
EC2 (کمپیوٹ) 45~55% اعلی
ڈیٹا کی منتقلی 15-20% بہت اعلی
آر ڈی ایس 10-15% درمیانی
ای بی ایس 8~12% درمیانی
کلاؤڈ واچ 3-6% درمیانی
لوڈ بیلنسر 3~5% کم

اب آئیے ہر ایک پیٹرن کو دیکھیں۔

پیٹرن 1: نیا ہائرنگ تجرباتی ٹیکس

انجینئرنگ کی تمام ملازمتوں کو ترقی کے ماحول کی ضرورت ہوتی ہے۔ یہ متوقع ہے۔ آپ جس چیز کی توقع نہیں کر سکتے ہیں وہ ہے جو کسی خصوصیت کے جاری ہونے کے بعد ہوتا ہے۔ کچھ بھی نہیں ہے۔

ماحول چلتا رہے گا۔ m5.xlarge کے لیے، $(0.192/hour) کے بھولے ہوئے ترقیاتی ماحول کی قیمت $138/مہینہ ہے۔ ایک ماحول کو بھولنے والے 10 انجینئرز کی لاگت $1,380 فی مہینہ ہے۔ یہ بنیادی ڈھانچے کی قیمت ہے جو کچھ نہیں کرتی ہے۔

یہ نمونہ سیریز A کے بعد تیز ہو جاتا ہے کیونکہ ملازمت پر کام جلدی ہوتا ہے۔ ایک نیا انجینئر پیر کو شامل ہوتا ہے، EC2، RDS، اور ڈویلپمنٹ کلسٹر پر نام کی جگہ کو گھماتا ہے، جمعہ تک جہاز کی خصوصیات، اور اگلے ٹکٹ پر چلا جاتا ہے۔ ماحول کسی کے راڈار پر نہیں ہے۔ ترقیاتی وسائل کے لیے کوئی آف بورڈنگ عمل نہیں ہے۔

فضلہ کیسا لگتا ہے:

Dev environment for Alice (feature/payment-flow):
  EC2 m5.xlarge — last CPU activity: 23 days ago
  RDS db.t3.medium — last connection: 19 days ago
  EKS namespace — last pod scheduled: 15 days ago
  Monthly cost: $187
  Status: running

اسے تلاش کرنا:

# Find EC2 instances with average CPU below 5% for the last 14 days
# These are idle instances — candidates for shutdown or termination
aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --period 1209600 \
  --statistics Average \
  --start-time $(date -d '14 days ago' --iso-8601=seconds) \
  --end-time $(date --iso-8601=seconds) \
  --dimensions Name=InstanceId,Value=YOUR_INSTANCE_ID \
  --query 'Datapoints[*].{Average:Average}' \
  --output table

درست کریں – خودکار بیکار مثال کو روکنے والا آلہ:

نیچے لیمبڈا ہر رات 22:00 بجے چلتا ہے۔ تمام ٹیگ شدہ EC2 مثالوں کو چیک کریں۔ Environment=dev گزشتہ 7 دنوں کے لیے CPU کا استعمال۔ کوئی بھی مثال جہاں اوسط 5% سے نیچے آجاتی ہے خود بخود روک دی جاتی ہے۔ بند ہونے سے پہلے، انجینئر کے ای میل پر ایک SNS اطلاع بھیجی جاتی ہے، جس سے انجینئر کو یہ شامل کر کے اسے اوور رائڈ کرنے کا موقع ملتا ہے: KeepAlive=true ٹیگ

# idle_environment_stopper.py
# Deploy as a Lambda function triggered by EventBridge on schedule: cron(0 22 * * ? *)
# This stops idle dev environments before they run through the night and weekend

import boto3
from datetime import datetime, timedelta, timezone

ec2 = boto3.client('ec2')
cloudwatch = boto3.client('cloudwatch')
sns = boto3.client('sns')

IDLE_CPU_THRESHOLD = 5.0      # Stop instances below this average CPU %
IDLE_DAYS = 7                  # Look back 7 days of CloudWatch data
SNS_TOPIC_ARN = 'arn:aws:sns:us-east-1:YOUR_ACCOUNT:dev-environment-alerts'

def get_average_cpu(instance_id):
    """Return the 7-day average CPU utilisation for an EC2 instance."""
    response = cloudwatch.get_metric_statistics(
        Namespace="AWS/EC2",
        MetricName="CPUUtilization",
        Dimensions=[{'Name': 'InstanceId', 'Value': instance_id}],
        StartTime=datetime.now(timezone.utc) - timedelta(days=IDLE_DAYS),
        EndTime=datetime.now(timezone.utc),
        Period=604800,  # One 7-day period
        Statistics=['Average']
    )
    datapoints = response.get('Datapoints', [])
    return datapoints[0]['Average'] if datapoints else 0.0

def lambda_handler(event, context):
    """Stop idle dev instances and notify their owners."""
    
    # Find all running dev instances
    response = ec2.describe_instances(
        Filters=[
            {'Name': 'instance-state-name', 'Values': ['running']},
            {'Name': 'tag:Environment', 'Values': ['dev', 'development']},
        ]
    )

    stopped = []
    skipped = []

    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instance_id = instance['InstanceId']
            tags = {t['Key']: t['Value'] for t in instance.get('Tags', [])}

            # Skip instances explicitly marked to keep alive
            if tags.get('KeepAlive', '').lower() == 'true':
                skipped.append(instance_id)
                continue

            avg_cpu = get_average_cpu(instance_id)

            if avg_cpu < IDLE_CPU_THRESHOLD:
                # Notify the owner before stopping
                owner = tags.get('Owner', 'unknown')
                sns.publish(
                    TopicArn=SNS_TOPIC_ARN,
                    Subject=f'Dev environment stopped: {instance_id}',
                    Message=(
                        f'Instance {instance_id} (Owner: {owner}) had {avg_cpu:.1f}% average CPU '
                        f'over {IDLE_DAYS} days and has been stopped.\n\n'
                        f'To prevent this, add the tag: KeepAlive=true\n'
                        f'To restart: aws ec2 start-instances --instance-ids {instance_id}'
                    )
                )
                ec2.stop_instances(InstanceIds=[instance_id])
                stopped.append({'id': instance_id, 'owner': owner, 'avg_cpu': avg_cpu})

    print(f"Stopped {len(stopped)} idle instances. Skipped {len(skipped)} keep-alive instances.")
    return {'stopped': stopped, 'skipped': skipped}

ماہانہ بچت: \(1,000~\)2,000 ٹیم کے سائز اور پیٹرن پر عمل درآمد کی مدت کے لحاظ سے۔

پیٹرن 2: اسٹیجنگ ماحول کو پھیلائیں۔

سٹیجنگ ایک ماحول سے شروع ہوتی ہے۔ پھر فرنٹ اینڈ ٹیم کو اپنی ٹیم کی ضرورت ہوتی ہے کیونکہ بیک اینڈ ٹیم ان کو توڑتی رہتی ہے۔ ایم ایل ٹیموں کو پھر الگ تھلگ کمپیوٹ کی ضرورت ہے۔ پھر QA کو انضمام کی جانچ کے لیے ایک مستحکم ماحول کی ضرورت ہے۔

ہمارے پاس چار سٹیجنگ ماحول ہیں جو کسی کے نوٹس لینے سے پہلے 24/7 چل رہے ہیں۔ ہر ایک دن میں 16 گھنٹے بیکار رہتا ہے۔

ماحول میں فضلہ موجود نہیں ہے۔ یہ شیڈول پر ہے۔ اسٹیجنگ ماحول کو صبح 3 بجے چلانے کی ضرورت نہیں ہے۔

فضلہ کیسا لگتا ہے:

staging-frontend:   $250/month   Used: Mon-Fri 09:00-18:00
staging-backend:    $250/month   Used: Mon-Fri 09:00-18:00
staging-ml:         $250/month   Used: Mon-Fri 10:00-17:00
staging-qa:         $250/month   Used: Mon-Fri 09:00-17:00
Total:            $1,000/month   Running: 24 hours/day, 7 days/week
Actual usage:        ~35%        You are paying 100%

اسے تلاش کرنا:

# Find EKS node groups tagged as staging with their current status
aws eks list-nodegroups --cluster-name your-cluster-name --output table

# Check EC2 instances tagged staging and their launch time
# Any instance running > 30 days with no weekend stop schedule is a candidate
aws ec2 describe-instances \
  --filters "Name=tag:Environment,Values=staging" "Name=instance-state-name,Values=running" \
  --query 'Reservations[*].Instances[*].{ID:InstanceId,Type:InstanceType,Launch:LaunchTime}' \
  --output table

درست کریں - AWS انسٹینس شیڈیولر کا استعمال کرتے ہوئے طے شدہ آغاز اور رک جاتا ہے:

# Option 1: Tag-based scheduling with AWS Instance Scheduler (CloudFormation solution)
# Add these tags to your staging EC2 instances and RDS clusters:
# Schedule: office-hours
# This starts instances at 08:00 and stops them at 20:00 Mon-Fri
# Weekend: completely off

# Option 2: Quick Lambda-based solution — stop all staging at 20:00 weekdays
aws events put-rule \
  --schedule-expression "cron(0 20 ? * MON-FRI *)" \
  --name stop-staging-environments \
  --state ENABLED

# The stop Lambda — same pattern as Pattern 1 but targets staging tag
# Add a corresponding start rule at 07:30 Mon-Fri

انضمام کو شیڈولنگ میں شامل کیا گیا۔

اگر آپ کا فرنٹ اینڈ اور بیک اینڈ ایک ڈیٹا بیس اسکیما کا اشتراک کرتے ہیں، نام کی جگہ کی سطح کی تنہائی انہیں ایک مشترکہ سٹیجنگ ماحول میں مضبوط کرتی ہے۔ مشترکہ لاگت دو الگ الگ ماحول سے کم ہے۔

# One shared staging cluster with namespace isolation
# frontend-staging and backend-staging share nodes via Karpenter
# but are isolated by namespace-level network policies
apiVersion: v1
kind: Namespace
metadata:
  name: staging-frontend
  labels:
    environment: staging
    team: frontend
---
apiVersion: v1
kind: Namespace
metadata:
  name: staging-backend
  labels:
    environment: staging
    team: backend

ریاضی:

سکرپٹ ماہانہ لاگت
پچھلا: 4 ماحول، ہمیشہ آن $1,000
بعد: دو مربوط ماحول، صرف دفتری اوقات $290
ماہانہ بچت $710

پیٹرن 3: NAT گیٹ وے ٹیکس

NAT گیٹ ویز ہر AWS بل میں سب سے زیادہ مستقل طور پر کم قیمت والی آئٹم ہیں جو میں آڈٹ کرتا ہوں۔ آپ سے $0.045 فی GB ڈیٹا پروسیس کیا جاتا ہے، اور EKS کلسٹرز میں فطری طور پر ایک ٹن ٹریفک ہوتا ہے۔

ECR سے کنٹینر کی تصاویر کھینچنے والے تمام پوڈ NAT گیٹ وے سے گزرتے ہیں۔ تمام لیمبڈا S3 کو لکھتے ہیں NAT گیٹ وے سے گزرتے ہیں۔ کوئی بھی سروس جو SQS کو پول کرتی ہے، DynamoDB سے سوال کرتی ہے، یا Secrets Manager API کو کال کرتی ہے NAT گیٹ وے سے گزرتی ہے جب تک کہ آپ VPC اینڈ پوائنٹ کنفیگر نہیں کرتے۔

VPC اینڈ پوائنٹس آپ کے VPC اور AWS سروسز کے درمیان ایک نجی کنکشن بناتے ہیں۔ ٹریفک کو NAT گیٹ وے کے بجائے AWS ریڑھ کی ہڈی سے روٹ کیا جاتا ہے۔ ڈیٹا ٹرانسفر مفت ہو جاتا ہے۔

فضلہ کیسا لگتا ہے:

# Run this to see your current NAT Gateway data processing bill
aws ce get-cost-and-usage \
  --time-period Start=\((date -d 'last month' +%Y-%m-01),End=\)(date +%Y-%m-01) \
  --granularity MONTHLY \
  --filter '{
    "Dimensions": {
      "Key": "USAGE_TYPE",
      "Values": ["NatGateway-Bytes", "NatGateway-Hours"]
    }
  }' \
  --metrics UnblendedCost \
  --query 'ResultsByTime[0].Total.UnblendedCost.Amount' \
  --output text

اگر یہ تعداد \(200) سے زیادہ ہے، تو آپ کے پاس NAT گیٹ وے کا مسئلہ ہے۔ EKS چلانے والی زیادہ تر سیریز A کمپنیوں کے لیے، اس کی قیمت \)800 اور $6,000 کے درمیان ہے۔

اصلاحات — چار اعلی ترین ٹریفک AWS سروسز کے لیے VPC اینڈ پوائنٹس:

# Get your VPC ID and route table ID first
VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=tag:Name,Values=your-vpc-name" \
  --query 'Vpcs[0].VpcId' --output text)

ROUTE_TABLE_ID=$(aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" "Name=association.main,Values=true" \
  --query 'RouteTables[0].RouteTableId' --output text)

# S3 gateway endpoint — free to create, eliminates all S3 NAT charges
aws ec2 create-vpc-endpoint \
  --vpc-id $VPC_ID \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids $ROUTE_TABLE_ID

# DynamoDB gateway endpoint — also free
aws ec2 create-vpc-endpoint \
  --vpc-id $VPC_ID \
  --service-name com.amazonaws.us-east-1.dynamodb \
  --route-table-ids $ROUTE_TABLE_ID

# ECR API endpoint — eliminates NAT charges on every container pull
aws ec2 create-vpc-endpoint \
  --vpc-id $VPC_ID \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.ecr.api \
  --subnet-ids $(aws ec2 describe-subnets \
    --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Tier,Values=private" \
    --query 'Subnets[*].SubnetId' --output text)

# ECR Docker endpoint — required alongside ECR API for image pulls
aws ec2 create-vpc-endpoint \
  --vpc-id $VPC_ID \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.ecr.dkr \
  --subnet-ids $(aws ec2 describe-subnets \
    --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Tier,Values=private" \
    --query 'Subnets[*].SubnetId' --output text)

جب آپ اپنے CFO کو اس کی وضاحت کرتے ہیں، تو اسے NAT ٹیکس کہیں۔ وہ ٹیکس کو سمجھتے ہیں۔ "ہم اندرونی نیٹ ورک ٹریفک کے لیے $0.045/GB کا ٹیکس ادا کر رہے ہیں جسے 30 منٹ میں ہٹایا جا سکتا ہے" یہ "ڈیٹا پروسیسنگ بائٹس" سے بہتر ہے۔

ماہانہ بچت: \(2,000~\)8,000 (کنٹینر کی بازیافت کی فریکوئنسی اور S3 کے استعمال پر منحصر ہے)

پیٹرن 4: آپ کے بچت کے منصوبے میں وقت کی غلطیاں

بچت کا منصوبہ 30-70% رعایت کے عوض 1-3 سال کے لیے AWS کمپیوٹ پر فی گھنٹہ ایک مقررہ رقم خرچ کرنے کا عہد ہے۔ ریاضی دلچسپ ہے۔ ٹائمنگ وہ ہوتی ہے جہاں ٹیم غلط ہو جاتی ہے۔

جب آپ کے بل بڑے ہو جاتے ہیں، تو آپ کی پہلی جبلت کا ارتکاب کرنا ہوتا ہے۔ بچت کا منصوبہ خریدیں، اپنے بل کم کریں اور اپنے CFO کو دکھائیں۔ مسئلہ: اگر آپ پہلے اسکیل نہیں کرتے ہیں، تو آپ رعایتی قیمت پر فضلہ کی ادائیگی کا عہد کر رہے ہیں۔ اگر آپ بعد میں سائز تبدیل کرتے ہیں، تو آپ کے اصل اخراجات آپ کی کمٹڈ رقم سے کم ہوں گے، اور آپ اس کمپیوٹ کے لیے ادائیگی کریں گے جو آپ استعمال نہیں کر رہے ہیں۔

غلط حکم ہے:

Step 1: AWS bill is $100,000/month
Step 2: Buy $70,000/hour Savings Plan commitment
Step 3: Rightsize instances — actual spend drops to $60,000
Step 4: Savings Plan covers \(70,000 but you only use \)60,000
Step 5: You pay $28,000/month for compute you do not use
         (Savings Plan discount applied to the overage)
         
Net result: You locked in waste for 12 months

صحیح ترتیب یہ ہے:

Step 1: Rightsize instances — spend drops from \(100,000 to \)60,000
Step 2: Add Spot for staging — spend drops from \(60,000 to \)45,000
Step 3: Migrate compatible workloads to Graviton — spend drops to $36,000
Step 4: NOW buy a Savings Plan covering $25,000/month (70% of steady-state)
Step 5: Effective monthly cost: \(12,500 for committed + \)11,000 on-demand = $23,500

Net result: $76,500/month saved versus the original bill

یہ کیسے جانیں کہ آپ کو کیا کرنے کی ضرورت ہے:

# View your last 30 days of EC2 On-Demand spend
# This is your rightsized baseline — what you actually use after optimisation
aws ce get-cost-and-usage \
  --time-period Start=\((date -d '30 days ago' +%Y-%m-%d),End=\)(date +%Y-%m-%d) \
  --granularity DAILY \
  --filter '{
    "And": [
      {"Dimensions": {"Key": "SERVICE", "Values": ["Amazon Elastic Compute Cloud - Compute"]}},
      {"Dimensions": {"Key": "PURCHASE_TYPE", "Values": ["On-Demand"]}}
    ]
  }' \
  --metrics UnblendedCost \
  --query 'ResultsByTime[*].{Date:TimePeriod.Start,Cost:Total.UnblendedCost.Amount}' \
  --output table

# Get AWS's own Savings Plan recommendation based on your usage
aws savingsplans get-savings-plans-purchase-recommendation \
  --savings-plans-type COMPUTE_SP \
  --term-in-years ONE_YEAR \
  --payment-option NO_UPFRONT \
  --lookback-period-in-days THIRTY_DAYS

عام طور پر، ہم اصلاح کے بعد 60-70% مستحکم آن ڈیمانڈ خرچ کا وعدہ کرتے ہیں۔ 30-40% لچکدار رہنے دیں۔ غیر اصلاح شدہ بیس لائن کا عہد نہ کریں۔

ماہانہ بچت: \(5,000~\)15,000 (کمپیوٹ کے اخراجات پر منحصر ہے) یہ وہ پیٹرن ہے جس میں سب سے زیادہ سنگل ٹاسک ROI ہوتا ہے جب صحیح ترتیب دی جائے۔

پیٹرن 5: AZs کے درمیان ڈیٹا کی منتقلی

AWS ہر سمت میں $0.01 فی GB چارج کرتا ہے جب آپ کا ڈیٹا دستیابی زون کی حدود کو عبور کرتا ہے۔ \)0.01 غیر اہم لگتا ہے۔ یہ سچ نہیں ہے۔ اس کی وجہ یہ ہے کہ تقسیم شدہ نظاموں میں AZ کی حدود کو مسلسل عبور کیا جاتا ہے اور شرحیں دو طرفہ ہوتی ہیں۔

سب سے عام منظر نامہ یہ ہے کہ ایپلیکیشن پوڈز کو ایک سے زیادہ AZs میں شیڈول کیا جاتا ہے (لچک کے لیے)، لیکن ڈیٹا بیس کو ایک AZ پر پن کیا جاتا ہے۔ دیگر AZs میں پوڈز سے ڈیٹا بیس کے تمام سوالات کی لاگت $0.01/GB ہے ڈیٹا بیس میں جانے کے لیے اور $0.01/GB واپس۔ 100GB فی دن کے لیے ڈیٹا بیس ٹریفک \(60/مہینہ ہے۔ 1TB فی دن کے لیے، یہ \)600/مہینہ ہے۔

فضلہ کیسا لگتا ہے:

# Check current cross-AZ data transfer charges
aws ce get-cost-and-usage \
  --time-period Start=\((date -d 'last month' +%Y-%m-01),End=\)(date +%Y-%m-01) \
  --granularity MONTHLY \
  --filter '{"Dimensions": {"Key": "USAGE_TYPE", "Values": ["DataTransfer-Regional-Bytes"]}}'  \
  --metrics UnblendedCost \
  --query 'ResultsByTime[0].Total.UnblendedCost.Amount' \
  --output text

کراس-AZ ٹریفک چلانے والے پوڈز کو کیسے تلاش کریں:

# Check which AZ your database RDS instance is in
aws rds describe-db-instances \
  --query 'DBInstances[*].{ID:DBInstanceIdentifier,AZ:AvailabilityZone}' \
  --output table

# Check which AZs your application pods are running in
kubectl get pods -o wide -n production | awk '{print $7}' | sort | uniq -c

اگر آپ کے پاس RDS ہے۔ us-east-1a فورڈ کا 60٪ us-east-1b اور us-east-1cکراس AZ ٹریفک کا مسئلہ ہے۔

درست کریں - ٹوپولوجی سے آگاہ روٹنگ:

# topology-aware-routing.yaml
# This tells Kubernetes to prefer scheduling pods in the same AZ
# as the node making the request — keeping traffic local

apiVersion: v1
kind: Service
metadata:
  name: payment-api
  namespace: production
  annotations:
    # Route traffic to pods in the same AZ as the caller when possible
    service.kubernetes.io/topology-mode: "Auto"
spec:
  selector:
    app: payment-api
  ports:
  - port: 8080
    targetPort: 8080
# For pods themselves — spread across AZs but prefer local
# topologySpreadConstraints ensures even distribution
# while topology-aware routing keeps traffic within AZs

spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: payment-api

خاص طور پر ڈیٹا بیس ٹریفک کے لیے، سنگل-AZ RDS سے Aurora میں منتقل ہونے پر غور کریں، جو AZ روٹنگ کو اندرونی طور پر ہینڈل کرتا ہے۔ آپ کی ایپلیکیشن ایک اینڈ پوائنٹ سے جڑتی ہے اور ارورہ اسے اندرونی طور پر روٹ کرتی ہے۔ ایپلیکیشن لیئر پر کوئی انٹر-AZ چارجز نہیں ہیں۔

ماہانہ بچت: \(500~\)6,000 ڈیٹا بیس کے استفسار کے حجم اور پوڈ کی AZ تعیناتی پر منحصر ہے۔

پیٹرن 6: gp2 والیوم ٹریپ

2014 میں، AWS نے gp2 EBS والیومز کا آغاز کیا۔ 2020 میں انہوں نے جی پی 3 جاری کیا، جو سستا، تیز، اور باکس سے باہر کی بہتر کارکردگی کا حامل ہے۔ 2026 میں، زیادہ تر سیریز A کمپنیاں اب بھی gp2 چلا رہی ہوں گی۔

فرق: gp2 کی قیمت $(0.10/GB/مہینہ) ہے اور 3 IOPS فی GB (کم از کم 100 IOPS) فراہم کرتا ہے۔ gp3 کی قیمت ₩0.08/GB/مہینہ ہے اور سائز سے قطع نظر 3,000 IOPS کی بنیادی لائن فراہم کرتا ہے۔ زیادہ تر حجم کے سائز کے لیے IOPS میں gp3 20% سستا اور 10x تیز ہے۔ ہجرت آن لائن ہے۔ یعنی یہ اس وقت تک چلتا ہے جب تک حجم منسلک اور استعمال میں ہو۔

تمام gp2 والیوم تلاش کریں:

# List every gp2 volume in your account with its size and monthly cost
aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'Volumes[*].{
    ID:VolumeId,
    Size:Size,
    State:State,
    MonthlyCost_USD:Size
  }' \
  --output table

# Count the total: number of volumes and combined GB
aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'length(Volumes)' --output text

aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'sum(Volumes[*].Size)' --output text

درست کریں - تمام gp2 کو ایک اسکرپٹ میں gp3 میں منتقل کریں:

#!/bin/bash
# migrate_gp2_to_gp3.sh
# Migrates all gp2 volumes to gp3. Online operation — no downtime.
# Each modification runs asynchronously; the volume stays available throughout.

echo "Starting gp2 to gp3 migration..."

# Get all gp2 volume IDs
VOLUMES=$(aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'Volumes[*].VolumeId' \
  --output text)

COUNT=0
for VOL_ID in $VOLUMES; do
  echo "Migrating $VOL_ID to gp3..."
  aws ec2 modify-volume \
    --volume-id $VOL_ID \
    --volume-type gp3 \
    --no-cli-pager
  COUNT=$((COUNT + 1))
done

echo "Migration initiated for $COUNT volumes."
echo "Modifications run online — no downtime. Monitor progress:"
echo "aws ec2 describe-volumes-modifications --query 'VolumesModifications[*].{ID:VolumeId,State:ModificationState}'"

تکمیل کی تصدیق کریں:

# Check that no gp2 volumes remain
aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'length(Volumes)' \
  --output text
# Expected: 0

ماہانہ بچت: کل EBS خرچ کا 20%۔ EBS 10,000 ون فی مہینہ، یا 30 منٹ کے کام کے لیے 2,000 ون بچاتا ہے۔

پیٹرن 7: لامحدود لاگ ٹریپ

CloudWatch لاگ گروپس میں "کبھی ختم نہیں ہوتا" کی ڈیفالٹ برقرار رکھنے کی پالیسی ہوتی ہے۔ واضح برقرار رکھنے کی ترتیبات کے بغیر بنایا گیا کوئی بھی لاگ گروپ غیر معینہ مدت تک لاگ جمع کرے گا۔ مصروف سیریز A کمپنیوں کے لیے، اس کا مطلب 2022 سے ڈیبگ لاگز کو محفوظ کرنا ہے جو سپرنٹ ریویو کے بعد سے کسی نے نہیں کھولے ہیں۔

اخراجات خاموشی سے بڑھ رہے ہیں۔ CloudWatch لاگ اسٹوریج کے لیے $0.03/GB/ماہ اور لاگ انگزیشن کے لیے $0.50/GB چارج کرتا ہے۔ یومیہ 50 جی بی لاگ تیار کرنے والا کلسٹر \(25/دن — \)750/مہینہ جمع کرے گا اور پھر ان لاگز کو بڑھتے ہوئے ماہانہ لاگت پر ہمیشہ کے لیے محفوظ کر لے گا۔

برقرار رکھنے کی پالیسی کے بغیر لاگ گروپس تلاش کریں:

# List all log groups with their retention settings
# Any group showing "retentionInDays: null" is infinite — it never expires
aws logs describe-log-groups \
  --query 'logGroups[*].{Name:logGroupName,RetentionDays:retentionInDays,StoredBytes:storedBytes}' \
  --output table | grep -E "(None|null)"

# Count how many log groups have no retention set
aws logs describe-log-groups \
  --query 'length(logGroups[?retentionInDays==`null`])' \
  --output text

کام کاج - بڑی تعداد میں برقرار رکھنے کی پالیسی سیٹ کریں:

لاگ کی مختلف اقسام میں تعمیل کے مختلف تقاضے ہوتے ہیں۔ ڈیبگ لاگز رکھنے کی ضرورت نہیں ہے۔ آڈٹ لاگز میں 365 دن لگ سکتے ہیں۔ نیچے دی گئی جدول میں معقول ڈیفالٹس کی فہرست ہے۔

لاگ کی قسم برقرار رکھنے کی سفارش کی گئی۔ وجہ
ایپلیکیشن ڈیبگ لاگ 14 دن صرف فعال ڈیبگنگ کے لیے مفید ہے۔
درخواست کی خرابی کا لاگ 90 دن حادثے کے بعد کی تفتیش کی کھڑکی
رسائی لاگ 30 دن سیکیورٹی جائزہ ونڈو
CloudTrail آڈٹ لاگز 365 دن SOC2 ثبوت کے تقاضے
VPC فلو لاگز 90 دن سیکورٹی تحقیقاتی ونڈو
#!/bin/bash
# set_log_retention.sh
# Sets 30-day retention on all log groups that have no policy set
# Adjust the retention period per log group type as needed

echo "Setting retention policies on log groups with no expiry..."

# Get all log groups with no retention
aws logs describe-log-groups \
  --query 'logGroups[?retentionInDays==`null`].logGroupName' \
  --output text | tr '\t' '\n' | while read LOG_GROUP; do

  # Skip CloudTrail logs — these need longer retention for SOC2
  if echo "$LOG_GROUP" | grep -qi "cloudtrail"; then
    echo "Skipping CloudTrail log group: $LOG_GROUP"
    aws logs put-retention-policy \
      --log-group-name "$LOG_GROUP" \
      --retention-in-days 365
    continue
  fi

  # Set 30-day retention on all other log groups
  echo "Setting 30-day retention on: $LOG_GROUP"
  aws logs put-retention-policy \
    --log-group-name "$LOG_GROUP" \
    --retention-in-days 30
done

echo "Done. Logs older than their retention period will be deleted automatically by CloudWatch."

ماہانہ بچت: اسٹوریج کی قیمت \(500~\)2,000۔ جمع کرنے کی لاگت کی بچت فوری طور پر شروع ہوجاتی ہے کیونکہ شور مچانے والی ڈیبگ لاگنگ کم ہوجاتی ہے۔ پرانے لاگز کی میعاد ختم ہونے کے بعد، 30 سے ​​90 دنوں تک اسٹوریج کی لاگت کی بچت بڑھ جاتی ہے۔

پیٹرن 8: یتیم ریسورس کلیکٹر

ہر انجینئر جو چھوڑ جاتا ہے ایک نشان چھوڑ جاتا ہے۔ ختم شدہ مثال کے ساتھ منسلک EBS والیوم۔ لچکدار IP تفویض کیا گیا لیکن منسلک نہیں ہے۔ Q3 میں فرسودہ خدمات سے پہلے بیلنس لوڈ کریں۔ تبدیل شدہ RDS مثال کا پچھلا سنیپ شاٹ۔ ان میں سے کوئی بھی جان بوجھ کر نہیں ہے، لیکن یہ سب پیسہ خرچ کرتے ہیں.

اس کا حل ہفتہ وار آڈٹ ہے۔ یہ دستی سروے نہیں ہے۔ یہ ایک خودکار اسکرپٹ ہے جو ہر اتوار کی رات چلتا ہے، یتیم وسائل تلاش کرتا ہے، اور حذف کرنے والے امیدواروں کی فہرست کے ساتھ ایک Slack پیغام بھیجتا ہے۔

یتیموں کو تلاش کریں:

# Unattached EBS volumes — you are paying for storage with nothing in it
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[*].{
    ID:VolumeId,
    Size:Size,
    Created:CreateTime,
    MonthlyCost:Size
  }' \
  --output table

# Unassociated Elastic IPs — $3.60/month each when not attached to a running instance
aws ec2 describe-addresses \
  --query 'Addresses[?AssociationId==`null`].[PublicIp,AllocationId]' \
  --output table

# Old snapshots — created more than 90 days ago, no longer needed
aws ec2 describe-snapshots \
  --owner-ids self \
  --query "Snapshots[?StartTime<='$(date -d '90 days ago' --iso-8601=seconds)'].[SnapshotId,StartTime,VolumeSize]" \
  --output table

# Idle load balancers — active but routing zero traffic
aws elbv2 describe-load-balancers \
  --query 'LoadBalancers[*].{ARN:LoadBalancerArn,DNS:DNSName,State:State.Code}' \
  --output table

ہفتہ وار ریکاپ لیمبڈا:

# orphan_resource_reporter.py
# Runs every Sunday at 20:00 via EventBridge
# Reports orphaned resources to Slack — does NOT auto-delete
# Deletion requires a human decision. The Lambda surfaces the candidates.

import boto3
import json
import urllib.request
from datetime import datetime, timedelta, timezone

SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'

def get_orphaned_resources():
    """Collect all orphaned AWS resources and their estimated monthly costs."""
    ec2 = boto3.client('ec2')
    elbv2 = boto3.client('elbv2')
    report = {'total_monthly_waste': 0, 'resources': []}

    # Unattached EBS volumes ($0.08/GB/month for gp3)
    volumes = ec2.describe_volumes(
        Filters=[{'Name': 'status', 'Values': ['available']}]
    )['Volumes']
    for vol in volumes:
        monthly_cost = round(vol['Size'] * 0.08, 2)
        report['resources'].append({
            'type': 'Unattached EBS Volume',
            'id': vol['VolumeId'],
            'detail': f"{vol['Size']}GB {vol['VolumeType']}",
            'monthly_cost': monthly_cost
        })
        report['total_monthly_waste'] += monthly_cost

    # Unassociated Elastic IPs ($3.60/month each)
    addresses = ec2.describe_addresses()['Addresses']
    for addr in addresses:
        if 'AssociationId' not in addr:
            report['resources'].append({
                'type': 'Unassociated Elastic IP',
                'id': addr['AllocationId'],
                'detail': addr['PublicIp'],
                'monthly_cost': 3.60
            })
            report['total_monthly_waste'] += 3.60

    # Snapshots older than 90 days
    cutoff = (datetime.now(timezone.utc) - timedelta(days=90)).isoformat()
    snapshots = ec2.describe_snapshots(OwnerIds=['self'])['Snapshots']
    old_snapshots = [s for s in snapshots if s['StartTime'].isoformat() < cutoff]
    for snap in old_snapshots:
        monthly_cost = round(snap.get('VolumeSize', 0) * 0.05, 2)
        report['resources'].append({
            'type': 'Old Snapshot (90+ days)',
            'id': snap['SnapshotId'],
            'detail': f"Created {snap['StartTime'].strftime('%Y-%m-%d')}",
            'monthly_cost': monthly_cost
        })
        report['total_monthly_waste'] += monthly_cost

    return report

def post_to_slack(report):
    """Send the orphaned resource report to Slack."""
    resource_lines="\n".join([
        f"• {r['type']} `{r['id']}` — {r['detail']} — *${r['monthly_cost']}/month*"
        for r in report['resources']
    ])

    message = {
        'text': (
            f":money_with_wings: *Weekly Orphaned Resource Report*\n\n"
            f"Found *{len(report['resources'])} orphaned resources* "
            f"costing *${report['total_monthly_waste']:.2f}/month*\n\n"
            f"{resource_lines}\n\n"
            f"Review and delete resources that are no longer needed."
        )
    }
    
    req = urllib.request.Request(
        SLACK_WEBHOOK_URL,
        data=json.dumps(message).encode(),
        headers={'Content-Type': 'application/json'}
    )
    urllib.request.urlopen(req)

def lambda_handler(event, context):
    report = get_orphaned_resources()
    post_to_slack(report)
    return {
        'resources_found': len(report['resources']),
        'monthly_waste': report['total_monthly_waste']
    }

ماہانہ بچت: \(500~\)2,000۔ ہر انجینئر جو چھوڑتا ہے عام طور پر اپنے پیچھے \(50–\)200 یتیم وسائل چھوڑ جاتا ہے۔ 30% سالانہ ٹرن اوور والے 30 افراد کی ٹیم کے لیے، یہ تیزی سے پیچیدہ ہو جاتا ہے۔

کل بچت کا خلاصہ

پیٹرن ماہانہ بچت ٹھیک کرنے کا وقت مشکل
1. نئی بھرتی کا تجربہ ٹیکس \(1,000~\)2,000 2 گھنٹے (لیمبڈا) درمیانی
2. بتدریج پھیلاؤ \(600~\)800 3 گھنٹے (منصوبہ بند) کم
3. NAT گیٹ وے ٹیکس \(2,000~\)8,000 30 منٹ کم
4. بچت کے منصوبے کا وقت \(5,000~\)15,000 ایک فیصلہ کم
5. AZs کے درمیان ڈیٹا کی منتقلی \(500~\)6,000 2 گھنٹے درمیانی
6. gp2 والیوم ٹریپ \(1,000~\)5,000 30 منٹ (اسکرپٹ) کم
7. لامحدود لاگ ٹریپ \(500~\)2,000 1 گھنٹہ (اسکرپٹ) کم
8. یتیم وسائل \(500~\)2,000 2 گھنٹے (لیمبڈا) کم
کل صلاحیت ₩(11,100–₩)40,800/ماہ

اس ہفتے کیا کرنا ہے۔

اس ہفتے تمام آٹھ کو ٹھیک نہ کریں۔ فی انجینئرنگ گھنٹہ ROI کی بنیاد پر ترجیح دیں:

دن 1 (30 منٹ): پیٹرن 3 - NAT گیٹ وے اینڈ پوائنٹ۔ اس گائیڈ میں اصلاحات میں سے، اس کا فی منٹ سب سے زیادہ ROI ہے۔ ایک کمانڈ کے ساتھ ایک S3 اینڈ پوائنٹ بنایا گیا ہے۔ مکمل

دن 2 (30 منٹ): پیٹرن 6 — gp2 سے gp3 میں منتقلی۔ اسکرپٹ چلائیں۔ آؤٹ پٹ چیک کریں: مکمل۔

دن 3 (1 گھنٹہ): پیٹرن 7 - لاگ برقرار رکھنے کی پالیسی۔ بلک ریٹینشن اسکرپٹ چلائیں۔ مکمل

دن 4 (2 گھنٹے): پیٹرن 1 اور 8 - دونوں لیمبڈا کو تعینات کریں۔ یہ خود بخود یہاں سے چلے گا۔

اگلا سپرنٹ: پیٹرن 2 (اسٹیجنگ شیڈول)، پیٹرن 5 (ٹوپیولوجی-آویئر روٹنگ)، اور پیٹرن 4 (پہلے ایک اسکیل سائیکل چلائیں، پھر بچت کے منصوبوں کا جائزہ لیں)۔

ہر ترمیم کے بعد Cost Explorer کھولیں۔ اس گائیڈ کے شروع میں بیس لائن اسکرین شاٹ سے اس کا موازنہ کریں۔ لائن نیچے جانا شروع ہونا چاہئے۔

وسائل

ایوبامی اڈیجومو سینئر پلیٹ فارم انجینئر اور FinOps ماہر۔ اس نے 30 سے ​​زیادہ سیریز A کمپنیوں کے لیے AWS انفراسٹرکچر کا آڈٹ کیا ہے اور FinOps فاؤنڈیشن اثاثہ لائبریری میں عملی ٹولز کا تعاون کیا ہے۔

اوپر تک سکرول کریں۔