AWS CodePipeline
AWS CodePipeline offers a way to define workflows for continuous integration and delivery (CI/CD).
Various AWS services are used to implement each stage of a pipeline.
There is no need to provision upfront infrastructure as build agents are provisioned on demand. This can be cheaper than running a dedicated build server.
Stages
A CodePipeline is divided into many stages, or steps in a workflow. A simple linear workflow might be
- source checkout
- build a docker image
- deploy the image as docker container
By configuring a git webhook, a pipeline can be triggered each time a commit is pushed to source control.
Artifact store
Each stage of a pipeline is executed asynchronously, and may use output artifacts from a previous stage. Artifact storage is required to accommodate this. In 2022, S3 is only option.
Source checkout
AWS provides git hosting via CodeCommit.
Source code residing on GitHub or BitBucket can be accessed using a CodeStar connections.
An archive artifact (zip of the source code) is an output of this stage. This can be sent to a downstream build stage.
Build
This stage is handled by a AWS CodeBuild project.
Role
CodePipeline will assume a role to run. It may need access to
- The S3 bucket for artifact storage
- The CodeStar connection to access source code
- The CodeBuild project to start the build job.
Terraform
Sample codepipeline
# github
resource "aws_codestarconnections_connection" "github" {
name = "github"
provider_type = "GitHub"
}
# S3 bucket where artifacts are stored for the pipeline
resource "aws_s3_bucket" "example_codepipeline" {
bucket = "example-codepipeline"
}
resource "aws_s3_bucket_public_access_block" "example_codepipeline" {
bucket = aws_s3_bucket.example_codepipeline.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_acl" "example_codepipeline" {
bucket = aws_s3_bucket.example_codepipeline.id
acl = "private"
}
# pipeline role
resource "aws_iam_role" "example" {
name = "example-codepipeline"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "example" {
name = "example-codepipeline"
role = aws_iam_role.example.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codestar-connections:UseConnection"
],
"Resource": "${aws_codestarconnections_connection.github.arn}"
},
{
"Effect":"Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketVersioning",
"s3:PutObjectAcl",
"s3:PutObject"
],
"Resource": [
"${aws_s3_bucket.example_codepipeline.arn}",
"${aws_s3_bucket.example_codepipeline.arn}/*"
]
},
{
"Effect": "Allow",
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild"
],
"Resource": [
"${aws_codebuild_project.example.arn}"
]
}
]
}
EOF
}
resource "aws_codepipeline" "example" {
name = "example"
role_arn = aws_iam_role.example.arn
artifact_store {
location = aws_s3_bucket.example.bucket
type = "S3"
}
stage {
name = "Source"
action {
category = "Source"
name = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.github.arn
FullRepositoryId = "magicmonster/example"
BranchName = "main"
}
}
}
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.example.name
}
}
}
}