Continuous Delivery with AWS CodePipeline

Continuous Delivery is an essential part of modern software development. AWS offers a complete CI/CD ecosystem with CodePipeline, CodeBuild, and CodeDeploy. In this post, we show how to set up a deployment pipeline for a Scala application.
AWS DevOps Tools Overview
AWS CodePipeline
CodePipeline is the orchestrating service that connects the individual steps of a deployment pipeline. It defines the workflow from source code change to deployment.
AWS CodeBuild
CodeBuild is a fully managed build service. It compiles source code, runs tests, and produces deployable artifacts.
AWS CodeDeploy
CodeDeploy automates deployment to EC2 instances, Lambda functions, or ECS services.
Pipeline Architecture
A typical pipeline consists of the following stages:
Source → Build → Test → Deploy (Staging) → Deploy (Production)Step 1: Setting Up Source Stage
The source stage monitors the code repository for changes. AWS supports various sources:
- AWS CodeCommit - AWS’s own Git service
- GitHub - Via GitHub Connections
- Bitbucket - Via Bitbucket Connections
- S3 - For artifact-based deployments
Example: GitHub Connection
# cloudformation-template.yaml
SourceStage:
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeStarSourceConnection
Version: 1
Configuration:
ConnectionArn: !Ref GitHubConnection
FullRepositoryId: myorg/myrepo
BranchName: main
OutputArtifacts:
- Name: SourceCodeStep 2: Build Stage with CodeBuild
buildspec.yml for Scala/sbt
version: 0.2
phases:
install:
runtime-versions:
java: corretto11
pre_build:
commands:
- echo "Installing sbt..."
- curl -fL "https://github.com/sbt/sbt/releases/download/v1.9.0/sbt-1.9.0.tgz" | tar xz
- export PATH="$PATH:./sbt/bin"
build:
commands:
- echo "Building..."
- sbt clean compile
- sbt test
- sbt "Docker / stage"
post_build:
commands:
- echo "Build completed"
- docker build -t $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION .
- docker push $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION
artifacts:
files:
- appspec.yml
- taskdef.json
discard-paths: no
cache:
paths:
- '/root/.ivy2/**/*'
- '/root/.sbt/**/*'Creating CodeBuild Project
BuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: my-scala-build
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_MEDIUM
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
PrivilegedMode: true
EnvironmentVariables:
- Name: ECR_REPO
Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/my-app
Source:
Type: CODEPIPELINE
BuildSpec: buildspec.yml
Cache:
Type: S3
Location: !Sub ${CacheBucket}/build-cacheStep 3: Deploy Stage
Option A: ECS Deployment
For containerized applications, ECS is a good choice:
DeployStage:
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: !Ref ECSCluster
ServiceName: !Ref ECSService
FileName: imagedefinitions.json
InputArtifacts:
- Name: BuildOutputOption B: Lambda Deployment
For serverless applications:
DeployStage:
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: my-lambda-stack
TemplatePath: BuildOutput::template.yamlStep 4: Approval Stage (optional)
For production deployments, a manual approval is recommended:
ApprovalStage:
Actions:
- Name: ManualApproval
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
NotificationArn: !Ref ApprovalTopic
CustomData: "Please approve deployment to production"Complete Pipeline
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: my-scala-pipeline
RoleArn: !GetAtt PipelineRole.Arn
Stages:
- Name: Source
Actions:
- Name: Source
# ... Source Configuration
- Name: Build
Actions:
- Name: Build
# ... Build Configuration
- Name: DeployStaging
Actions:
- Name: Deploy
# ... Staging Deployment
- Name: Approval
Actions:
- Name: ManualApproval
# ... Approval Configuration
- Name: DeployProduction
Actions:
- Name: Deploy
# ... Production DeploymentBest Practices
1. Infrastructure as Code
The entire pipeline should be defined as CloudFormation or CDK. This makes it versioned and reproducible.
2. Secrets Management
Use AWS Secrets Manager or Parameter Store for credentials:
EnvironmentVariables:
- Name: DB_PASSWORD
Type: SECRETS_MANAGER
Value: my-secret-name:password3. Use Caching
CodeBuild caching significantly speeds up builds - especially for sbt with its many dependencies.
4. Set Up Notifications
SNS notifications for build failures:
NotificationRule:
Type: AWS::CodeStarNotifications::NotificationRule
Properties:
Name: pipeline-notifications
Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
EventTypeIds:
- codepipeline-pipeline-pipeline-execution-failed
Targets:
- TargetType: SNS
TargetAddress: !Ref NotificationTopicConclusion
AWS CodePipeline provides a complete CI/CD solution that seamlessly integrates into the AWS ecosystem. For teams already using AWS, it’s a natural choice. The combination of CodePipeline, CodeBuild, and various deployment options enables flexible and robust deployment workflows.
At innFactory, we successfully use AWS CodePipeline for our cloud projects and help companies optimize their CI/CD processes on AWS.

Tobias Jonas


