Capstone (2): The Complete Production Pipeline

K
Kai··4 min read

The target infrastructure is ready from Article 15. Now we wire up the rest: a pipeline that carries code the whole way from commit to production on that fleet. This is where every piece of the series fits together — CodeCommit, CodeBuild (with tests), the approval gate, and CodeDeploy blue/green with rollback — into a single chain. We run it for real with a real code change, then tear everything down.

💰 Cost

This run temporarily has up to four instances (blue + green) plus the ALB. The cleanup section at the end deletes all of the series' resources — run it right after you've seen the result.

The complete pipeline: four stages

The capstone pipeline has four stages, each one a lesson from the series:

{"pipeline": {
  "name": "awscicd-cap-pipeline", "pipelineType": "V2",
  "roleArn": "...awscicd-codepipeline-role",
  "artifactStore": {"type": "S3", "location": "awscicd-artifacts-..."},
  "stages": [
    {"name": "Source",          "actions": [{ "...CodeCommit",  "config": {"RepositoryName":"awscicd-demo-app","BranchName":"main"}, "out":"Src" }]},
    {"name": "BuildAndTest",     "actions": [{ "...CodeBuild",   "config": {"ProjectName":"awscicd-demo-build"}, "in":"Src", "out":"Built" }]},
    {"name": "Approval",         "actions": [{ "...Manual" }]},
    {"name": "DeployBlueGreen",  "actions": [{ "...CodeDeploy",  "config": {"ApplicationName":"awscicd-demo","DeploymentGroupName":"awscicd-cap-dg"}, "in":"Built" }]}
  ]
}}

Source pulls the code (Article 3), BuildAndTest builds and runs pytest as a gate (Articles 4–6), Approval blocks waiting for an approver (Article 13), DeployBlueGreen blue/green deploys onto the ASG behind the ALB (Articles 11, 15). One pipeline wraps the whole series.

Run end-to-end with a real change

Change the application (heading up to v3) and push — exactly what a developer does every day:

$ sed -i '' 's/v2/v3/' index.html
$ git commit -am "Bump app to v3 for capstone" && git push origin main

The pipeline runs on its own. Watch each stage:

$ aws codepipeline get-pipeline-state --name awscicd-cap-pipeline \
    --query 'stageStates[].[stageName,latestExecution.status]' --output text
Source:Succeeded        BuildAndTest:InProgress  Approval:None         DeployBlueGreen:None
Source:Succeeded        BuildAndTest:Succeeded   Approval:InProgress   DeployBlueGreen:None

The pipeline stops at Approval — build and test have passed, now it waits for an approver. Approve:

$ TOKEN=$(aws codepipeline get-pipeline-state --name awscicd-cap-pipeline \
    --query "stageStates[?stageName=='Approval'].actionStates[0].latestExecution.token | [0]" --output text)
$ aws codepipeline put-approval-result --pipeline-name awscicd-cap-pipeline \
    --stage-name Approval --action-name ManualApproval \
    --result summary="capstone approve",status=Approved --token "$TOKEN"

The blue/green deploy runs (stands up the green fleet, validates, shifts traffic). A few minutes later:

$ aws codepipeline get-pipeline-state --name awscicd-cap-pipeline \
    --query 'stageStates[].[stageName,latestExecution.status]' --output text
Source  Succeeded
BuildAndTest    Succeeded
Approval    Succeeded
DeployBlueGreen Succeeded

All four stages Succeeded. Verify the new version is live in production via the ALB:

$ curl http://awscicd-cap-alb-...elb.amazonaws.com/
... awscicd demo app — v3 ...

v3 — the version we just committed — now serves for real, through a chain where nobody typed a single deploy command. Because it's blue/green, throughout the process the ALB always points at a healthy fleet: users see no disruption, and if green fails validation or an alarm fires, rollback is just pointing the ALB back at the living blue.

   git push (v3) → CodeCommit main
        │ trigger
   ┌──────────────────── awscicd-cap-pipeline (V2) ────────────────────┐
   │ Source        BuildAndTest      Approval        DeployBlueGreen     │
   │ CodeCommit ─▶ CodeBuild+pytest ─▶ [approver]   ─▶ CodeDeploy B/G    │
   │               (test gate)                          ↓                │
   └────────────────────────────────────────────────── │ ───────────────┘
                                      green ASG ◀── copy ──┤  shift traffic
                                          │ validate       │  via ALB
                                          ▼                ▼
                              ALB ─▶ healthy fleet (v3)  blue kept for rollback

🧹 Cleanup the entire series

Capstone done, tear down all the resources created across the 16 articles. The capstone infrastructure (expensive) first:

$ aws codepipeline delete-pipeline --name awscicd-cap-pipeline
$ aws autoscaling delete-auto-scaling-group --auto-scaling-group-name awscicd-cap-asg --force-delete
$ aws autoscaling delete-auto-scaling-group --auto-scaling-group-name CodeDeploy_awscicd-cap-dg_d-... --force-delete
$ aws elbv2 delete-load-balancer --load-balancer-arn <cap-alb>
$ aws elbv2 delete-target-group --target-group-arn <cap-tg>
$ aws ec2 delete-launch-template --launch-template-name awscicd-cap-lt
$ aws deploy delete-deployment-group --application-name awscicd-demo --deployment-group-name awscicd-cap-dg

Then the foundation (nearly free but worth deleting to keep things clean):

$ aws deploy delete-deployment-group --application-name awscicd-demo --deployment-group-name awscicd-demo-dg
$ aws deploy delete-application --application-name awscicd-demo
$ aws codebuild delete-project --name awscicd-demo-build
$ aws codecommit delete-repository --repository-name awscicd-demo-app
$ aws ssm delete-parameter --name /cicddemo/greeting; aws ssm delete-parameter --name /cicddemo/api-key
$ aws secretsmanager delete-secret --secret-id awscicd/demo/db --force-delete-without-recovery
$ aws s3 rm s3://awscicd-artifacts-... --recursive && aws s3api delete-bucket --bucket awscicd-artifacts-...
$ aws ec2 delete-security-group --group-id <sg>
# the IAM roles + instance profile: detach policies, remove-role-from-instance-profile, then delete

Double-check on the console that no EC2/ALB/ASG is left behind — this is the expensive part that's easiest to forget.

Series wrap-up

You've gone from "what is CI/CD" to a complete production pipeline on AWS, all via the CLI. What the capstone wraps up: CodeCommit holds the code; CodeBuild builds and runs tests as a blocking gate (with secrets from SSM/Secrets Manager masked, test reports); CodeArtifact for internal packages; CodeDeploy deploys onto EC2 with in-place, lifecycle hooks, Auto Scaling Group, and blue/green + rollback zero-downtime; CodePipeline orchestrates it all through Source → Build → Approval → Deploy, with an approval gate and notifications. Throughout: each service runs under a least-privilege IAM service role, and every article was tested for real then torn down clean.

Where to go next

The series stops at a solid pipeline, but there are many directions to dig deeper. Infrastructure-as-code: build the pipeline and infrastructure themselves with CloudFormation, CDK, or Terraform (see the Terraform series) instead of loose CLI commands. Other deploy targets: CodeDeploy to ECS (blue/green containers) or Lambda (canary). Large scale: cross-account pipelines (build in one account, deploy to another), and CodeCatalyst — AWS's new unified DevOps service that gathers source/CI-CD/issues in one place. Each direction builds on the very foundation these 16 articles laid, and you now have enough grounding to read the docs and carry on by yourself.