DEV Community

omuthu for AWS Community Builders

Posted on

Dynamic Pipeline Orchestration using CodePipeline, CodeBuild and Step Functions

Introduction

AWS CodePipeline helps in orchestrating CI/CD pipeline all the way from building and testing to deploying applications, from development to production environments.

However, one of the limitations of AWS CodePipeline is its inability to dynamically execute or skip any pipeline action.

This post demonstrates how to setup a CI/CD pipeline to dynamically orchestrate and execute actions based on inputs

AWS Services

This solution uses the following AWS services:

  • AWS CodeCommit – Source Control
  • AWS CodeBuild – Build System
  • AWS CodePipeline – Continuous Delivery
  • AWS Step Functions - Workflow automation using state machines

Solution Overview

  1. A change or commit to the code in the CodeCommit application repository triggers CodePipeline with the help of a CloudWatch event.
  2. The pipeline downloads the code from the CodeCommit repository, initiates the first build using CodeBuild and securely saves the built artifact to an S3 bucket.
  3. Once build succeeds, pipeline triggers a Step Function Workflow
  4. Step Function workflow uses artifact from previous build as input and iterates for each item in the input
  5. For each input, it triggers respective CodeBuild or Pass state using Choice state
  6. Step Functions will succeed once all invoked builds suceed

Architecture

CodePipeline CodeBuild StepFunctions Orchestration

Steps

CodeCommit

  1. Created a repo and have a file "sample_source.json" with below content

{"services":["service_A", "service_B"]}

CodeBuild

First CodeBuild

  • It copies source file and generates ABC.json which is passed as output artifact and consumed by next Step Function
  • This is optional when codebuild can generate a similar json file with list of services to be passed as input to step functions
  • BuildSpec

ServiceA and ServiceB CodeBuild

Step Functions

State Machine

State Machine json

  • The artifact passed as json file will be received as json input by step functions state machine
  • It receives the input using a "Map" state which supprts iteration
  • Within iterator, "Choice" state is used to validate the values and invoke respective "Task" or "Pass" state
  • The "Task" state in our scenario will invoke a CodeBuild task using "Optimized Integrations"
  • CodeBuild task supports only sync invocation which means the next state following CodeBuild execution has to wait until it finishes.
  • However, since the iterator uses a "Choice" state, each iteration is independent and happens in parallel
  • In this example, for "ServiceA" and "ServiceB", CodeBuild is executed and "ServiceC" is set as a "pass" state

Note: Ensure enough permissions are granted for StepFunctions IAM role to make relevant service invocations

StepFunction IAM permissions for CodeBuild

CodePipeline

CodePipeline Definition

CodePipeline Definition

  • Once all the above steps are done, all we need to do is to create pipeline in CodePipeline
  • Create Source stage using any SCM, I used CodeCommit
  • Create a Build stage using existing "First Codebuild" build project
  • Create next "Step Sunctions" stage with following params
    • Action Provider: Step Functions
    • Input artifacts: Output Artifact from previous "First CodeBuild"
    • State machine ARN: Choose the recently created stateMachine ARN
    • Input type: File Path
    • Input: ABC.json (use whatever file is sent in output artifact from previous build)

Execution

  • Release a change to test the pipeline
  • In this example, if services list changes in "sample_source.json", step functions will execute only those states

Conclusion

  • This solution demonstrated the invocation of Step Functions from CodePipeline and Step Functions execution executing builds in CodeBuild dynamically based upon the received input

Code Repository

My LinkedIn

Top comments (5)

Collapse
 
ashokkumarsundar profile image
ashokkumarsundar

Good one Muthu, eagerly waiting for more articles sharing your vast experience in AWS.

One doubt on this, can you share a use case where we need couple of build levels (one at CodePipeline level and another at CodeBuild triggered by Step Function)?

Collapse
 
omuthu profile image
omuthu • Edited

Hi Ashok, CI pipelines are predefined and actions defined are static. With just codepipeline, every stage would execute as it is defined. A shared repo which has pipeline setup to do more than one build based on folder paths within the repo, all folders would get built or deployed even when files in one or few folders are updated. Step Functions can help in such cases to skip or execute stages conditionally

Something like this Ex: 1

Will also help in complex pipelines where some stages/actions need to be executed/skipped on conditions and like this Ex: 2

Collapse
 
fagiani profile image
Paulo Fagiani

@omuthu Thanks for sharing that! How about the deploy after all builds happen? For example if you have a Blue/Green ECS deployment how does it fit on CodePipeline? Would it have to be detached and called by the lambda function? Keep Rocking!

Collapse
 
jasondunn profile image
Jason Dunn [AWS]

Great first article! 👍

Collapse
 
omuthu profile image
omuthu

Thanks Jason