DEV Community

Cover image for Deploy Code By Using AWS Continuous Integration And Continuous Delivery (CI/CD) Services | πŸ—οΈ Build A Complete CI/CD Pipeline

Deploy Code By Using AWS Continuous Integration And Continuous Delivery (CI/CD) Services | πŸ—οΈ Build A Complete CI/CD Pipeline

Exam Guide: Developer - Associate
πŸ—οΈ Domain 3: Deployment
πŸ“˜ Task 4: Deploy Code By Using AWS Continuous Integration And Continuous Delivery (CI/CD) Services

This task tests your ability to build and manage CI/CD pipelines using AWS developer tools. You need to understand how CodeCommit, CodeBuild, CodeDeploy, and CodePipeline work together, how to write buildspec and appspec files, how deployment strategies differ, and how to configure automatic rollbacks. Deployment strategies for Lambda and EC2, SAM deployment preferences, and pipeline orchestration.


πŸ“˜ Concepts

AWS CI/CD Pipeline Overview

The four AWS developer tools form a complete CI/CD pipeline:

Service Role Input Output
CodeCommit Source control Git push Source artifact
CodeBuild Build and test Source artifact Build artifact
CodeDeploy Deploy Build artifact Running application
CodePipeline Orchestration Trigger (push, schedule) Coordinated pipeline execution

How they connect:

CodeCommit (source) β†’ CodeBuild (build/test) β†’ CodeDeploy (deploy)
         ↑                                              |
         └──────── CodePipeline (orchestrates all) β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

πŸ’‘CodePipeline is the orchestrator. It doesn't build or deploy anything itself. It connects stages (source, build, test, deploy) and manages transitions between them. Each stage can use different providers (GitHub instead of CodeCommit, Jenkins instead of CodeBuild, etc.).

CodeCommit Fundamentals

Feature Details
What It Is Managed Git repository hosted in AWS
Authentication HTTPS (Git credentials or credential helper) or SSH (SSH keys)
Encryption Encrypted at rest (AWS managed keys) and in transit (HTTPS/SSH)
Triggers SNS notifications or Lambda functions on repository events
Cross-account Use IAM roles with AssumeRole for cross-account access
Branching Standard Git branching: main, develop, feature branches

πŸ’‘CodeCommit supports triggers for push events that can invoke Lambda functions or send SNS notifications. This is different from CodePipeline's source stage: triggers are repository-level events, while CodePipeline polls or uses CloudWatch Events to detect changes.

CodeBuild buildspec.yml Structure

The buildspec file tells CodeBuild what to do. It has four phases:

version: 0.2

env:
  variables:
    ENV_NAME: "production"
  parameter-store:
    DB_PASSWORD: "/myapp/db-password"
  secrets-manager:
    API_KEY: "myapp/api-key:API_KEY"

phases:
  install:
    runtime-versions:
      python: 3.13
    commands:
      - pip install -r requirements.txt

  pre_build:
    commands:
      - echo "Running tests..."
      - python -m pytest tests/ -v

  build:
    commands:
      - echo "Building..."
      - sam build

  post_build:
    commands:
      - echo "Packaging..."
      - sam package --s3-bucket my-bucket --output-template-file packaged.yaml

artifacts:
  files:
    - packaged.yaml
    - appspec.yml
  discard-paths: yes

cache:
  paths:
    - '/root/.cache/pip/**/*'

reports:
  test-reports:
    files:
      - "**/*.xml"
    base-directory: test-results
Enter fullscreen mode Exit fullscreen mode
Phase When It Runs Typical Use
install First Install dependencies, runtime versions
pre_build Before build Run tests, log in to ECR, lint code
build Main phase Compile code, run SAM build, create artifacts
post_build After build Package artifacts, push images, notifications
Section Purpose
env.variables Plain text environment variables
env.parameter-store Values pulled from SSM Parameter Store at build time
env.secrets-manager Values pulled from Secrets Manager at build time
artifacts Files to pass to the next pipeline stage
cache Paths to cache between builds (speeds up installs)
reports Test report files for CodeBuild report groups

πŸ’‘The buildspec file must be named buildspec.yml and placed in the root of your source directory (unless you override the name in the CodeBuild project settings).

The env section can pull secrets from Parameter Store and Secrets Manager. This is the secure way to use credentials in builds. Never hardcode secrets in the buildspec.

CodeDeploy appspec.yml Structure

The appspec file tells CodeDeploy how to deploy your application. The structure differs by compute platform:

For Lambda:

version: 0.0
Resources:
  - MyFunction:
      Type: AWS::Lambda::Function
      Properties:
        Name: my-function
        Alias: prod
        CurrentVersion: 1
        TargetVersion: 2
Hooks:
  - BeforeAllowTraffic: PreTrafficCheckFunction
  - AfterAllowTraffic: PostTrafficCheckFunction
Enter fullscreen mode Exit fullscreen mode

For EC2/On-Premises:

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html
permissions:
  - object: /var/www/html
    owner: www-data
    group: www-data
    mode: "755"
hooks:
  BeforeInstall:
    - location: scripts/before_install.sh
      timeout: 300
  AfterInstall:
    - location: scripts/after_install.sh
      timeout: 300
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
  ValidateService:
    - location: scripts/validate.sh
      timeout: 300
Enter fullscreen mode Exit fullscreen mode

CodeDeploy Lifecycle Hooks

Lambda Deployment Hooks:

Hook When It Runs Purpose
BeforeAllowTraffic Before traffic shifts to new version Run validation tests against the new version
AfterAllowTraffic After traffic shifts to new version Run integration tests, verify health

EC2 Deployment Hooks (in order):

Hook When It Runs Purpose
BeforeInstall Before files are copied Clean up old files, stop services
AfterInstall After files are copied Configure app, set permissions
ApplicationStart After AfterInstall Start services, warm up
ValidateService After ApplicationStart Health checks, smoke tests
BeforeBlockTraffic Before deregistering from ELB Graceful connection draining
AfterBlockTraffic After deregistering from ELB Run tasks while instance is out of service
BeforeAllowTraffic Before registering with ELB Final checks before receiving traffic
AfterAllowTraffic After registering with ELB Verify instance is healthy in ELB

πŸ’‘ For Lambda deployments, the hooks are Lambda functions themselves: they run your validation code and must return Succeeded or Failed to CodeDeploy.

For EC2, hooks are shell scripts that run on the instance.

If a hook fails (the deployment rolls back).

Deployment Strategies Comparison

Know each strategy of by heart:

Strategy How It Works Downtime Rollback Speed Risk Best For
AllAtOnce Deploy to all instances simultaneously Brief Redeploy previous version High: all instances affected Dev/test environments
Rolling Deploy in batches (one batch at a time) None (if batch size < total) Redeploy previous version Medium: one batch at a time EC2 fleets with ELB
Rolling with additional batch Adds new instances before removing old ones None Redeploy previous version Low: maintains full capacity Production EC2 fleets
Blue/Green Create entirely new environment, switch traffic None Switch back to blue Low Production with zero downtime
Canary Shift X% traffic, wait, then shift 100% None Shift back to 0% Low: limited blast radius Lambda, API Gateway
Linear Shift X% every N minutes None Shift back to 0% Low: gradual exposure Lambda, API Gateway

SAM DeploymentPreference Types

SAM automates Lambda deployment strategies through CodeDeploy:

Type Traffic Shift Pattern Example
AllAtOnce 100% immediately Instant cutover
Canary10Percent5Minutes 10% for 5 min, then 100% Quick canary validation
Canary10Percent10Minutes 10% for 10 min, then 100% Longer canary validation
Canary10Percent15Minutes 10% for 15 min, then 100% Extended canary validation
Canary10Percent30Minutes 10% for 30 min, then 100% Conservative canary
Linear10PercentEvery1Minute +10% every minute (10 min total) Fast linear rollout
Linear10PercentEvery2Minutes +10% every 2 min (20 min total) Moderate linear rollout
Linear10PercentEvery3Minutes +10% every 3 min (30 min total) Slow linear rollout
Linear10PercentEvery10Minutes +10% every 10 min (100 min total) Very conservative rollout

SAM Template Example:

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Handler: index.handler
    Runtime: python3.13
    AutoPublishAlias: live
    DeploymentPreference:
      Type: Canary10Percent5Minutes
      Alarms:
        - !Ref MyFunctionErrorAlarm
      Hooks:
        PreTraffic: !Ref PreTrafficHookFunction
        PostTraffic: !Ref PostTrafficHookFunction
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ AutoPublishAlias is required for DeploymentPreference to work. SAM automatically publishes a new version on each deploy and updates the alias. The Alarms section triggers automatic rollback if any alarm enters ALARM state during deployment. Canary shifts traffic in two steps (X% then 100%), while Linear shifts in equal increments.

API Gateway Stages and Custom Domains

Concept What It Is Use Case
Stage A named reference to a deployment (dev, staging, prod) Environment separation
Stage Variables Key-value pairs available in the stage Point to different Lambda aliases per stage
Canary Release Split traffic between current and canary deployment Test new API version with real traffic
Custom Domain Map your domain to API Gateway api.example.com instead of xyz.execute-api.region.amazonaws.com
Base Path Mapping Map URL paths to different APIs /v1 β†’ API v1, /v2 β†’ API v2

Stage Variables For Lambda Integration:

Stage: prod β†’ stageVariables.lambdaAlias = "prod"
Stage: dev  β†’ stageVariables.lambdaAlias = "dev"

Lambda ARN: arn:aws:lambda:region:account:function:name:${stageVariables.lambdaAlias}
Enter fullscreen mode Exit fullscreen mode

API Gateway Canary Settings:

Setting Description
Canary Percentage % of traffic routed to canary deployment (0-100)
Stage Variable Overrides Different stage variables for canary traffic
Promote Canary Move canary deployment to production
Delete Canary Remove canary and keep current production

πŸ’‘API Gateway stages are not the same as Lambda aliases, but they work together. Use stage variables to point each stage to the corresponding Lambda alias.

A common pattern: API Gateway prod stage β†’ stage variable lambdaAlias=prod β†’ Lambda function prod alias β†’ version 5.

Rollback Strategies

Rollback Type How It Works When It Triggers
Automatic (alarm-based) CodeDeploy monitors CloudWatch alarms during deployment Alarm enters ALARM state
Automatic (hook failure) CodeDeploy rolls back if a lifecycle hook fails Hook returns Failed
Manual You stop the deployment and roll back You detect an issue
SAM Automatic SAM configures CodeDeploy with alarms from DeploymentPreference Configured alarm triggers

CloudWatch Alarm For Automatic Rollback:

Metric Threshold Purpose
Errors > 0 for 1 minute Catch any Lambda errors
Duration > timeout * 0.8 for 5 minutes Catch performance degradation
Throttles > 0 for 1 minute Catch concurrency issues
5XXError (API GW) > 1% for 5 minutes Catch server errors

πŸ’‘Automatic rollback with CloudWatch alarms is the recommended approach for production deployments.

SAM makes this easy: just add the Alarms list to DeploymentPreference.

CodeDeploy monitors the alarms during the deployment window. If any alarm fires, it automatically shifts all traffic back to the previous version. The rollback is fast because it just updates the alias pointer.

Pre/Post Traffic Hooks

Traffic hooks are Lambda functions that validate your deployment:

PreTraffic Hook Pattern:

import boto3
import json

codedeploy = boto3.client('codedeploy')

def handler(event, context):
    deployment_id = event['DeploymentId']
    lifecycle_event_hook_execution_id = event['LifecycleEventHookExecutionId']

    # Run your validation tests here
    try:
        # Example: invoke the new version and check the response
        lambda_client = boto3.client('lambda')
        response = lambda_client.invoke(
            FunctionName='my-function:live',  # the alias
            Payload=json.dumps({'test': True})
        )
        result = json.loads(response['Payload'].read())

        if result.get('statusCode') == 200:
            status = 'Succeeded'
        else:
            status = 'Failed'
    except Exception:
        status = 'Failed'

    # Report back to CodeDeploy
    codedeploy.put_lifecycle_event_hook_execution_status(
        deploymentId=deployment_id,
        lifecycleEventHookExecutionId=lifecycle_event_hook_execution_id,
        status=status
    )
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ The PreTraffic hook runs before any traffic shifts to the new version: use it for smoke tests and validation.

The PostTraffic hook runs after all traffic has shifted: use it for integration tests.

Both hooks must call put_lifecycle_event_hook_execution_status to tell CodeDeploy whether to proceed or roll back.

If a hook times out (default 1 hour), the deployment fails.

CodePipeline Concepts

Concept Description
Pipeline The overall workflow definition
Stage A logical group of actions (Source, Build, Deploy)
Action A task within a stage (CodeBuild action, CodeDeploy action)
Artifact Files passed between stages (stored in S3)
Transition The link between stages (can be disabled to pause the pipeline)
Approval action Manual approval gate before proceeding
Pipeline Feature Details
Trigger CloudWatch Events (push to CodeCommit), webhook (GitHub), S3 upload
Cross-region Actions can deploy to different regions
Cross-account Use IAM roles for cross-account deployments
Parallel Actions Multiple actions in the same stage run in parallel
Sequential stages Stages run in order. A stage must complete before the next starts

πŸ’‘ CodePipeline stores artifacts in an S3 bucket (created automatically or specified by you).

Each action produces output artifacts and consumes input artifacts.

If you need a manual approval before deploying to production, add an Approval action between the staging deploy and production deploy stages.


πŸ—οΈ Build A Complete CI/CD Pipeline

Build a Complete CI/CD Pipeline from scratch using the AWS Console.

  • A CodeCommit repository with application code
  • A CodeBuild project that runs tests and packages the application
  • A CodePipeline that orchestrates source β†’ build β†’ deploy
  • A Lambda function with canary deployment configured through SAM
  • CloudWatch alarms for automatic rollback
  • A working pipeline that triggers on code push

Prerequisites


Part I

Create A Github Repository And Add Code

πŸ’‘ Why GitHub instead of CodeCommit? AWS closed CodeCommit to new customers in July 2024. Even accounts that can create a CodeCommit repo often find it's not offered as a CodePipeline source provider. GitHub via CodeConnections is the reliable, current, real-world source integration. And it's fully supported by CodePipeline. CodeCommit, CodeBuild, CodeDeploy, and CodePipeline (If your account does offer CodeCommit and you'd rather use it, use it)

Step 01: Create the GitHub Repository

Go to GitHub β†’ New β†’ Repository name: cicd-demo-app β†’ Choose Private (or Public)

⚠️ Don't initialize with a README (we'll push our own files)

Click Create repository

πŸ’‘ Prefer CodeCommit? If your account offers CodeCommit and it appears as a CodePipeline source provider, you can use it instead: create the repo in the CodeCommit console, generate Git credentials in IAM (Security credentials β†’ API keys β†’ Generate API key β†’ AWS CodeCommit), attach the AWSCodeCommitPowerUser policy to your user, then clone the HTTPS URL and push. HTTPS uses Git credentials. SSH uses an uploaded SSH key. Everything downstream (CodeBuild, CodePipeline, CodeDeploy) is identical. only the source provider changes.

Step By Step Guide For Setting Up CodeCommit
Step 1: Open the CodeCommit console β†’ Create repository

  • Repository name: cicd-demo-app
  • Description - optional: Demo application for CI/CD pipeline

Click Create

Step 2: Configure Git Credentials
πŸ’‘ CodeCommit HTTPS access uses Git credentials tied to your IAM user (a generated username/password, separate from your AWS access keys).
Step 3: Open the IAM console β†’ IAM users β†’ select your IAM user

Step 4: Click the Security credentials tab

Step 5: In the API keys section, click Generate API key

Step 6: Service β–Ό: AWS CodeCommit

Click Generate API key

Step 7: Retrieve API key
⚠️ Copy or download the username and password now: This is the only time the password is shown. If you lose it, you must reset it.

Click Close

πŸ’‘ Git Credentials vs Access Keys. CodeCommit HTTPS uses a dedicated username/password (Git credentials), not your AWS_ACCESS_KEY_ID. These are IAM-managed and require a CodeCommit policy like AWSCodeCommitPowerUser on your user. HTTPS = Git credentials or the credential helper. SSH = an uploaded SSH public key.

Step 8: Now attach a CodeCommit permissions policy to the same IAM user so it can actually use the repository.

Step 9: Still on the user's page, go to the Permissions tab β†’ Add permissions β–Ό β†’ Attach policies directly β†’ search for and select AWSCodeCommitPowerUser β†’ Next β†’ Add permissions.

Step 10: Clone And Add Application Code

git clone https://git-codecommit.us-east-1.amazonaws.com/v1/repos/cicd-demo-app
cd cicd-demo-app


python

Step 02: Add the Application Code Locally

mkdir cicd-demo-app
cd cicd-demo-app
git init
git branch -M main
Enter fullscreen mode Exit fullscreen mode

Step 03: Create the Lambda function code app.py

import json

VERSION = "1.0.0"

def lambda_handler(event, context):
    """Order API handler with version tracking."""
    return {
        'statusCode': 200,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps({
            'message': 'Order API is running',
            'version': VERSION,
            'functionVersion': context.function_version
        })
    }
Enter fullscreen mode Exit fullscreen mode

Step 04: Create the SAM template template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: CI/CD Demo Application

Globals:
  Function:
    Timeout: 10
    Runtime: python3.13

Resources:
  OrderFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: app.lambda_handler
      CodeUri: .
      AutoPublishAlias: live
      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Alarms:
          - !Ref OrderFunctionErrorAlarm

  OrderFunctionErrorAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: Errors on OrderFunction
      Namespace: AWS/Lambda
      MetricName: Errors
      Dimensions:
        - Name: FunctionName
          Value: !Ref OrderFunction
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanOrEqualToThreshold
      TreatMissingData: notBreaching
Enter fullscreen mode Exit fullscreen mode

Step 05: Create the buildspec buildspec.yml

version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.13
    commands:
      - pip install aws-sam-cli

  build:
    commands:
      - sam build

  post_build:
    commands:
      - sam package --s3-bucket ${ARTIFACT_BUCKET} --output-template-file packaged.yaml

artifacts:
  files:
    - packaged.yaml
Enter fullscreen mode Exit fullscreen mode

Step 06: Push the code

git add .
git commit -m "Initial application code"
Enter fullscreen mode Exit fullscreen mode

Step 07: Push to Github

git remote add origin `https://github.com/YOUR_USERNAME/cicd-demo-app.git`
git push -u origin main
Enter fullscreen mode Exit fullscreen mode

Part II

Set Up a CodeBuild Project

Step 01: Create an S3 Bucket for Artifacts

Open the S3 console β†’ Create bucket β†’ Account Regional namespace (recommended) β†’ Bucket name: cicd-demo-artifacts

Keep defaults β†’ Create bucket

Step 02: Create the CodeBuild Project

Open the CodeBuild console β†’ Create project

Project configuration:

  • Project name: cicd-demo-build
  • Project type: Default project

β–Ό Source:

  • Source provider β–Ό: GitHub
  • Repository: Repository in my GitHub account
  • Repository: cicd-demo-app

⚠️ If you used CodeCommit instead of GitHub: Set Source provider to CodeCommit

β–Ό Environment:

  • Provisioning model: On-demand
  • Environment image: Managed image
  • Compute: EC2
  • Running mode: Container
  • Operating system: Amazon Linux
  • Runtime(s): Standard
  • Image: aws/codebuild/amazonlinux-x86_64-standard:5.0
  • Image version: Always use the latest image for this runtime version
  • Service role: New service role

β–Ά Additional Configuration: β†’ Environment variables:

  • Name: ARTIFACT_BUCKET β†’ Value: your S3 bucket name

β–Ό Buildspec:

  • Build specifications: Use a buildspec file
  • Buildspec name - optional: buildspec.yml

β–Ό Artifacts:

  • Type: Amazon S3
  • Bucket name: cicd-demo-artifacts-...
  • Name: build-output

Click Create build project

⚠️ Grant the CodeBuild role access to your artifact bucket.

The auto-created CodeBuild service role can write to CodeBuild's default locations, but sam package uploads to your custom ARTIFACT_BUCKET, and the role won't have permission by default.

If the build fails at post_build with an AccessDenied on S3:

Step 1: Go to IAM β†’ Roles β†’ the codebuild-cicd-demo-build-service-role
Step 2: Add permissions β†’ Attach policies β†’ attach AmazonS3FullAccess (or a scoped inline policy allowing s3:PutObject, s3:GetObject, s3:GetBucketLocation on your bucket)

πŸ’‘ Also confirm your S3 bucket and CodeBuild project are in the same region

Step 03: Run a Test Build

Click Start build

⚠️ Watch the build logs in real time
Verify each phase completes: INSTALL β†’ PRE_BUILD β†’ BUILD β†’ POST_BUILD
Check the S3 bucket for the packaged.yaml artifact

πŸ’‘ CodeBuild charges by the minute. Build environments are ephemeral. They're created fresh for each build. Use the cache section in buildspec.yml to cache dependencies between builds and speed up subsequent builds. CodeBuild can also pull secrets from Parameter Store and Secrets Manager using the env section.


Part III

Create a CodePipeline

Step 01: Build the Pipeline

Step 01.1: Open the CodePipeline console β†’ Create pipeline

Step 01.2: Choose creation option

  • Category: Build custom pipeline

Click Next

Step 01.3: Choose Pipeline settings

  • Pipeline name: cicd-demo-pipeline
  • Execution mode: queued
  • Service role: New service role

Click Next

Step 01.4: Add a source stage

  • Source provider β–Ό: GitHub (via GitHub App)
  • Connection: click Connect to GitHub β†’ authorize the CodeConnections connection (reuse the one from CodeBuild if you already made it)
  • Repository name: YOUR_USERNAME/cicd-demo-app
  • Default branch: main
  • Output artifact format: CodePipeline default

Click Next

πŸ’‘ CodeConnections. A connection is a reusable, managed OAuth link between AWS and GitHub (or Bitbucket/GitLab). CodePipeline uses it to detect pushes and pull source. No Git credentials or webhooks to manage yourself. The same connection works across CodePipeline and CodeBuild.

Step 01.5: Add build stage - optional

  • Build provider: Other build providers
  • β–Ό AWS CodeBuild
  • Project name: cicd-demo-build

Click Next

Step 01.6: Add test stage - optional

Click Next

Step 01.7: Add deploy stage

  • Deploy provider β–Ό: AWS CloudFormation
  • Region: United States (North Virginia)
  • Input artifacts: BuildArtifact
  • Action mode: Create or update a stack
  • Stack name: cicd-demo-app
  • Artifact name: BuildArtifact
  • File name: packaged.yaml
  • Capabilities: CAPABILITY_IAM CAPABILITY_AUTO_EXPAND
  • Role name: create/select a CloudFormation deployment role (see the warning below)

Click Next β†’ Create pipeline

Step 02: Watch the Pipeline Execute

The pipeline starts automatically after creation

⚠️ Watch each stage transition: Source β†’ Build β†’ Deploy

Click on each stage to see details and logs

The deploy stage creates a CloudFormation stack with your Lambda function

Step 03: Add a Manual Approval Stage

Step 03.1: Click Edit on the pipeline

Step 03.2: Click Add stage between Build and Deploy

Step 03.3 Stage name: Approval

Click Add stage

Step 03.4: Click Add action group:

  • Action name: ManualApproval
  • Action provider: Manual approval
  • Click: Done

Click Save

πŸ’‘Now the pipeline pauses at the Approval stage and waits for someone to approve before deploying.


Part IV

Configure Canary Deployment with Alarms

Step 01: Verify the Deployment Configuration

Open the CodeDeploy console β†’ Applications

πŸ’‘ You should see a deployment group created by SAM (named something like cicd-demo-app-ServerlessDeploymentApplication-*)

Click on it to see the deployment configuration: CodeDeployDefault.LambdaCanary10Percent5Minutes

Step 02: View the CloudWatch Alarm

Open the CloudWatch console β†’ Alarms

πŸ’‘ Find the OrderFunctionErrorAlarm created by the SAM template

It should be in OK state (no errors yet)

Step 03: Trigger a Deployment

Step 03.1: Update app.py locally

import json

VERSION = "2.0.0"

def lambda_handler(event, context):
    """Order API handler v2 β€” added health check."""
    action = event.get('action', 'default')

    if action == 'health':
        return {
            'statusCode': 200,
            'body': json.dumps({'status': 'healthy', 'version': VERSION})
        }

    return {
        'statusCode': 200,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps({
            'message': 'Order API is running',
            'version': VERSION,
            'functionVersion': context.function_version,
            'improvement': 'Added health check endpoint'
        })
    }
Enter fullscreen mode Exit fullscreen mode

Step 03.2: Push the change

git add .
git commit -m "v2.0.0 - Add health check"
git push origin main
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ The pipeline triggers automatically

Step 03.3: After the deploy stage, go to CodeDeploy β†’ watch the canary deployment:

  • 10% of traffic shifts to version 2
  • CodeDeploy waits 5 minutes while monitoring the alarm
  • If no alarm fires, 100% shifts to version 2

Step 04: Test Automatic Rollback

Push a broken version that throws errors

import json

VERSION = "3.0.0-broken"

def lambda_handler(event, context):
    """Intentionally broken to test rollback."""
    raise Exception("Something went wrong!")
Enter fullscreen mode Exit fullscreen mode

Push and let the pipeline deploy

πŸ’‘ During the canary phase, the 10% of traffic hitting the new version generates errors

The CloudWatch alarm triggers β†’ CodeDeploy automatically rolls back

All traffic returns to the previous working version


Part V

Set Up Automatic Rollback with CloudWatch Alarms

Step 01: Create Additional Alarms

Step 01.1: Open the CloudWatch console β†’ Alarms β†’ Create alarm

Step 01.2: Select metric: Lambda β†’ By Function Name β†’ OrderFunction β†’ Duration

Step 01.3: Configure

  • Statistic: Average
  • Period: 60 seconds
  • Threshold: Greater than 5000 (5 seconds)
  • Evaluation periods: 2 of 3
  • Alarm name: OrderFunction-HighDuration

Click Create alarm

Step 01.4: Create another alarm for throttles

  • Metric: Throttles for OrderFunction
  • Threshold: Greater than 0
  • Period: 60 seconds
  • Alarm name: OrderFunction-Throttles

Step 02: Update the SAM Template template.yaml with Multiple

      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Alarms:
          - !Ref OrderFunctionErrorAlarm
          - !Ref OrderFunctionDurationAlarm
          - !Ref OrderFunctionThrottleAlarm
Enter fullscreen mode Exit fullscreen mode

Push the change to trigger a pipeline run with the updated alarm configuration.

πŸ’‘ You can attach multiple CloudWatch alarms to a deployment preference. If any single alarm fires during the deployment window, CodeDeploy rolls back.

This gives you defense in depth: catch errors, latency spikes, and throttling issues. The alarms are only monitored during the active deployment window, not permanently.


πŸ—οΈ What You Built | πŸ“˜ Exam Concepts Recap

What You Built Exam Concept
Connected a GitHub repo via CodeConnections Source stage, managed source integrations
Built a CodeBuild project with buildspec.yml Build phases, environment variables, artifacts
Created a CodePipeline (source β†’ build β†’ deploy) Pipeline orchestration and artifact flow
Added a manual approval stage Human gates before production deployment
Configured Canary10Percent5Minutes in SAM Gradual traffic shifting with DeploymentPreference
Attached CloudWatch alarms to the deployment Automatic rollback on alarm breach
Pushed a broken version and watched it roll back Defense-in-depth deployment safety
Used AutoPublishAlias: live Required for SAM safe deployments

⚠️ Clean Up Protocol

  1. CodePipeline β†’ Delete cicd-demo-pipeline
  2. CodeBuild β†’ Delete cicd-demo-build project
  3. CloudFormation β†’ Delete the cicd-demo-app stack (removes Lambda, alarms, CodeDeploy resources)
  4. Developer Tools β†’ Settings β†’ Connections β†’ delete the GitHub CodeConnections connection (and optionally delete/keep the GitHub repo yourself)
  5. S3 β†’ Empty and delete the artifacts bucket
  6. IAM β†’ Delete the service roles created for CodeBuild, CodePipeline, and the CloudFormation deploy role
  7. CloudWatch β†’ Delete any remaining log groups and alarms

Key Takeaways

  1. CodePipeline orchestrates the pipeline but doesn't build or deploy: it connects CodeCommit (source), CodeBuild (build), and CodeDeploy (deploy) stages.
  2. buildspec.yml has four phases: install, pre_build, build, post_build.
  3. Use the env section to pull secrets from Parameter Store and Secrets Manager securely.
  4. appspec.yml structure differs between Lambda (Resources + Hooks) and EC2 (files + permissions + hooks).
  5. Canary shifts traffic in two steps (X% then 100%).
  6. Linear shifts in equal increments.
  7. Blue/Green creates a new environment and switches all traffic at once.
  8. SAM DeploymentPreference requires AutoPublishAlias. It automatically creates CodeDeploy deployments with traffic shifting and alarm monitoring.
  9. PreTraffic hooks run before traffic shifts: use for smoke tests. 10. PostTraffic hooks run after: use for integration tests. Both must call put_lifecycle_event_hook_execution_status.
  10. Automatic rollback triggers when a CloudWatch alarm fires during deployment or when a lifecycle hook fails. This is the recommended approach for production.
  11. API Gateway stage variables let you point different stages to different Lambda aliases: prod stage β†’ prod alias, dev stage β†’ dev alias.
  12. CodePipeline artifacts are stored in S3. Each action consumes input artifacts and produces output artifacts that flow to the next stage.
  13. Manual approval actions in CodePipeline create gates between stages: useful for requiring human sign-off before production deployments.

Additional Resources

⚠️ The Future of AWS CodeCommit ⚠️


πŸ—οΈ

Top comments (0)