> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# DevOps & CI/CD

> Master AWS CodePipeline, CloudFormation, CDK, and infrastructure automation

<Frame>
  <img src="https://mintcdn.com/devweeekends/sTu6A4whRFPJo0_g/images/aws/cicd-pipeline.svg?fit=max&auto=format&n=sTu6A4whRFPJo0_g&q=85&s=b3985e1e555afebab520013cca830a89" alt="AWS CI/CD Pipeline Architecture" width="1080" height="1080" data-path="images/aws/cicd-pipeline.svg" />
</Frame>

## Module Overview

<Info>
  **Estimated Time**: 4-5 hours | **Difficulty**: Advanced | **Prerequisites**: Compute, Security, Networking
</Info>

DevOps on AWS combines powerful CI/CD services with Infrastructure as Code. The goal is to make deployments boring -- a well-built pipeline turns "deploying to production" from a stressful Friday afternoon event into an automated, reversible, observable process that happens dozens of times per day. This module covers the complete deployment automation stack. A practical note: many teams use GitHub Actions or GitLab CI for build/test and only use AWS services (CodeDeploy, CloudFormation) for the deployment phase. That is perfectly fine -- the concepts here apply regardless of which CI tool you use upstream.

**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

```hcl theme={null}
# 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

```yaml theme={null}
# 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

```hcl theme={null}
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 gives the build container access to the Docker daemon.
    # Required for building Docker images inside CodeBuild.
    # Security note: only enable this for projects that actually build images.
    # Privileged mode means the build can do anything on the host -- if your
    # build runs untrusted code (e.g., PRs from forks), this is a security risk.
    privileged_mode             = true

    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

```yaml theme={null}
# 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"
```

```hcl theme={null}
# 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

```yaml theme={null}
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

```typescript theme={null}
// 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

```typescript theme={null}
// 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

<AccordionGroup>
  <Accordion title="Q1: Explain blue-green vs canary deployments.">
    **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
  </Accordion>

  <Accordion title="Q2: CloudFormation vs CDK - when to use each?">
    **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)
  </Accordion>

  <Accordion title="Q3: How do you implement GitOps on AWS?">
    **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
  </Accordion>

  <Accordion title="Q4: How do you handle secrets in CI/CD pipelines?">
    **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:**

    ```yaml theme={null}
    # 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
  </Accordion>

  <Accordion title="Q5: Design a multi-account CI/CD strategy.">
    **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
  </Accordion>
</AccordionGroup>

***

## 🧪 Hands-On Lab: Complete CI/CD Pipeline

<Steps>
  <Step title="Set Up CodeCommit/GitHub">
    Create repository with application code
  </Step>

  <Step title="Create CodeBuild Project">
    Build Docker image, run tests, push to ECR
  </Step>

  <Step title="Configure CodeDeploy">
    ECS blue-green deployment with canary
  </Step>

  <Step title="Build CodePipeline">
    Connect source → build → deploy stages
  </Step>

  <Step title="Add Manual Approval">
    Require approval before production
  </Step>

  <Step title="Configure Rollback">
    CloudWatch alarms trigger automatic rollback
  </Step>
</Steps>

***

## Next Module

<Card title="Well-Architected Framework" icon="award" href="/aws/well-architected">
  Review your architecture against AWS best practices
</Card>
