Featured image of post AWS Code Pipelines in a Nutshell

AWS Code Pipelines in a Nutshell

Sample App + Full Pipeline Setup

πŸš€ Welcome to the Pipeline Party: Part 1

This is Part 1 of our series β€œAWS Code Pipelines in a Nutshell”. We’re gonna get our hands dirty with a real sample app and connect the dots between:

  • AWS CodeCommit (our Git repo)
  • AWS CodeBuild (to build stuff)
  • AWS CodeDeploy (to push the stuff)
  • AWS CodePipeline (to glue it all together)

So buckle up, grab your keyboard, and let’s make some DevOps magic happen!


🧁 Sample App: A Simple Express.js Web App

Here’s a tiny Node.js + Express app we’ll use:

πŸ“ app.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;

app.get("/", (req, res) => {
  res.send("πŸŽ‰ Hello from AWS CodePipeline! πŸŽ‰");
});

app.listen(port, () => {
  console.log(`App running at http://localhost:${port}`);
});

πŸ“ package.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "name": "codepipeline-demo",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

Push this to your Git repo (we’ll use CodeCommit shortly).


πŸ—ƒ Step 1: AWS CodeCommit – Git in the Cloud

πŸ› οΈ Create a CodeCommit Repo

1
2
3
aws codecommit create-repository \
  --repository-name codepipeline-demo \
  --repository-description "Demo app for AWS CodePipeline"

πŸ”— Clone & Push the App

1
2
3
4
5
6
git clone https://git-codecommit.<region>.amazonaws.com/v1/repos/codepipeline-demo
cd codepipeline-demo
# Copy your app.js and package.json into this folder
git add .
git commit -m "Initial commit"
git push

Boom! Your app is now in CodeCommit.


πŸ”§ Step 2: AWS CodeBuild – Build that Thing

πŸ› οΈ Create buildspec.yml

Add this to your root directory:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - echo "Installing dependencies..."
      - npm install
  build:
    commands:
      - echo "Build successful! πŸŽ‰"

artifacts:
  files:
    - '**/*'

πŸ—οΈ Create a CodeBuild Project

1
2
3
4
5
6
aws codebuild create-project \
  --name codepipeline-demo-build \
  --source type=CODECOMMIT,location=https://git-codecommit.<region>.amazonaws.com/v1/repos/codepipeline-demo \
  --artifacts type=NO_ARTIFACTS \
  --environment type=LINUX_CONTAINER,image=aws/codebuild/standard:7.0,computeType=BUILD_GENERAL1_SMALL \
  --service-role arn:aws:iam::<account-id>:role/CodeBuildServiceRole

πŸ“¦ Step 3: AWS CodeDeploy – Shipping Time

Let’s deploy this thing to EC2.

πŸ—‚οΈ Create appspec.yml

Add this to your repo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app

hooks:
  AfterInstall:
    - location: scripts/install.sh
      timeout: 180
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 180
      runas: ec2-user

πŸ“ scripts/install.sh

1
2
3
#!/bin/bash
cd /home/ec2-user/app
npm install

πŸ“ scripts/start.sh

1
2
3
#!/bin/bash
cd /home/ec2-user/app
nohup npm start > app.log 2>&1 &

Don’t forget to make these executable:

1
chmod +x scripts/*.sh

🎯 Create an Application and Deployment Group

1
2
3
4
5
6
7
8
9
aws deploy create-application \
  --application-name codepipeline-demo-app \
  --compute-platform Server

aws deploy create-deployment-group \
  --application-name codepipeline-demo-app \
  --deployment-group-name codepipeline-demo-dg \
  --ec2-tag-filters Key=Name,Value=CodeDeployDemo,Type=KEY_AND_VALUE \
  --service-role-arn arn:aws:iam::<account-id>:role/CodeDeployServiceRole

Make sure your EC2 instance has:

  • A tag Name=CodeDeployDemo
  • The CodeDeploy agent installed

🧬 Step 4: AWS CodePipeline – Glue It All Together

πŸ§ͺ Create the Pipeline

1
aws codepipeline create-pipeline --cli-input-json file://pipeline.json

πŸ“„ pipeline.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{
  "pipeline": {
    "name": "codepipeline-demo-pipeline",
    "roleArn": "arn:aws:iam::<account-id>:role/CodePipelineServiceRole",
    "artifactStore": {
      "type": "S3",
      "location": "my-codepipeline-bucket"
    },
    "stages": [
      {
        "name": "Source",
        "actions": [
          {
            "name": "SourceAction",
            "actionTypeId": {
              "category": "Source",
              "owner": "AWS",
              "provider": "CodeCommit",
              "version": "1"
            },
            "outputArtifacts": [
              {
                "name": "SourceOutput"
              }
            ],
            "configuration": {
              "RepositoryName": "codepipeline-demo",
              "BranchName": "main"
            },
            "runOrder": 1
          }
        ]
      },
      {
        "name": "Build",
        "actions": [
          {
            "name": "BuildAction",
            "actionTypeId": {
              "category": "Build",
              "owner": "AWS",
              "provider": "CodeBuild",
              "version": "1"
            },
            "inputArtifacts": [
              {
                "name": "SourceOutput"
              }
            ],
            "outputArtifacts": [
              {
                "name": "BuildOutput"
              }
            ],
            "configuration": {
              "ProjectName": "codepipeline-demo-build"
            },
            "runOrder": 1
          }
        ]
      },
      {
        "name": "Deploy",
        "actions": [
          {
            "name": "DeployAction",
            "actionTypeId": {
              "category": "Deploy",
              "owner": "AWS",
              "provider": "CodeDeploy",
              "version": "1"
            },
            "inputArtifacts": [
              {
                "name": "BuildOutput"
              }
            ],
            "configuration": {
              "ApplicationName": "codepipeline-demo-app",
              "DeploymentGroupName": "codepipeline-demo-dg"
            },
            "runOrder": 1
          }
        ]
      }
    ],
    "version": 1
  }
}

πŸŽ‰ Final Result

You now have:

  • A live Node.js app
  • Versioned in AWS CodeCommit
  • Built using AWS CodeBuild
  • Deployed to EC2 with AWS CodeDeploy
  • All automated via AWS CodePipeline

Go Beyond the Basics

So you’ve got a simple pipeline up and running. Nice!

But now you’re asking the big questions:

  • How do I know if something goes wrong?
  • What’s this blue/green deployment everyone keeps talking about?
  • Can I do custom stuff during builds and deploys?

You’re in luckβ€”this part covers exactly that!


Monitoring CodePipeline: Keeping an Eye on the Beast

πŸ” View Pipeline Execution Status

You can check your pipeline’s state via the AWS Console or CLI:

1
2
3
aws codepipeline get-pipeline-execution \
  --pipeline-name codepipeline-demo-pipeline \
  --pipeline-execution-id <execution-id>

Or list all executions:

1
2
aws codepipeline list-pipeline-executions \
  --pipeline-name codepipeline-demo-pipeline

You’ll get:

  • Start time
  • Status (Succeeded, Failed, InProgress)
  • Trigger info

🧯 Hook into CloudWatch Alarms

When a stage fails, AWS will automatically emit CloudWatch Events. Hook them up to SNS for email/text alerts or Lambda functions for automatic rollback.

1
2
aws sns create-topic --name codepipeline-alerts
aws sns subscribe --topic-arn <topic-arn> --protocol email --notification-endpoint your@email.com

Then add that SNS topic to a CloudWatch rule for CodePipeline Pipeline Execution State Change.


πŸŒ€ Blue/Green Deployment with CodeDeploy

Let’s level up our deploys with zero-downtime deployments.

🧠 What is Blue/Green?

  • Blue: your currently running version
  • Green: the new version you’re deploying

CodeDeploy will:

  1. Launch new instances or use a separate ASG
  2. Test the new version
  3. Shift traffic gradually or instantly
  4. Roll back if something breaks

🎯 Update Your Deployment Group

Switch the deployment type to BLUE_GREEN:

1
2
3
4
aws deploy update-deployment-group \
  --application-name codepipeline-demo-app \
  --current-deployment-group-name codepipeline-demo-dg \
  --deployment-style deploymentType=BLUE_GREEN,deploymentOption=WITH_TRAFFIC_CONTROL

πŸ—οΈ Add Load Balancer Support

Make sure your EC2 instances are behind a Load Balancer (ALB preferred), then specify the target groups in your deployment group.

1
2
3
4
aws deploy update-deployment-group \
  --application-name codepipeline-demo-app \
  --current-deployment-group-name codepipeline-demo-dg \
  --blue-green-deployment-configuration file://bluegreen-config.json

bluegreen-config.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "deploymentReadyOption": {
    "actionOnTimeout": "CONTINUE_DEPLOYMENT",
    "waitTimeInMinutes": 1
  },
  "greenFleetProvisioningOption": {
    "action": "COPY_AUTO_SCALING_GROUP"
  },
  "terminateBlueInstancesOnDeploymentSuccess": {
    "action": "TERMINATE",
    "terminationWaitTimeInMinutes": 5
  }
}

πŸ”§ Advanced buildspec.yml: Customize All the Things

Want to run unit tests? Create zip files? Deploy to S3? You got it.

πŸ“ Sample buildspec.yml with Tests & Artifact

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - npm install
  pre_build:
    commands:
      - echo "Running unit tests..."
      - npm test || exit 1
  build:
    commands:
      - echo "Zipping build output"
      - zip -r app.zip .
artifacts:
  files:
    - app.zip

This will:

  • Fail the build if tests fail
  • Package the app into a zip file
  • Upload it to CodePipeline as an artifact

πŸ§™ Custom Scripts in CodeDeploy

πŸš€ More Hook Options in appspec.yml

Here’s a full list of lifecycle hooks:

1
2
3
4
5
hooks:
  BeforeInstall:
  AfterInstall:
  ApplicationStart:
  ValidateService:

You can also use scripts like:

1
2
#!/bin/bash
pm2 restart app || node app.js &

Or run DB migrations, send Slack alerts, etc.


🧰 Handy CLI Tools & Tips

  • Check CodeDeploy agent on EC2:

    1
    
    sudo service codedeploy-agent status
    
  • Log locations:

    • CodeDeploy logs: /opt/codedeploy-agent/deployment-root/
    • Hook logs: /opt/codedeploy-agent/deployment-root/*/logs/scripts.log
  • Manually trigger a pipeline:

    1
    2
    
    aws codepipeline start-pipeline-execution \
      --name codepipeline-demo-pipeline
    

Time to go Serverless

You’ve built your pipeline.
You’ve got blue/green deployments like a boss.
Now it’s time to go serverless, link up with GitHub, and do multi-region deploysβ€”the fancy DevOps buffet! 🍱


⚑ Deploying Serverless Apps with CodePipeline + Lambda

Want to deploy Lambda functions without crying over zip files and cronjobs?
We got you.

🧾 Example: Serverless Node.js Lambda

index.js

1
2
3
4
5
6
exports.handler = async (event) => {
  return {
    statusCode: 200,
    body: "Hello from Lambda & CodePipeline! πŸŽ‰",
  };
};

template.yaml (SAM Template)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  HelloLambda:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      CodeUri: .
      MemorySize: 128
      Timeout: 5
      Events:
        HelloAPI:
          Type: Api
          Properties:
            Path: /hello
            Method: get

πŸ“ Add buildspec.yml for SAM Build & Deploy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - npm install -g aws-sam-cli
  build:
    commands:
      - sam build
  post_build:
    commands:
      - sam package --s3-bucket my-sam-artifacts-bucket --output-template-file packaged.yaml
artifacts:
  files:
    - packaged.yaml

πŸ’₯ Setup Deploy Stage for Lambda

Change the deploy provider in your pipeline to CloudFormation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "name": "DeployLambda",
  "actionTypeId": {
    "category": "Deploy",
    "owner": "AWS",
    "provider": "CloudFormation",
    "version": "1"
  },
  "configuration": {
    "ActionMode": "CREATE_UPDATE",
    "StackName": "lambda-pipeline-stack",
    "TemplatePath": "BuildOutput::packaged.yaml",
    "Capabilities": "CAPABILITY_IAM"
  },
  "inputArtifacts": [{ "name": "BuildOutput" }],
  "runOrder": 1
}

πŸ”— Using GitHub as a Source for CodePipeline

Tired of pushing to CodeCommit? Let’s hook up your GitHub repo.

πŸ”‘ Step 1: Connect GitHub to AWS

Go to AWS Console > CodePipeline > Connections
Create a new GitHub Connection (via AWS CodeStar).

It’ll ask for GitHub OAuth permissions. Grant them.

πŸŽ›οΈ Step 2: Update Your Pipeline Source

Switch your source provider to GitHub:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "name": "Source",
  "actions": [
    {
      "name": "GitHubSource",
      "actionTypeId": {
        "category": "Source",
        "owner": "ThirdParty",
        "provider": "GitHub",
        "version": "1"
      },
      "outputArtifacts": [{ "name": "SourceOutput" }],
      "configuration": {
        "Owner": "your-github-username",
        "Repo": "your-repo-name",
        "Branch": "main",
        "OAuthToken": "****" 
      },
      "runOrder": 1
    }
  ]
}

πŸ›‘ PSA: If using GitHub source in new regions, use CodeStar connections instead of OAuth tokensβ€”it’s the cool kid now.


🌍 Multi-Region Deployment Like a Global DevOps Jedi

Let’s say you want your app deployed in us-east-1 AND eu-west-1.

Here’s the plan:

  • Build once
  • Deploy the same artifact to both regions

πŸ’‘ Step 1: Create a Cross-Region S3 Bucket

You need an S3 artifact bucket in each region:

1
aws s3 mb s3://my-codepipeline-artifacts-eu --region eu-west-1

🧠 Step 2: Update Your Pipeline with Cross-Region Deploy

Add a second deploy stage like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "name": "DeployToEU",
  "actionTypeId": {
    "category": "Deploy",
    "owner": "AWS",
    "provider": "CloudFormation",
    "version": "1"
  },
  "region": "eu-west-1",
  "configuration": {
    "ActionMode": "CREATE_UPDATE",
    "StackName": "my-stack-eu",
    "TemplatePath": "BuildOutput::packaged.yaml",
    "Capabilities": "CAPABILITY_IAM"
  },
  "inputArtifacts": [{ "name": "BuildOutput" }],
  "runOrder": 1
}

Don’t forget to give CodePipeline permission to use cross-region S3 buckets and services.