Hands-on Lab · 5 of 9

Lab 5: DevOps, Automation & IaC

Is lab se console pe click karke infrastructure banana band ho jaata hai, aur sab kuch code se hone lagta hai. Pehle tum CloudFormation mein parameters, conditions aur outputs wala template likhoge, change sets se surakshit updates karoge, aur drift pakadna seekhoge. Phir CDK (Python) mein loops ki madad se infrastructure banaoge. Uske baad ek asli CI/CD pipeline banaoge jo GitHub pe push hote hi tests chalaye, Docker image banaye, use ECR mein daale aur ECS pe rolling deploy kare. Tum CodeDeploy se ek canary release karoge jo alarm bajne pe apne aap rollback ho jaata hai, aur ant mein EventBridge se services ko events ke through dheele taur pe jodoge.

⏱ 5–6 hours
📶 Intermediate
✅ Prereq: Labs 1–2 complete, GitHub account, Node.js 20+
💰 Cost: ~$0.10–0.30 (ECS task, CodeBuild minutes)
🏢 Account: Either (GitHub connection may be blocked in some company sandboxes)
0 / 0 checks done

0 Setup

Terminal aur prerequisites
export AWS_DEFAULT_REGION=us-east-1
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
mkdir -p ~/deepdive/lab5 && cd ~/deepdive/lab5

node --version     # v20+ chahiye (CDK CLI ke liye). Nahi hai: brew install node
git --version

Part D ke liye tumhe Lab 2 ka ECS setup chahiye: ECR repository deepdive-app, cluster deepdive-cluster, aur chalti hui service deepdive-svc, jiske container ka naam web ho. Agar tumne yeh sab delete kar diya tha, toh Lab 2 ke steps F1 se F3 dobara kar lo; isme lagbhag 15 minute lagte hain.

Declarative aur imperative ka farak

Imperative tareeke mein, jaise ek CLI script mein, tum kadam-dar-kadam batate ho: "bucket banao, phir versioning chalu karo, phir tag lagao". Agar yeh script dobara chalao, toh "bucket already exists" jaisa error aata hai. Declarative tareeke mein, jaise CloudFormation, CDK ya Terraform mein, tum sirf yeh batate ho ki "mujhe aisa bucket chahiye". Tool khud maujooda halat se compare karke sirf zaroori badlaav karta hai, aur agar tum ise dobara chalao toh kuch nahi badalta. Is guarantee ko idempotent hona kehte hain. Isi wajah se infrastructure ko Git mein review kiya ja sakta hai, har environment bilkul ek jaisa banta hai, aur ek command se sab kuch delete ho jaata hai.

A CloudFormation: template anatomy, stack create

A1
Template likho — Parameters, Conditions, Resources, Outputs
How

Neeche wala template stack.yaml naam ki file mein save karo. Yeh ek versioned S3 bucket aur alerts ke liye ek SNS topic banata hai:

AWSTemplateFormatVersion: "2010-09-09"
Description: DEEPDIVE Lab 5 - versioned data bucket + alerts topic

Parameters:
  EnvName:
    Type: String
    AllowedValues: [dev, prod]
    Default: dev
    Description: Environment name
  AlertEmail:
    Type: String
    Description: Email address for alert notifications

Conditions:
  IsProd: !Equals [!Ref EnvName, prod]

Resources:
  DataBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "deepdive-${EnvName}-${AWS::AccountId}-cfn"
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration: !If
        - IsProd
        - Rules:
            - Id: expire-old-versions
              Status: Enabled
              NoncurrentVersionExpiration:
                NoncurrentDays: 90
        - !Ref AWS::NoValue
      Tags:
        - Key: Project
          Value: deepdive

  AlertsTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub "deepdive-${EnvName}-alerts"
      Subscription:
        - Protocol: email
          Endpoint: !Ref AlertEmail

Outputs:
  BucketName:
    Value: !Ref DataBucket
  BucketArn:
    Value: !GetAtt DataBucket.Arn
  TopicArn:
    Value: !Ref AlertsTopic
Template ka har section kya karta hai
  • Parameters se ek hi template alag-alag inputs (jaise dev ya prod) ke saath chalaya ja sakta hai. Conditions se input ke hisaab se kisi resource ya property ko chalu ya band kiya ja sakta hai.
  • Resources hi ek aisa section hai jo zaroori hai. Har resource ka template ke andar ek logical ID hota hai (jaise DataBucket), aur AWS mein bane asli resource ke naam ko physical ID kehte hain.
  • Intrinsic functions template ke andar values nikaalne ke kaam aate hain. !Ref kisi parameter ki value ya resource ka mukhya ID deta hai (bucket ke liye uska naam, SNS topic ke liye uska ARN). !GetAtt resource ka koi khaas attribute deta hai, jaise .Arn. !Sub string ke andar variables bharta hai, aur !If aur !Equals conditions ke liye hote hain. AWS::AccountId aur AWS::Region jaise "pseudo parameters" AWS khud deta hai, aur AWS::NoValue ka matlab hai "is property ko hata do".
  • Outputs stack ke nateeje batate hain, jinhe doosre stacks Export aur !ImportValue se use kar sakte hain.

Template mein koi galti to nahi, yeh check karne ke liye use validate karo:

aws cloudformation validate-template --template-body file://stack.yaml
Acceptance criteria (verify)
  • validate-template ne Parameters ki list lautayi aur koi error nahi aaya.
  • Tum bata sakte ho ki !Ref DataBucket aur !GetAtt DataBucket.Arn mein kya value aayegi.
A2
Stack deploy karo aur events padho

Stack banao, uske poora hone ka intezaar karo, aur phir uske events aur outputs dekho. you@example.com ki jagah apna email daalna:

aws cloudformation create-stack --stack-name deepdive-lab5 \
  --template-body file://stack.yaml \
  --parameters ParameterKey=EnvName,ParameterValue=dev ParameterKey=AlertEmail,ParameterValue=you@example.com \
  --tags Key=Project,Value=deepdive

aws cloudformation wait stack-create-complete --stack-name deepdive-lab5

aws cloudformation describe-stack-events --stack-name deepdive-lab5 \
  --query 'StackEvents[].[Timestamp,LogicalResourceId,ResourceStatus]' --output table

aws cloudformation describe-stacks --stack-name deepdive-lab5 \
  --query 'Stacks[0].Outputs' --output table
🖱 Console se bhi ho sakta hai
  1. CloudFormation → Stacks → Create stack → With new resources — Upload a template file se stack.yaml chuno, Next dabao, stack naam deepdive-lab5 aur parameters (EnvName, AlertEmail) bharo, Next-Next dabate hue Submit karo. Events tab live update hota hai.

Tumhare email pe SNS ka confirmation link aayega; use confirm kar do. Phir CloudFormation console mein stack kholo aur teen tabs dekho: Resources tab, jahan logical ID aur physical ID ka milaan dikhta hai; Template tab; aur Events tab.

Acceptance criteria (verify)
  • Stack CREATE_COMPLETE hai aur Outputs mein BucketName, BucketArn aur TopicArn dikh rahe hain.
  • Tumne events neeche se upar padhe aur har resource ke liye CREATE_IN_PROGRESS se CREATE_COMPLETE tak ka safar dekha.

B CloudFormation: change sets, drift, delete failures

B1
Change set: pehle dekho kya badlega, phir apply karo
Why

Production stack pe seedha update chala dena andhere mein teer chalane jaisa hai. Change set pehle hi dikha deta hai ki kaunsa resource jodha (Add), badla (Modify) ya hataya (Remove) jaayega, aur kaunsa Replace hoga. Replace ka matlab hai ki purana resource delete hoga aur naya banega, jo database ya bucket ke liye data khone ka khatra hai.

How

stack.yaml ke Resources section mein neeche wala naya resource jodo:

  WorkQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub "deepdive-${EnvName}-work"
      MessageRetentionPeriod: 345600      # 4 din

Aur Outputs section mein yeh output jodo:

  QueueUrl:
    Value: !Ref WorkQueue

Ab ek change set banao, dekho usme kya badlega, aur phir use execute karo:

aws cloudformation create-change-set --stack-name deepdive-lab5 --change-set-name add-queue \
  --template-body file://stack.yaml \
  --parameters ParameterKey=EnvName,UsePreviousValue=true ParameterKey=AlertEmail,UsePreviousValue=true

aws cloudformation wait change-set-create-complete --stack-name deepdive-lab5 --change-set-name add-queue
aws cloudformation describe-change-set --stack-name deepdive-lab5 --change-set-name add-queue \
  --query 'Changes[].ResourceChange.[Action,LogicalResourceId,ResourceType,Replacement]' --output table

aws cloudformation execute-change-set --stack-name deepdive-lab5 --change-set-name add-queue
aws cloudformation wait stack-update-complete --stack-name deepdive-lab5
🖱 Console se bhi ho sakta hai
  1. Stack kholo, Stack actions → Create change set for current stack, updated stack.yaml upload karo, naam add-queue rakho. Change set kholne pe ek table mein Add/Modify/Remove aur Replacement column dikhta hai — yahi jaankari console mein bhi milti hai.
  2. Review karke Execute change set dabao.

Ab ek experiment karo, lekin use execute mat karna. Template mein BucketName badal do (jaise end mein -v2 jod do), ek naya change set banao aur use describe karo. Tumhe Replacement: True dikhega, jiska matlab hai ki purana bucket delete ho jaayega. Is change set ko aws cloudformation delete-change-set --stack-name deepdive-lab5 --change-set-name <naam> se hata do aur template ko wapas theek kar do.

Acceptance criteria (verify)
  • Change set mein sirf Add WorkQueue dikha, aur execute karne ke baad queue ban gayi.
  • BucketName badalne pe tumne Replacement: True dekha aur samjha ki yeh khatarnaak kyun hai.
B2
Drift detection: kisi ne console se chhed-chhaad ki
Why

Infrastructure as Code tabhi kaam karta hai jab log console se haath se badlaav na karein. Drift detection batata hai ki asli resource template se kahan alag ho gaya hai.

How
  1. S3 console mein deepdive-dev-...-cfn bucket kholo, Properties mein Bucket Versioning ko Edit karke Suspend kar do.

Ab CloudFormation se drift detect karwao aur dekho ki kya badla hua mila:

DRIFT_ID=$(aws cloudformation detect-stack-drift --stack-name deepdive-lab5 --query StackDriftDetectionId --output text)
sleep 15
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id $DRIFT_ID \
  --query '[DetectionStatus,StackDriftStatus]'
aws cloudformation describe-stack-resource-drifts --stack-name deepdive-lab5 \
  --stack-resource-drift-status-filters MODIFIED \
  --query 'StackResourceDrifts[].PropertyDifferences[].[PropertyPath,ExpectedValue,ActualValue]' --output table

Isko theek karne ke liye versioning ko wapas Enable karo aur drift detection dobara chalao; ab status IN_SYNC aana chahiye. Terraform mein yahi kaam "plan" command karti hai.

Acceptance criteria (verify)
  • Stack DRIFTED dikha, aur property /VersioningConfiguration/Status ki expected value Enabled aur actual value Suspended thi.
  • Theek karne ke baad status IN_SYNC ho gaya.
B3
Delete fail hoga — kyun, aur DeletionPolicy

Bucket mein ek file daalo aur phir stack delete karne ki koshish karo:

echo "data" > d.txt
BUCKET=$(aws cloudformation describe-stacks --stack-name deepdive-lab5 --query "Stacks[0].Outputs[?OutputKey=='BucketName'].OutputValue" --output text)
aws s3 cp d.txt s3://$BUCKET/d.txt
🖱 Delete karna console se bhi ho sakta hai
  1. Stack select karo, Delete dabao. Fail hone pe Events tab mein DELETE_FAILED reason dikhega.
aws cloudformation delete-stack --stack-name deepdive-lab5
aws cloudformation wait stack-delete-complete --stack-name deepdive-lab5   # fail hoga
aws cloudformation describe-stack-events --stack-name deepdive-lab5 \
  --query "StackEvents[?ResourceStatus=='DELETE_FAILED'].[LogicalResourceId,ResourceStatusReason]" --output table

Fail hone ki wajah hogi "The bucket you tried to delete is not empty". CloudFormation kabhi bhi chupchaap tumhara data delete nahi karta. Isko theek karne ke liye S3 console mein bucket kholo aur Empty dabao (bucket versioned hai, isliye yeh saare versions bhi hata dega), aur phir delete-stack dobara chalao.

DeletionPolicy aur UpdateReplacePolicy

Production ke databases aur buckets pe aam taur pe DeletionPolicy: Retain lagaya jaata hai, jisse stack delete hone pe bhi resource bacha rehta hai. RDS aur EBS jaise resources pe Snapshot bhi lagaya ja sakta hai, jo delete se pehle ek aakhri snapshot le leta hai. Isse agar galti se delete-stack chal jaaye, tab bhi data surakshit rehta hai. Stack policies aur termination protection bhi isi maqsad se hote hain.

Acceptance criteria (verify)
  • Tumne DELETE_FAILED ki wajah padhi, aur bucket khaali karne ke baad stack delete ho gaya.

C CDK (Python): bootstrap, synth, diff, deploy

C1
CDK install + project + bootstrap

CDK ka command-line tool install karo, ek naya Python project banao, aur apne account aur region ko CDK ke liye taiyaar (bootstrap) karo:

npm install -g aws-cdk
cdk --version

mkdir -p ~/deepdive/lab5/cdk-lab && cd ~/deepdive/lab5/cdk-lab
cdk init app --language python
source .venv/bin/activate
pip install -r requirements.txt

# Account+region mein ek baar: CDK ka staging bucket, ECR repo aur deploy roles banata hai
cdk bootstrap aws://$ACCOUNT_ID/us-east-1

Bootstrap kiye bina cdk deploy "This stack uses assets, so the toolkit stack must be deployed" ya SSM parameter /cdk-bootstrap/... not found jaisa error deta hai. CloudFormation console mein CDKToolkit naam ka stack dekho; isse samajh aata hai ki CDK bhi andar se CloudFormation hi use karta hai.

Acceptance criteria (verify)
  • CDKToolkit stack CREATE_COMPLETE hai.
  • Project mein app.py aur cdk_lab/cdk_lab_stack.py files ban gayi hain.
C2
Loop se 3 buckets + Lambda + S3 trigger — 30 lines mein
How

cdk_lab/cdk_lab_stack.py file ka poora content neeche wale code se badal do. Yeh code ek loop se teen buckets banata hai, ek Lambda function banata hai, "raw" bucket mein file aane pe us function ko chalata hai, aur function ko "processed" bucket mein likhne ki permission deta hai:

from aws_cdk import (
    CfnOutput,
    Duration,
    RemovalPolicy,
    Stack,
    aws_lambda as _lambda,
    aws_s3 as s3,
    aws_s3_notifications as s3n,
)
from constructs import Construct


class CdkLabStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        buckets = {}
        for stage in ["raw", "processed", "archive"]:          # YAML mein yeh loop nahi likh sakte
            buckets[stage] = s3.Bucket(
                self, f"{stage.capitalize()}Bucket",
                versioned=True,
                encryption=s3.BucketEncryption.S3_MANAGED,
                block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
                enforce_ssl=True,
                removal_policy=RemovalPolicy.DESTROY,          # lab ke liye; prod mein RETAIN
                auto_delete_objects=True,
            )

        processor = _lambda.Function(
            self, "Processor",
            runtime=_lambda.Runtime.PYTHON_3_12,
            handler="index.handler",
            code=_lambda.Code.from_inline(
                "def handler(event, context):\n"
                "    print(event['Records'][0]['s3']['object']['key'])\n"
                "    return 'ok'\n"
            ),
            timeout=Duration.seconds(10),
        )

        buckets["raw"].add_event_notification(
            s3.EventType.OBJECT_CREATED, s3n.LambdaDestination(processor)
        )
        buckets["processed"].grant_write(processor)            # least-privilege IAM policy khud banegi

        for stage, bucket in buckets.items():
            CfnOutput(self, f"{stage}BucketName", value=bucket.bucket_name)

Ab dekho ki CDK isse kitna CloudFormation banata hai, kya badlega, aur phir deploy karo:

cdk synth | wc -l          # ~30 lines Python → kitni lines CloudFormation?
cdk synth | grep -A3 "AWS::IAM::Policy" | head -20
cdk diff
cdk deploy                 # IAM changes dikhayega → y
Constructs ke teen levels

CDK mein building blocks ko constructs kehte hain, aur inke teen level hote hain. L1 constructs (jaise CfnBucket) seedhe CloudFormation resources hain, ek ke badle ek. L2 constructs (jaise s3.Bucket) samajhdaar defaults ke saath aate hain aur unme grant_write aur add_event_notification jaise helper methods hote hain; tumne yahi use kiye. L3 constructs, jinhe patterns bhi kehte hain, ek line mein poora architecture bana dete hain, jaise ApplicationLoadBalancedFargateService, jo ALB, ECS, Fargate aur security groups ek saath banata hai. Dhyan do ki grant_write ne tumhare liye exact bucket ARN wali IAM policy khud likh di; CDK ka "behtar developer experience" isi ko kehte hain.

Acceptance criteria (verify)
  • cdk deploy poora hua aur output mein teeno buckets ke naam aaye.
  • raw bucket mein file upload karne pe Lambda ke CloudWatch logs mein file ki key print hui.
  • Tumne note kiya ki cdk synth ka CloudFormation output kitni lines ka tha.
C3
Change karo, diff dekho, destroy karo

Lambda function mein memory_size=256, jodo aur cdk diff chalao. Diff mein sirf MemorySize property ka badlaav dikhega. Phir cdk deploy chalao. Uske baad poora stack hata do:

cdk destroy          # auto_delete_objects ki wajah se buckets khaali karke delete honge
deactivate && cd ~/deepdive/lab5
Acceptance criteria (verify)
  • Diff mein sirf ek property ka badlaav dikha.
  • cdk destroy ke baad CloudFormation mein CdkLabStack delete ho gaya. CDKToolkit stack ko rehne do.

D CI/CD: CodePipeline + CodeBuild → ECR → ECS

Is part mein tum neeche diya gaya pipeline banaoge. Jab bhi tum GitHub pe code push karoge, pipeline apne aap code laayegi, tests chalayegi, Docker image banake ECR mein daalegi, aur ECS service ko naye version pe update kar degi:

git push ──► CodePipeline ├─ Source : GitHub (CodeConnections) ├─ Build : CodeBuild ── pytest ── docker build ── push ECR ── imagedefinitions.json └─ Deploy : Amazon ECS (deepdive-cluster / deepdive-svc) ── rolling update
D1
GitHub repo taiyar karo — app + tests + buildspec

Lab 2 wala app copy karo, uske liye tests likho, aur ek buildspec.yml banao jo CodeBuild ko batati hai ki kya-kya karna hai:

mkdir -p ~/deepdive/deepdive-cicd && cd ~/deepdive/deepdive-cicd
cp ~/deepdive/app/app.py ~/deepdive/app/requirements.txt ~/deepdive/app/Dockerfile ~/deepdive/app/.dockerignore .

cat > test_app.py <<'EOF'
from app import app


def test_home_returns_greeting():
    resp = app.test_client().get("/")
    assert resp.status_code == 200
    assert resp.get_json()["message"].startswith("Hello")


def test_health():
    assert app.test_client().get("/health").status_code == 200
EOF

cat > buildspec.yml <<'EOF'
version: 0.2

env:
  variables:
    REPO_NAME: deepdive-app
    CONTAINER_NAME: web

phases:
  install:
    commands:
      - python3 -m pip install -r requirements.txt pytest
  pre_build:
    commands:
      - echo "== Unit tests =="
      - python3 -m pytest -q
      - ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
      - REGISTRY=$ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - REPO_URI=$REGISTRY/$REPO_NAME
      - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - aws ecr get-login-password | docker login --username AWS --password-stdin $REGISTRY
  build:
    commands:
      - echo "== Docker build $IMAGE_TAG =="
      - docker build -t $REPO_URI:$IMAGE_TAG -t $REPO_URI:latest .
  post_build:
    commands:
      - docker push $REPO_URI:$IMAGE_TAG
      - docker push $REPO_URI:latest
      - printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $REPO_URI:$IMAGE_TAG > imagedefinitions.json
      - cat imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json
EOF

git init -b main && git add . && git commit -m "DEEPDIVE app with tests and buildspec"

Ab GitHub pe deepdive-cicd naam ki ek nayi aur bilkul khaali repository banao (README mat jodna), aur phir apna code usme push karo:

git remote add origin https://github.com/<your-username>/deepdive-cicd.git
git push -u origin main
buildspec ki zaroori baatein
  • Image ka tag git commit ka chhota SHA rakha gaya hai, jisse har deploy ka pata chal sakta hai, jaise "production mein abhi kaunsa commit chal raha hai?". Sirf latest tag ke saath deploy karna ek buri aadat maani jaati hai.
  • Tests pre_build phase mein chalte hain. Agar tests fail hue, toh image banti hi nahi aur deploy bhi nahi hota.
  • imagedefinitions.json file ECS ke deploy step ko batati hai ki container web ki nayi image kaunsi hai. Isme likha naam task definition ke container ke naam se match hona chahiye.
  • CodeBuild pe image x86 machine pe banti hai, isliye Lab 2 wali Apple Silicon ki problem yahan nahi aati.
Acceptance criteria (verify)
  • Local machine pe pip install -r requirements.txt pytest && python3 -m pytest -q chalane pe "2 passed" aaya.
  • Code GitHub pe push ho gaya.
D2
Pipeline banao (Source → Build → Deploy)
How
  1. CodePipeline console mein Create pipeline dabao aur Build custom pipeline chuno. Naam deepdive-pipeline rakho, execution mode default rehne do, service role mein New service role chuno aur Next dabao.
  2. Source stage mein provider GitHub (via GitHub App) chuno aur Connect to GitHub dabao. Connection ka naam deepdive-github rakho, "Install a new app" chuno, GitHub pe sirf deepdive-cicd repository ko allow karo aur Connect dabao. Phir repository deepdive-cicd aur branch main chuno, push pe trigger rehne do aur Next dabao.
  3. Build stage mein Other build providers → AWS CodeBuild chuno aur Create project dabao. Ek popup khulega jisme:
    • Project ka naam deepdive-build rakho. Environment mein Managed image, EC2, Amazon Linux, Standard runtime aur latest amazonlinux-x86_64-standard image chuno.
    • Privileged pe tick zaroor lagao, kyunki Docker image banane ke liye yeh zaroori hai. Is tick ko bhool jaana sabse common galti hai.
    • Service role naya banne do, buildspec mein Use a buildspec file chuno, CloudWatch logs chalu rakho, aur Continue to CodePipeline dabao.
    Phir Next dabao.
  4. Test stage ko skip karo. Deploy stage mein provider Amazon ECS chuno, cluster deepdive-cluster, service deepdive-svc aur image definitions file imagedefinitions.json daalo, Next dabao aur Create pipeline karo.

Pipeline banate hi ek run shuru ho jaayega, aur uska Build stage fail hoga. Details mein CodeBuild ke logs kholo; wahan denied: User ... is not authorized to perform: ecr:InitiateLayerUpload (ya GetAuthorizationToken) jaisa error hoga. Yeh expected hai, kyunki CodeBuild ke naye role ko ECR mein image push karne ki permission nahi hai. Isko theek karo:

  1. IAM mein codebuild-deepdive-build-service-role role kholo, Add permissions dabao aur AmazonEC2ContainerRegistryPowerUser policy attach karo.
  2. Pipeline mein Build stage pe Retry dabao, ya poori pipeline ke liye Release change dabao.
Acceptance criteria (verify)
  • Build ke logs mein "2 passed", docker push aur imagedefinitions.json dikhe.
  • Deploy stage Succeeded hua, aur ECS service ke Deployments tab mein task definition ka naya revision dikha.
  • ECR mein commit-SHA wale tag ki image aa gayi.
D3
Code change → push → apne aap production

Ab app ka message badlo, tests chalao aur code push karo. Iske baad tumhe kuch nahi karna; pipeline khud sab kar degi:

cd ~/deepdive/deepdive-cicd
sed -i.bak 's/Hello from DEEPDIVE/Hello from DEEPDIVE (deployed by pipeline)/' app.py && rm app.py.bak
python3 -m pytest -q
git commit -am "Update greeting" && git push

CodePipeline mein naya execution chalta hua dekho. Deploy stage poora hone ke baad ECS service ke Tasks tab mein naye task ka public IP lo aur curl http://IP:5000 chalao. Har deploy pe public IP badal jaata hai, isliye asli setup mein service ke aage ek ALB lagaya jaata hai, jaisa Capstone 3 mein hai.

Acceptance criteria (verify)
  • Push ke 5–8 minute ke andar naya message live ho gaya.
  • Pipeline ki history mein har execution ka commit ID dikh raha hai.

E Deployment strategies + CodeDeploy (canary + auto-rollback hands-on)

Naya version kaise deploy karein: risk aur speed ka santulan
StrategyKaise hoti haiRollbackAWS mein kahan
RollingTasks ya instances ko thode-thode karke naye version pe laaya jaata haiDobara rolling karni padti hai, jo dheemi haiECS ka default tareeka (minimumHealthyPercent aur maximumPercent se control); tumne Part D mein yahi kiya
Blue/GreenPoora naya environment (green) khada karke test kiya jaata hai, aur phir traffic ek jhatke mein us pe switch hota haiTraffic wapas blue pe, seconds meinCodeDeploy ke saath ALB ke do target groups; ECS mein ab built-in blue/green option bhi hai
CanaryPehle 10% traffic naye version pe bheja jaata hai, aur sab theek rahe toh 100%Sirf woh 10% wapas lena padta haiCodeDeploy (Lambda ya ECS) ke configs jaise Canary10Percent5Minutes, ya ALB ke weighted target groups
LinearHar kuch minute mein traffic ka kuch pratishat badhaya jaata hai—CodeDeploy ka Linear10PercentEvery1Minute

CodeDeploy teen jagah deploy kar sakta hai. EC2 aur on-premises servers pe yeh ek agent aur appspec.yml file ke hooks (BeforeInstall, AfterInstall, ApplicationStart, ValidateService) se kaam karta hai. Lambda pe yeh alias ke traffic ko dheere-dheere shift karta hai. ECS pe yeh blue/green deployment karta hai. Agar deployment ke dauraan koi CloudWatch alarm bajta hai, toh CodeDeploy apne aap rollback kar deta hai. Jenkins se tulna karein toh Jenkinsfile ke stages CodePipeline ke stages jaise hain, Jenkins ka agent CodeBuild ke container jaisa hai, aur deploy plugin CodeDeploy jaisa hai.

E1
Lambda ke do versions + 'live' alias banao
Why

Lambda ka version code ki ek aisi copy hai jo kabhi nahi badalti, aur har version ka ek number hota hai (1, 2, 3 waghera). Alias (jaise live) ek pointer hai jo kisi version ki taraf point karta hai, aur traffic ko do versions ke beech baant bhi sakta hai. CodeDeploy isi alias ke weights ko dheere-dheere badal ke canary ya linear deployment karta hai. Clients hamesha deepdive-canary:live ko call karte hain, isliye unhe pata bhi nahi chalta ki peeche kaunsa version chal raha hai.

Neeche ke commands ek basic Lambda role banate hain, version 1 ke saath function banate hain, us pe live alias lagate hain, aur phir code badal ke version 2 publish karte hain:

mkdir -p ~/deepdive/lab5/canary && cd ~/deepdive/lab5/canary

cat > trust-lambda.json <<'EOF'
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}
EOF
LAMBDA_ROLE=$(aws iam create-role --role-name deepdive-lambda-basic \
  --assume-role-policy-document file://trust-lambda.json --query Role.Arn --output text)
aws iam attach-role-policy --role-name deepdive-lambda-basic \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
sleep 10

printf 'def lambda_handler(event, context):\n    return {"version": "v1"}\n' > canary.py
zip -q fn.zip canary.py
aws lambda create-function --function-name deepdive-canary --runtime python3.13 \
  --handler canary.lambda_handler --role $LAMBDA_ROLE --zip-file fileb://fn.zip
aws lambda wait function-active --function-name deepdive-canary
aws lambda publish-version --function-name deepdive-canary --query Version --output text      # 1
aws lambda create-alias --function-name deepdive-canary --name live --function-version 1

printf 'def lambda_handler(event, context):\n    return {"version": "v2"}\n' > canary.py
zip -q fn.zip canary.py
aws lambda update-function-code --function-name deepdive-canary --zip-file fileb://fn.zip >/dev/null
aws lambda wait function-updated --function-name deepdive-canary
aws lambda publish-version --function-name deepdive-canary --query Version --output text      # 2
🖱 Version/alias console se bhi bante hain
  1. Function kholo, Actions → Publish new version se version number milta hai.
  2. Aliases tab → Create alias, naam live, version chuno, Save karo. Baad mein isi alias ko edit karke "Additional version" jod ke weight se traffic split bhi console se ho sakta hai — CodeDeploy isi field ko automate karta hai.
Acceptance criteria (verify)
  • Versions 1 aur 2 ban gaye, aur live alias version 1 ki taraf point kar raha hai.
E2
CodeDeploy canary: 10% traffic 5 minute, phir 100%

Ab CodeDeploy ke liye ek role, ek application aur ek deployment group banao, jiska config pehle 10% traffic ko 5 minute ke liye naye version pe bhejta hai. Phir ek chhota helper function deploy banao jo AppSpec banakar deployment shuru karta hai, aur version 1 se 2 ka deployment chalao:

cat > trust-cd.json <<'EOF'
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"codedeploy.amazonaws.com"},"Action":"sts:AssumeRole"}]}
EOF
CD_ROLE=$(aws iam create-role --role-name deepdive-codedeploy-role \
  --assume-role-policy-document file://trust-cd.json --query Role.Arn --output text)
aws iam attach-role-policy --role-name deepdive-codedeploy-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda
sleep 10

aws deploy create-application --application-name deepdive-lambda-app --compute-platform Lambda
aws deploy create-deployment-group --application-name deepdive-lambda-app \
  --deployment-group-name live --service-role-arn $CD_ROLE \
  --deployment-config-name CodeDeployDefault.LambdaCanary10Percent5Minutes \
  --deployment-style deploymentType=BLUE_GREEN,deploymentOption=WITH_TRAFFIC_CONTROL

# AppSpec: alias 'live' ko version FROM se TO pe le jao
deploy() {
  python3 - "$1" "$2" > revision.json <<'PYEOF'
import json, sys
appspec = {"version": 0.0, "Resources": [{"deepdive-canary": {
    "Type": "AWS::Lambda::Function",
    "Properties": {"Name": "deepdive-canary", "Alias": "live",
                   "CurrentVersion": sys.argv[1], "TargetVersion": sys.argv[2]}}}]}
print(json.dumps({"revisionType": "AppSpecContent",
                  "appSpecContent": {"content": json.dumps(appspec)}}))
PYEOF
  aws deploy create-deployment --application-name deepdive-lambda-app \
    --deployment-group-name live --revision file://revision.json --query deploymentId --output text
}
DEP=$(deploy 1 2); echo $DEP

Agle paanch minute tak function ko baar-baar call karke dekho ki traffic kaise baanta ja raha hai:

for i in $(seq 1 30); do
  aws lambda invoke --function-name deepdive-canary:live /tmp/o.json >/dev/null && cat /tmp/o.json; echo
done | sort | uniq -c

aws lambda get-alias --function-name deepdive-canary --name live \
  --query '[FunctionVersion,RoutingConfig]'
aws deploy get-deployment --deployment-id $DEP --query 'deploymentInfo.[status,deploymentConfigName]'

Canary ke paanch minute ke dauraan lagbhag 27 jawab v1 ke aur 3 jawab v2 ke aayenge, aur alias ke RoutingConfig mein {"2": 0.1} dikhega. Paanch minute baad deployment Succeeded ho jaayega aur 100% traffic v2 pe chala jaayega. CodeDeploy console mein deployment kholke traffic shifting ki progress bar bhi dekho.

Acceptance criteria (verify)
  • Canary ke dauraan lagbhag 10% jawab v2 ke aaye, aur alias pe 0.1 ka weight dikha.
  • Deployment Succeeded hua aur ab saare jawab v2 ke hain.
E3
Buggy release → alarm → automatic rollback

Ab ek jaan-boojh ke toota hua version 3 banao, Lambda errors pe ek alarm lagao, deployment group ko us alarm se jodo aur automatic rollback chalu karo. Phir version 2 se 3 ka deployment shuru karo aur function ko baar-baar call karke errors paida karo:

printf 'def lambda_handler(event, context):\n    raise Exception("v3 bug!")\n' > canary.py
zip -q fn.zip canary.py
aws lambda update-function-code --function-name deepdive-canary --zip-file fileb://fn.zip >/dev/null
aws lambda wait function-updated --function-name deepdive-canary
aws lambda publish-version --function-name deepdive-canary --query Version --output text      # 3

aws cloudwatch put-metric-alarm --alarm-name deepdive-canary-errors \
  --namespace AWS/Lambda --metric-name Errors \
  --dimensions Name=FunctionName,Value=deepdive-canary Name=Resource,Value=deepdive-canary:live \
  --statistic Sum --period 60 --evaluation-periods 1 --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold --treat-missing-data notBreaching

aws deploy update-deployment-group --application-name deepdive-lambda-app \
  --current-deployment-group-name live \
  --alarm-configuration 'enabled=true,alarms=[{name=deepdive-canary-errors}]' \
  --auto-rollback-configuration 'enabled=true,events=[DEPLOYMENT_FAILURE,DEPLOYMENT_STOP_ON_ALARM]'

DEP=$(deploy 2 3); echo $DEP
# 10% traffic ab v3 pe — errors generate karo:
for i in $(seq 1 60); do aws lambda invoke --function-name deepdive-canary:live /tmp/o.json >/dev/null; done

1–3 minute ke andar alarm ALARM state mein chala jaayega, CodeDeploy deployment ko Stop kar dega aur use rollback kar dega. get-alias se dekho; alias wapas version 2 pe hoga aur koi routing weight nahi bachega. Poore samay mein sirf lagbhag 10% requests ne bug dekha, aur woh bhi kuch hi minute ke liye. Canary release ka poora fayda yahi hai.

aws deploy get-deployment --deployment-id $DEP --query 'deploymentInfo.[status,rollbackInfo.rollbackMessage]'
aws lambda get-alias --function-name deepdive-canary --name live --query '[FunctionVersion,RoutingConfig]'

Blue/green (all-at-once) bhi try karo: deployment group ka config badal ke CodeDeployDefault.LambdaAllAtOnce kar do aur deploy 2 1 chalao. Is baar alias ek hi jhatke mein switch hoga, aur rollback karne ka matlab hai alias ko wapas purane version pe kar dena. ECS pe yahi pattern ALB ke do target groups (blue aur green) aur ek test listener ke saath kiya jaata hai.

Acceptance criteria (verify)
  • Deployment ka status Stopped ya Failed hai aur uske saath rollback ka message hai.
  • Alias wapas version 2 pe aa gaya.

F EventBridge: rules, patterns, fan-out

Seedha trigger aur event bus ka farak

Lab 2 mein S3 ne Lambda ko seedha call kiya tha. Us tareeke mein ek bucket event sirf ek-do destinations tak jaata hai, aur uski configuration bucket pe hi hoti hai. EventBridge mein S3 sirf ek "Object Created" event event bus pe daal deta hai. Uske baad rules event patterns se match karke us event ko kitne bhi targets tak bhej sakte hain, jaise Lambda, SNS, SQS, Step Functions, ya doosra AWS account. Event bhejne wale (producer) ko yeh pata hi nahi hota ki use kaun-kaun sun raha hai. Naya consumer jodne ke liye bas ek naya rule banana padta hai, aur S3 ki configuration ko chhuna bhi nahi padta. Ise loose coupling kehte hain.

F1
Bucket pe EventBridge notifications ON karo

S3 console mein Lab 2 wala deepdive-uploads-<ACCOUNT_ID> bucket kholo. Properties tab mein Amazon EventBridge section ke aage Edit dabao, use On karo aur Save karo.

CLI se karoge toh dhyan rakhna

aws s3api put-bucket-notification-configuration --notification-configuration '{"EventBridgeConfiguration":{}}' command bucket ki poori notification configuration ko badal deti hai, jisse Lab 2 wala Lambda trigger mit jaayega. Console ka toggle sirf EventBridge ko chalu karta hai aur baaki settings nahi chhedta. Agar yeh bucket tumhare paas nahi hai, toh aws s3 mb s3://deepdive-uploads-$ACCOUNT_ID se bana lo.

Acceptance criteria (verify)
  • Bucket ki Properties mein "Send notifications to Amazon EventBridge for all events in this bucket: On" dikh raha hai.
F2
EventBridge-format Lambda banao
Why

EventBridge se aane wale event ka format S3 ke seedhe trigger se alag hota hai. Usme event["Records"] nahi, balki event["detail"] hota hai. Isliye Lab 2 wala function yahan KeyError: 'Records' dekar fail ho jaata.

Lambda console mein Create function dabao, naam deepdive-eb-processor rakho, runtime Python 3.13 chuno, basic role rehne do, aur yeh code deploy karo:

import json


def lambda_handler(event, context):
    detail = event["detail"]
    print(json.dumps({
        "source": event["source"],             # aws.s3
        "detail_type": event["detail-type"],   # Object Created
        "bucket": detail["bucket"]["name"],
        "key": detail["object"]["key"],
        "size": detail["object"].get("size"),
        "time": event["time"],
    }))
    return {"ok": True}
Acceptance criteria (verify)
  • Function deploy ho gaya hai.
F3
Pattern likho aur bina AWS resource ke test karo

Ek event pattern likho jo sirf is bucket ke reports/ prefix wale uploads se match kare. Saath hi ek sample event banao, aur AWS ke test command se check karo ki pattern us event se match karta hai ya nahi. Isme koi asli resource nahi banta:

cd ~/deepdive/lab5
export UP_BUCKET=deepdive-uploads-$ACCOUNT_ID

cat > pattern.json <<EOF
{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "bucket": { "name": ["$UP_BUCKET"] },
    "object": { "key": [{ "prefix": "reports/" }] }
  }
}
EOF

cat > sample-event.json <<EOF
{
  "version": "0", "id": "11111111-2222-3333-4444-555555555555",
  "detail-type": "Object Created", "source": "aws.s3",
  "account": "$ACCOUNT_ID", "time": "2026-09-23T10:00:00Z", "region": "us-east-1",
  "resources": ["arn:aws:s3:::$UP_BUCKET"],
  "detail": { "version": "0", "bucket": { "name": "$UP_BUCKET" },
              "object": { "key": "reports/q3.csv", "size": 120 }, "reason": "PutObject" }
}
EOF

aws events test-event-pattern --event-pattern file://pattern.json --event file://sample-event.json
# {"Result": true}. Ab sample-event.json mein key ko "other/q3.csv" karke dobara → false

Event patterns ke kuch niyam yaad rakho. Kisi array mein di gayi values mein se koi bhi match ho jaaye toh kaafi hai (yaani OR, jaise ["a","b"]). Alag-alag fields sab match hone chahiye (yaani AND). Aur prefix, suffix, anything-but aur numeric jaise content filters se aur bareek matching ki ja sakti hai.

Acceptance criteria (verify)
  • reports/ wale event ke liye nateeja true aaya, aur other/ wale ke liye false.
F4
Rule + do targets (Lambda + SNS) — fan-out

Pehle ek SNS topic banao aur usme apna email subscribe karo; email aane pe subscription confirm kar dena:

TOPIC_ARN=$(aws sns create-topic --name deepdive-events --query TopicArn --output text)
aws sns subscribe --topic-arn $TOPIC_ARN --protocol email --notification-endpoint you@example.com
# email confirm karo
  1. EventBridge console mein Rules → Create rule kholo. Naam deepdive-s3-reports rakho, event bus default chuno, "Rule with an event pattern" chuno aur Next dabao.
  2. Event source mein AWS events chuno, creation method mein Custom pattern (JSON editor) chuno, pattern.json ka content paste karo aur Next dabao.
  3. Pehla target AWS service mein Lambda function chuno aur deepdive-eb-processor select karo. Add another target dabao, SNS topic chuno aur deepdive-events select karo. Next dabao aur Create karo.

Ab do files upload karo, ek pattern se match karne wali aur ek nahi, aur Lambda ke logs dekho:

echo "q3 numbers" > q3.csv
aws s3 cp q3.csv s3://$UP_BUCKET/reports/q3.csv     # Lambda log + email
aws s3 cp q3.csv s3://$UP_BUCKET/misc/q3.csv        # kuch nahi (pattern match nahi)
aws logs tail /aws/lambda/deepdive-eb-processor --since 5m --format short

Agar email nahi aaya, toh SNS topic ki access policy mein EventBridge ko publish karne ki permission chahiye. Console aksar yeh khud jod deta hai, lekin agar na jode, toh SNS mein deepdive-events topic kholo, Edit dabao aur Access policy mein yeh statement jodo:

{
  "Sid": "AllowEventBridgePublish",
  "Effect": "Allow",
  "Principal": { "Service": "events.amazonaws.com" },
  "Action": "sns:Publish",
  "Resource": "arn:aws:sns:us-east-1:<ACCOUNT_ID>:deepdive-events"
}

Rule ke Monitoring tab mein MatchedEvents, Invocations aur FailedInvocations metrics dekho. Real systems mein targets ke saath ek DLQ (SQS dead-letter queue) aur retry policy lagayi jaati hai, taaki koi fail hua event kho na jaaye.

EventBridge ke aur features (jaankari ke liye)

Scheduler cron ya rate ke schedule pe (jaise rate(5 minutes) ya cron(0 2 * * ? *)) Lambda function ya ECS task chala sakta hai, jisse alag cron server ki zaroorat khatam ho jaati hai. Archive aur replay se purane events ko dobara chalaya ja sakta hai, jaise kisi bug ko theek karne ke baad. Custom event buses pe tumhare apne apps apne events (jaise OrderPlaced) PutEvents se bhej sakte hain. Pipes kisi source (jaise SQS ya DynamoDB stream) se events lekar unhe filter karta hai, unme jaankari jodta hai, aur phir target tak bhejta hai.

Acceptance criteria (verify)
  • reports/ mein upload karne pe Lambda ka log aur email, dono aaye; yaani ek event do consumers tak pahuncha.
  • misc/ mein upload karne pe kuch nahi hua.
  • Rule ke Monitoring tab mein MatchedEvents ke graph mein ek point dikha.

G Break & Fix, Challenge

Break & Fix 1 — fail hota test production ko bachata hai

app.py mein message badal ke "Hi from DEEPDIVE" kar do, jabki test startswith("Hello") ki umeed karta hai, aur phir commit karke push karo. Pipeline ka Build stage Failed ho jaayega aur logs mein AssertionError dikhega. Deploy stage chala hi nahi, isliye production pe purana version hi chal raha hai. Message wapas Hello... karke dobara push karo. Isse CI ka asli kaam samajh aata hai: kharab code ko production tak pahunchne hi na dena.

Break & Fix 2 — Privileged mode off

CodeBuild mein deepdive-build project kholo, Edit karke Environment mein Privileged ka tick hata do, aur pipeline mein Release change dabao. Build is error ke saath fail hoga: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Tick wapas laga do.

Break & Fix 3 — CloudFormation rollback

stack.yaml mein MessageRetentionPeriod: 99999999 kar do (jabki iski zyada se zyada value 1209600 hai) aur stack create ya update karo. Stack UPDATE_ROLLBACK_COMPLETE ya ROLLBACK_COMPLETE state mein chala jaayega; Events tab mein iski wajah padho. Fail hone pe CloudFormation ne sab kuch pehle wali halat mein wapas kar diya, aur IaC ki suraksha yahi hai. Ek baat yaad rakho: jo naya stack ROLLBACK_COMPLETE mein chala jaata hai use update nahi kiya ja sakta; use delete karke dobara banana padta hai.

Challenge — no steps given

Teen kaam bina steps dekhe karo. Pehla, Lab 4 ka poora VPC (do public aur do private subnets, Internet Gateway, NAT aur route tables) CDK mein likho. Hint yeh hai ki ec2.Vpc(self, "Vpc", max_azs=2, nat_gateways=1) jaisa ek L2 construct yeh sab kar deta hai. cdk synth chala ke dekho ki kitne resources bane, aur jab tak cleanup ka samay na ho tab tak ise deploy mat karna. Doosra, apni pipeline mein Build aur Deploy ke beech ek manual approval stage jodo, jisme SNS email pe approve karne ka link aaye. Teesra, EventBridge Scheduler se deepdive-eb-processor ko har paanch minute mein chalao, aur phir use band kar do.

Explain it back (interview practice)
  1. Declarative IaC ka kya matlab hai, aur idempotent hona kyun zaroori hai?
  2. !Ref, !GetAtt aur !Sub mein kya farak hai?
  3. Change set kyun use karte hain? "Replacement: True" ka kya khatra hai?
  4. Drift kya hota hai, aur use kaise pakdoge?
  5. CDK aur CloudFormation ka aapas mein kya rishta hai? cdk bootstrap kya banata hai?
  6. Tumhari pipeline ka har stage kya karta hai? Image ka tag commit SHA kyun rakha gaya?
  7. Rolling, blue/green aur canary mein se kab kaunsa chunoge? Tumhare canary deployment mein rollback kisne aur kaise trigger kiya?
  8. S3 ke seedhe trigger aur EventBridge mein kya farak hai, aur kab kaunsa chunoge?
🧹 Cleanup — billing se bachne ke liye zaroor karo
  • Pipeline: CodePipeline deepdive-pipeline aur CodeBuild project deepdive-build delete karo. Chaaho toh Developer Tools ke Settings mein Connections se deepdive-github connection bhi delete kar sakte ho.
  • ECS: service deepdive-svc ka desired count 0 karke use delete karo, phir cluster delete karo. Task definitions ko deregister karna optional hai, kyunki unka koi charge nahi.
  • ECR: aws ecr delete-repository --repository-name deepdive-app --force. Agar tum Capstone 3 abhi karne wale ho, toh repository ko rehne do.
  • CloudFormation: confirm karo ki deepdive-lab5 delete ho gaya aur CdkLabStack destroy ho gaya. CDKToolkit ko rakh sakte ho kyunki uska kharcha bahut kam hai; delete karna ho toh pehle uska staging bucket khaali karna padega.
  • EventBridge: rule deepdive-s3-reports, SNS topic deepdive-events aur Lambda deepdive-eb-processor delete karo.
  • S3 aur logs: deepdive-uploads-... bucket ko khaali karke delete karo. Lab 2 wala Lambda deepdive-s3-logger bhi ab delete kar sakte ho. CloudWatch ke log groups /aws/lambda/deepdive-* aur /aws/codebuild/deepdive-build bhi delete karo.
  • CodeDeploy: aws deploy delete-application --application-name deepdive-lambda-app chalao, Lambda deepdive-canary aur alarm deepdive-canary-errors delete karo, aur role deepdive-codedeploy-role ki policies detach karke use delete karo. deepdive-lambda-basic role ko rakh lo, kyunki Lab 8 mein kaam aayega.
  • IAM: codebuild-deepdive-build-service-role aur AWSCodePipelineServiceRole-*-deepdive-pipeline roles bhi delete kar sakte ho.