Skip to main content
AWS CI/CD Pipeline Architecture

Module Overview

Estimated Time: 4-5 hours | Difficulty: Advanced | Prerequisites: Compute, Security, Networking
DevOps on AWS combines powerful CI/CD services with Infrastructure as Code. This module covers the complete deployment automation stack. What Youโ€™ll Learn:
  • CodePipeline, CodeBuild, CodeDeploy for CI/CD
  • CloudFormation for infrastructure provisioning
  • AWS CDK for programmatic infrastructure
  • Deployment strategies (blue-green, canary)
  • GitOps and infrastructure automation
  • DevOps best practices and patterns

AWS DevOps Services Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    AWS DevOps Ecosystem                                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                         โ”‚
โ”‚   SOURCE               BUILD                  DEPLOY                   โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€               โ”€โ”€โ”€โ”€โ”€                  โ”€โ”€โ”€โ”€โ”€โ”€                   โ”‚
โ”‚   CodeCommit           CodeBuild              CodeDeploy               โ”‚
โ”‚   GitHub               (Compile, Test,        (EC2, ECS,               โ”‚
โ”‚   Bitbucket            Package)               Lambda, On-prem)         โ”‚
โ”‚   S3                                                                    โ”‚
โ”‚        โ”‚                    โ”‚                      โ”‚                   โ”‚
โ”‚        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                             โ–ผ                                           โ”‚
โ”‚                      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                   โ”‚
โ”‚                      โ”‚ CodePipelineโ”‚                                   โ”‚
โ”‚                      โ”‚ (Orchestrate)โ”‚                                  โ”‚
โ”‚                      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                   โ”‚
โ”‚                                                                         โ”‚
โ”‚   INFRASTRUCTURE AS CODE:                                               โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                             โ”‚
โ”‚   โ€ข CloudFormation (YAML/JSON templates)                               โ”‚
โ”‚   โ€ข AWS CDK (TypeScript, Python, Java, Go, C#)                         โ”‚
โ”‚   โ€ข Terraform (HCL, multi-cloud)                                       โ”‚
โ”‚   โ€ข Pulumi (General-purpose languages)                                  โ”‚
โ”‚                                                                         โ”‚
โ”‚   SUPPORTING SERVICES:                                                  โ”‚
โ”‚   โ€ข CodeArtifact (Package management)                                  โ”‚
โ”‚   โ€ข ECR (Container registry)                                           โ”‚
โ”‚   โ€ข Systems Manager (Configuration)                                    โ”‚
โ”‚   โ€ข Secrets Manager (Credentials)                                      โ”‚
โ”‚                                                                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

CodePipeline

Pipeline Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    CodePipeline Structure                               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚   โ”‚                         PIPELINE                                 โ”‚  โ”‚
โ”‚   โ”‚                                                                  โ”‚  โ”‚
โ”‚   โ”‚  Stage 1: Source                                                 โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Action: GitHub (Push to main)                            โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Output: SourceArtifact                                   โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚  โ”‚
โ”‚   โ”‚                           โ”‚                                      โ”‚  โ”‚
โ”‚   โ”‚                           โ–ผ                                      โ”‚  โ”‚
โ”‚   โ”‚  Stage 2: Build                                                  โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Action: CodeBuild                                        โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Input: SourceArtifact                                    โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Output: BuildArtifact                                    โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚  โ”‚
โ”‚   โ”‚                           โ”‚                                      โ”‚  โ”‚
โ”‚   โ”‚                           โ–ผ                                      โ”‚  โ”‚
โ”‚   โ”‚  Stage 3: Test (Parallel Actions)                               โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Unit Tests     โ”‚  โ”‚ Integration     โ”‚  โ”‚  Security Scan  โ”‚  โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  (CodeBuild)    โ”‚  โ”‚ Tests           โ”‚  โ”‚  (CodeBuild)    โ”‚  โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚  โ”‚
โ”‚   โ”‚                           โ”‚                                      โ”‚  โ”‚
โ”‚   โ”‚                           โ–ผ                                      โ”‚  โ”‚
โ”‚   โ”‚  Stage 4: Deploy to Staging                                     โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Action: CodeDeploy (Blue/Green)                          โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚  โ”‚
โ”‚   โ”‚                           โ”‚                                      โ”‚  โ”‚
โ”‚   โ”‚                           โ–ผ                                      โ”‚  โ”‚
โ”‚   โ”‚  Stage 5: Manual Approval                                       โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Action: Approval (SNS notification)                      โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚  โ”‚
โ”‚   โ”‚                           โ”‚                                      โ”‚  โ”‚
โ”‚   โ”‚                           โ–ผ                                      โ”‚  โ”‚
โ”‚   โ”‚  Stage 6: Deploy to Production                                  โ”‚  โ”‚
โ”‚   โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚  โ”‚
โ”‚   โ”‚  โ”‚  Action: CodeDeploy (Canary 10%, then 100%)              โ”‚   โ”‚  โ”‚
โ”‚   โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚  โ”‚
โ”‚   โ”‚                                                                  โ”‚  โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

CodePipeline Terraform

# CodePipeline with GitHub source and ECS deploy
resource "aws_codepipeline" "app_pipeline" {
  name     = "app-pipeline"
  role_arn = aws_iam_role.codepipeline_role.arn

  artifact_store {
    location = aws_s3_bucket.pipeline_artifacts.bucket
    type     = "S3"
    
    encryption_key {
      id   = aws_kms_key.pipeline.arn
      type = "KMS"
    }
  }

  # Source Stage - GitHub
  stage {
    name = "Source"
    
    action {
      name             = "GitHub_Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeStarSourceConnection"
      version          = "1"
      output_artifacts = ["source_output"]
      
      configuration = {
        ConnectionArn    = aws_codestarconnections_connection.github.arn
        FullRepositoryId = "myorg/myrepo"
        BranchName       = "main"
        DetectChanges    = true
      }
    }
  }

  # Build Stage
  stage {
    name = "Build"
    
    action {
      name             = "Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      input_artifacts  = ["source_output"]
      output_artifacts = ["build_output"]
      version          = "1"
      
      configuration = {
        ProjectName = aws_codebuild_project.app_build.name
      }
    }
  }

  # Test Stage (Parallel)
  stage {
    name = "Test"
    
    action {
      name            = "UnitTests"
      category        = "Test"
      owner           = "AWS"
      provider        = "CodeBuild"
      input_artifacts = ["source_output"]
      version         = "1"
      run_order       = 1
      
      configuration = {
        ProjectName = aws_codebuild_project.unit_tests.name
      }
    }
    
    action {
      name            = "SecurityScan"
      category        = "Test"
      owner           = "AWS"
      provider        = "CodeBuild"
      input_artifacts = ["source_output"]
      version         = "1"
      run_order       = 1  # Same run_order = parallel
      
      configuration = {
        ProjectName = aws_codebuild_project.security_scan.name
      }
    }
  }

  # Deploy to Staging
  stage {
    name = "Deploy_Staging"
    
    action {
      name            = "Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "ECS"
      input_artifacts = ["build_output"]
      version         = "1"
      
      configuration = {
        ClusterName = aws_ecs_cluster.staging.name
        ServiceName = aws_ecs_service.staging.name
        FileName    = "imagedefinitions.json"
      }
    }
  }

  # Manual Approval
  stage {
    name = "Approval"
    
    action {
      name     = "ManualApproval"
      category = "Approval"
      owner    = "AWS"
      provider = "Manual"
      version  = "1"
      
      configuration = {
        NotificationArn = aws_sns_topic.pipeline_approvals.arn
        CustomData      = "Please review staging deployment before production"
      }
    }
  }

  # Deploy to Production
  stage {
    name = "Deploy_Production"
    
    action {
      name            = "Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "CodeDeployToECS"
      input_artifacts = ["build_output"]
      version         = "1"
      
      configuration = {
        ApplicationName                = aws_codedeploy_app.app.name
        DeploymentGroupName            = aws_codedeploy_deployment_group.prod.deployment_group_name
        TaskDefinitionTemplateArtifact = "build_output"
        TaskDefinitionTemplatePath     = "taskdef.json"
        AppSpecTemplateArtifact        = "build_output"
        AppSpecTemplatePath            = "appspec.yaml"
      }
    }
  }
}

CodeBuild

Build Specification

# buildspec.yml
version: 0.2

env:
  variables:
    NODE_ENV: production
  parameter-store:
    DB_PASSWORD: /app/db/password
  secrets-manager:
    API_KEY: prod/api-key:API_KEY

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - echo Installing dependencies...
      - npm ci
  
  pre_build:
    commands:
      - echo Logging into ECR...
      - aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REPO
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:-latest}
  
  build:
    commands:
      - echo Building application...
      - npm run build
      - echo Building Docker image...
      - docker build -t $ECR_REPO:$IMAGE_TAG .
      - docker tag $ECR_REPO:$IMAGE_TAG $ECR_REPO:latest
  
  post_build:
    commands:
      - echo Pushing Docker image...
      - docker push $ECR_REPO:$IMAGE_TAG
      - docker push $ECR_REPO:latest
      - echo Creating image definitions file...
      - printf '[{"name":"app","imageUri":"%s"}]' $ECR_REPO:$IMAGE_TAG > imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json
    - taskdef.json
    - appspec.yaml
  discard-paths: yes

cache:
  paths:
    - node_modules/**/*
    - /root/.npm/**/*

reports:
  jest-reports:
    files:
      - 'coverage/clover.xml'
    file-format: CLOVERXML
  
  security-reports:
    files:
      - 'trivy-results.json'
    file-format: CUCUMBERJSON

CodeBuild Project Terraform

resource "aws_codebuild_project" "app_build" {
  name          = "app-build"
  description   = "Build and push Docker image"
  build_timeout = "30"
  service_role  = aws_iam_role.codebuild_role.arn

  artifacts {
    type = "CODEPIPELINE"
  }

  environment {
    compute_type                = "BUILD_GENERAL1_MEDIUM"
    image                       = "aws/codebuild/amazonlinux2-x86_64-standard:4.0"
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"
    privileged_mode             = true  # Required for Docker builds

    environment_variable {
      name  = "ECR_REPO"
      value = aws_ecr_repository.app.repository_url
    }

    environment_variable {
      name  = "AWS_REGION"
      value = data.aws_region.current.name
    }
  }

  source {
    type      = "CODEPIPELINE"
    buildspec = "buildspec.yml"
  }

  cache {
    type  = "LOCAL"
    modes = ["LOCAL_DOCKER_LAYER_CACHE", "LOCAL_SOURCE_CACHE"]
  }

  logs_config {
    cloudwatch_logs {
      group_name  = "/codebuild/app-build"
      stream_name = "build-logs"
    }
  }

  vpc_config {
    vpc_id             = aws_vpc.main.id
    subnets            = aws_subnet.private[*].id
    security_group_ids = [aws_security_group.codebuild.id]
  }
}

CodeDeploy

Deployment Strategies

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Deployment Strategies                                โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                         โ”‚
โ”‚   IN-PLACE (Rolling)                                                   โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                                    โ”‚
โ”‚   [v1] [v1] [v1] [v1]   โ”€โ”€โ–ถ   [v2] [v1] [v1] [v1]   โ”€โ”€โ–ถ   [v2] [v2]...โ”‚
โ”‚   โ€ข Update instances one at a time                                     โ”‚
โ”‚   โ€ข Brief capacity reduction                                            โ”‚
โ”‚   โ€ข Rollback = redeploy v1                                              โ”‚
โ”‚   โ€ข Good for: EC2, on-prem                                              โ”‚
โ”‚                                                                         โ”‚
โ”‚   BLUE/GREEN                                                            โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                                            โ”‚
โ”‚   Blue (v1): [โ– ] [โ– ] [โ– ] [โ– ]   โ†โ”€โ”€ Production traffic                  โ”‚
โ”‚   Green(v2): [โ–ก] [โ–ก] [โ–ก] [โ–ก]   โ†โ”€โ”€ New version deployed                โ”‚
โ”‚                                                                         โ”‚
โ”‚   After testing, swap traffic:                                          โ”‚
โ”‚   Blue (v1): [โ– ] [โ– ] [โ– ] [โ– ]   โ†โ”€โ”€ Standby (for rollback)              โ”‚
โ”‚   Green(v2): [โ–ก] [โ–ก] [โ–ก] [โ–ก]   โ†โ”€โ”€ Production traffic                  โ”‚
โ”‚                                                                         โ”‚
โ”‚   โ€ข Zero downtime                                                       โ”‚
โ”‚   โ€ข Instant rollback (swap back)                                       โ”‚
โ”‚   โ€ข Double the resources temporarily                                    โ”‚
โ”‚   โ€ข Good for: ECS, Lambda, critical apps                               โ”‚
โ”‚                                                                         โ”‚
โ”‚   CANARY                                                                โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€                                                                โ”‚
โ”‚   [v1] [v1] [v1] [v1]   โ”€โ”€โ–ถ   [v2] [v1] [v1] [v1]   (10% traffic)      โ”‚
โ”‚                              Monitor for errors...                      โ”‚
โ”‚   If healthy:              โ”€โ”€โ–ถ   [v2] [v2] [v2] [v2]   (100% traffic)  โ”‚
โ”‚   If errors:               โ”€โ”€โ–ถ   [v1] [v1] [v1] [v1]   (rollback)      โ”‚
โ”‚                                                                         โ”‚
โ”‚   CANARY OPTIONS:                                                       โ”‚
โ”‚   โ€ข Canary10Percent5Minutes                                            โ”‚
โ”‚   โ€ข Canary10Percent10Minutes                                           โ”‚
โ”‚   โ€ข Canary10Percent15Minutes                                           โ”‚
โ”‚   โ€ข Linear10PercentEvery1Minute                                        โ”‚
โ”‚   โ€ข Linear10PercentEvery3Minutes                                       โ”‚
โ”‚   โ€ข AllAtOnce (not recommended for prod)                               โ”‚
โ”‚                                                                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

CodeDeploy for ECS

# appspec.yaml for ECS Blue/Green
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "app"
          ContainerPort: 8080
        PlatformVersion: "LATEST"
        
Hooks:
  - BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
  - AfterInstall: "LambdaFunctionToValidateAfterInstall"
  - AfterAllowTestTraffic: "LambdaFunctionToRunSmokeTests"
  - BeforeAllowTraffic: "LambdaFunctionToValidateBeforeTraffic"
  - AfterAllowTraffic: "LambdaFunctionToValidateAfterTraffic"
# CodeDeploy for ECS with Blue/Green
resource "aws_codedeploy_app" "app" {
  name             = "app"
  compute_platform = "ECS"
}

resource "aws_codedeploy_deployment_group" "production" {
  app_name               = aws_codedeploy_app.app.name
  deployment_group_name  = "production"
  service_role_arn       = aws_iam_role.codedeploy_role.arn
  deployment_config_name = "CodeDeployDefault.ECSCanary10Percent5Minutes"

  ecs_service {
    cluster_name = aws_ecs_cluster.main.name
    service_name = aws_ecs_service.app.name
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
      wait_time_in_minutes = 0
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 60
    }
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.https.arn]
      }

      test_traffic_route {
        listener_arns = [aws_lb_listener.test.arn]
      }

      target_group {
        name = aws_lb_target_group.blue.name
      }

      target_group {
        name = aws_lb_target_group.green.name
      }
    }
  }

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE", "DEPLOYMENT_STOP_ON_ALARM"]
  }

  alarm_configuration {
    enabled = true
    alarms  = [aws_cloudwatch_metric_alarm.error_rate.name]
  }
}

CloudFormation

Stack Template

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Production VPC with ECS Cluster'

Parameters:
  Environment:
    Type: String
    Default: production
    AllowedValues: [development, staging, production]
  
  VpcCidr:
    Type: String
    Default: 10.0.0.0/16

Mappings:
  EnvironmentConfig:
    development:
      InstanceType: t3.small
      MinSize: 1
      MaxSize: 2
    staging:
      InstanceType: t3.medium
      MinSize: 2
      MaxSize: 4
    production:
      InstanceType: t3.large
      MinSize: 3
      MaxSize: 10

Conditions:
  IsProduction: !Equals [!Ref Environment, production]

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-vpc

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, 8]]
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-public-1

  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${Environment}-cluster
      ClusterSettings:
        - Name: containerInsights
          Value: !If [IsProduction, enabled, disabled]
      CapacityProviders:
        - FARGATE
        - FARGATE_SPOT
      DefaultCapacityProviderStrategy:
        - CapacityProvider: FARGATE
          Weight: !If [IsProduction, 1, 0]
        - CapacityProvider: FARGATE_SPOT
          Weight: !If [IsProduction, 0, 1]

  # Nested stack for modularity
  DatabaseStack:
    Type: AWS::CloudFormation::Stack
    Condition: IsProduction
    Properties:
      TemplateURL: https://s3.amazonaws.com/templates/database.yaml
      Parameters:
        VpcId: !Ref VPC
        SubnetIds: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub ${Environment}-VpcId

  ClusterArn:
    Description: ECS Cluster ARN
    Value: !GetAtt ECSCluster.Arn
    Export:
      Name: !Sub ${Environment}-ClusterArn

AWS CDK

CDK Application Structure

// lib/app-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';

interface AppStackProps extends cdk.StackProps {
  environment: 'development' | 'staging' | 'production';
}

export class AppStack extends cdk.Stack {
  public readonly cluster: ecs.Cluster;
  public readonly service: ecs_patterns.ApplicationLoadBalancedFargateService;

  constructor(scope: Construct, id: string, props: AppStackProps) {
    super(scope, id, props);

    const isProd = props.environment === 'production';

    // VPC with public and private subnets
    const vpc = new ec2.Vpc(this, 'VPC', {
      maxAzs: isProd ? 3 : 2,
      natGateways: isProd ? 3 : 1,
      subnetConfiguration: [
        {
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
          cidrMask: 24,
        },
        {
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
          cidrMask: 24,
        },
        {
          name: 'Isolated',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
          cidrMask: 24,
        },
      ],
    });

    // ECS Cluster
    this.cluster = new ecs.Cluster(this, 'Cluster', {
      vpc,
      containerInsights: isProd,
      enableFargateCapacityProviders: true,
    });

    // RDS Database (production only)
    const database = isProd
      ? new rds.DatabaseInstance(this, 'Database', {
          engine: rds.DatabaseInstanceEngine.postgres({
            version: rds.PostgresEngineVersion.VER_15,
          }),
          instanceType: ec2.InstanceType.of(
            ec2.InstanceClass.R6G,
            ec2.InstanceSize.LARGE
          ),
          vpc,
          vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
          multiAz: true,
          allocatedStorage: 100,
          storageEncrypted: true,
          deletionProtection: true,
        })
      : undefined;

    // Fargate Service with ALB
    this.service = new ecs_patterns.ApplicationLoadBalancedFargateService(
      this,
      'Service',
      {
        cluster: this.cluster,
        cpu: isProd ? 1024 : 256,
        memoryLimitMiB: isProd ? 2048 : 512,
        desiredCount: isProd ? 3 : 1,
        taskImageOptions: {
          image: ecs.ContainerImage.fromRegistry('nginx:latest'),
          containerPort: 80,
          environment: {
            NODE_ENV: props.environment,
            ...(database && {
              DB_HOST: database.instanceEndpoint.hostname,
            }),
          },
        },
        publicLoadBalancer: true,
        circuitBreaker: { rollback: true },
        capacityProviderStrategies: [
          {
            capacityProvider: isProd ? 'FARGATE' : 'FARGATE_SPOT',
            weight: 1,
          },
        ],
      }
    );

    // Auto Scaling
    const scaling = this.service.service.autoScaleTaskCount({
      minCapacity: isProd ? 3 : 1,
      maxCapacity: isProd ? 20 : 3,
    });

    scaling.scaleOnCpuUtilization('CpuScaling', {
      targetUtilizationPercent: 70,
      scaleInCooldown: cdk.Duration.seconds(60),
      scaleOutCooldown: cdk.Duration.seconds(60),
    });

    scaling.scaleOnRequestCount('RequestScaling', {
      requestsPerTarget: 1000,
      targetGroup: this.service.targetGroup,
    });

    // Outputs
    new cdk.CfnOutput(this, 'LoadBalancerDNS', {
      value: this.service.loadBalancer.loadBalancerDnsName,
    });
  }
}

// bin/app.ts
import * as cdk from 'aws-cdk-lib';
import { AppStack } from '../lib/app-stack';

const app = new cdk.App();

// Development
new AppStack(app, 'AppDev', {
  environment: 'development',
  env: { account: '111111111111', region: 'us-east-1' },
});

// Production
new AppStack(app, 'AppProd', {
  environment: 'production',
  env: { account: '222222222222', region: 'us-east-1' },
});

CDK Pipeline

// lib/pipeline-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as pipelines from 'aws-cdk-lib/pipelines';
import { Construct } from 'constructs';
import { AppStack } from './app-stack';

export class PipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Self-mutating pipeline
    const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
      pipelineName: 'AppPipeline',
      synth: new pipelines.ShellStep('Synth', {
        input: pipelines.CodePipelineSource.gitHub('org/repo', 'main', {
          authentication: cdk.SecretValue.secretsManager('github-token'),
        }),
        commands: [
          'npm ci',
          'npm run build',
          'npm run test',
          'npx cdk synth',
        ],
      }),
      dockerEnabledForSynth: true,
    });

    // Staging stage
    const staging = pipeline.addStage(
      new AppStage(this, 'Staging', {
        environment: 'staging',
        env: { account: '111111111111', region: 'us-east-1' },
      }),
      {
        pre: [
          new pipelines.ShellStep('IntegrationTests', {
            commands: ['npm run test:integration'],
          }),
        ],
        post: [
          new pipelines.ShellStep('SmokeTests', {
            commands: ['curl -f https://staging.example.com/health'],
          }),
        ],
      }
    );

    // Production stage with approval
    pipeline.addStage(
      new AppStage(this, 'Production', {
        environment: 'production',
        env: { account: '222222222222', region: 'us-east-1' },
      }),
      {
        pre: [
          new pipelines.ManualApprovalStep('PromoteToProduction', {
            comment: 'Approve production deployment',
          }),
        ],
      }
    );
  }
}

class AppStage extends cdk.Stage {
  constructor(
    scope: Construct,
    id: string,
    props: cdk.StageProps & { environment: string }
  ) {
    super(scope, id, props);
    new AppStack(this, 'App', { environment: props.environment as any });
  }
}

๐ŸŽฏ Interview Questions

Blue-Green:
  • Two identical environments
  • Deploy to inactive (green)
  • Switch all traffic at once
  • Instant rollback (switch back)
  • 2x resources during deployment
Canary:
  • Single environment, gradual rollout
  • Send small % traffic to new version
  • Monitor for errors, then increase
  • Progressive validation
  • Smaller blast radius
Choose blue-green when:
  • Need instant rollback
  • Database schema changes
  • Complete environment validation
Choose canary when:
  • Risk-averse, large user base
  • Need gradual validation
  • Cost-conscious
CloudFormation:
  • Direct YAML/JSON templates
  • Simpler for basic infrastructure
  • No additional tooling needed
  • Better for pure declarative IaC
  • StackSets for multi-account
CDK:
  • Higher-level abstractions
  • Full programming language power
  • Better for complex, reusable constructs
  • Unit testing infrastructure
  • Compile-time type checking
  • Generates CloudFormation
CDK L1, L2, L3 constructs:
  • L1: Direct CloudFormation (CfnXxx)
  • L2: Curated with sensible defaults
  • L3: Patterns (complete solutions)
GitOps principles:
  • Git as single source of truth
  • Declarative infrastructure
  • Automated sync (pull-based)
AWS implementation:
Git Push โ†’ CodePipeline โ†’ 
CodeBuild (synth CDK) โ†’ 
CloudFormation deploy
For Kubernetes (EKS):
  • ArgoCD or Flux for GitOps
  • CodePipeline triggers image build
  • ArgoCD detects manifest changes
  • Pulls and applies to cluster
Best practices:
  • Separate app and infra repos
  • Use semantic versioning
  • Implement drift detection
Never store in code!Options:
  1. Secrets Manager: Runtime retrieval, rotation
  2. Parameter Store: Cost-effective, hierarchical
  3. CodeBuild env vars: Build-time secrets
Best practices:
# buildspec.yml
env:
  secrets-manager:
    API_KEY: prod/api-key:API_KEY
  parameter-store:
    DB_PASSWORD: /app/db/password
Rotation:
  • Secrets Manager automatic rotation
  • Lambda rotation function
  • Applications must handle credential refresh
Account structure:
Management Account
โ”œโ”€โ”€ Shared Services (CI/CD, artifacts)
โ”œโ”€โ”€ Development Account
โ”œโ”€โ”€ Staging Account
โ””โ”€โ”€ Production Account
Pipeline flow:
  1. Pipeline in Shared Services account
  2. Cross-account IAM roles for deployment
  3. Artifact bucket with cross-account access
  4. CloudFormation StackSets for multi-account
Key patterns:
  • Single pipeline, multiple deployment targets
  • Promotion through environments
  • Separate production approval
  • Centralized artifact storage

๐Ÿงช Hands-On Lab: Complete CI/CD Pipeline

1

Set Up CodeCommit/GitHub

Create repository with application code
2

Create CodeBuild Project

Build Docker image, run tests, push to ECR
3

Configure CodeDeploy

ECS blue-green deployment with canary
4

Build CodePipeline

Connect source โ†’ build โ†’ deploy stages
5

Add Manual Approval

Require approval before production
6

Configure Rollback

CloudWatch alarms trigger automatic rollback

Next Module

Well-Architected Framework

Review your architecture against AWS best practices