Skip to main content

AWS CodeBuild


1 - Overview

AWS CodeBuild is a fully managed build service that compiles source code, runs tests, and produces deployment-ready artifacts.


2 - Configuring a project

2.1 Create a CodeBuild project

# Via CLI
aws codebuild create-project \
--name mon-projet-build \
--source type=CODECOMMIT,location=https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/mon-app \
--artifacts type=S3,location=mon-bucket-artifacts \
--environment type=LINUX_CONTAINER,image=aws/codebuild/amazonlinux2-x86_64-standard:4.0,computeType=BUILD_GENERAL1_SMALL \
--service-role arn:aws:iam::123456789:role/CodeBuildServiceRole

2.2 Via CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: CodeBuild Project

Resources:
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: mon-projet-build
Description: Build de mon application
ServiceRole: !GetAtt CodeBuildRole.Arn

Source:
Type: CODECOMMIT
Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/mon-app
BuildSpec: buildspec.yml

Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
PrivilegedMode: true # Pour Docker
EnvironmentVariables:
- Name: ENV
Value: production
- Name: SECRET_KEY
Type: SECRETS_MANAGER
Value: my-secret:key

Artifacts:
Type: S3
Location: !Ref ArtifactsBucket
Name: build-output
Packaging: ZIP

Cache:
Type: S3
Location: !Sub ${CacheBucket}/cache

LogsConfig:
CloudWatchLogs:
Status: ENABLED
GroupName: /codebuild/mon-projet

TimeoutInMinutes: 30
QueuedTimeoutInMinutes: 60

Tags:
- Key: Project
Value: MonProjet

CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
Policies:
- PolicyName: CodeBuildPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource: !Sub ${ArtifactsBucket.Arn}/*
- Effect: Allow
Action:
- codecommit:GitPull
Resource: '*'

3 - buildspec.yml

3.1 Basic structure

# buildspec.yml
version: 0.2

env:
variables:
JAVA_HOME: "/usr/lib/jvm/java-17-amazon-corretto"
parameter-store:
DB_PASSWORD: /myapp/db/password
secrets-manager:
API_KEY: my-secret:api_key

phases:
install:
runtime-versions:
nodejs: 18
docker: 20
commands:
- echo "Installing dependencies..."
- npm ci

pre_build:
commands:
- echo "Running pre-build..."
- npm run lint
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPO

build:
commands:
- echo "Building..."
- npm run build
- docker build -t $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION .
- docker push $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION

post_build:
commands:
- echo "Build completed on $(date)"
- echo "Creating imagedefinitions.json"
- printf '[{"name":"app","imageUri":"%s"}]' $ECR_REPO:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json

artifacts:
files:
- dist/**/*
- imagedefinitions.json
discard-paths: no
base-directory: .

cache:
paths:
- node_modules/**/*
- /root/.npm/**/*

reports:
jest-reports:
files:
- 'junit.xml'
base-directory: coverage
file-format: JUNITXML
coverage-reports:
files:
- 'coverage/clover.xml'
file-format: CLOVERXML

3.2 Predefined environment variables

VariableDescription
CODEBUILD_BUILD_IDUnique build ID
CODEBUILD_BUILD_NUMBERSequential build number
CODEBUILD_RESOLVED_SOURCE_VERSIONCommit ID
CODEBUILD_SOURCE_REPO_URLSource repo URL
CODEBUILD_WEBHOOK_HEAD_REFBranch for webhooks
CODEBUILD_SRC_DIRSources directory

3.3 Complete Docker build

version: 0.2

env:
variables:
AWS_REGION: eu-west-1
ECR_REPO: 123456789.dkr.ecr.eu-west-1.amazonaws.com/mon-app

phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REPO
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}

build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $ECR_REPO:latest .
- docker tag $ECR_REPO:latest $ECR_REPO:$IMAGE_TAG

post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $ECR_REPO:latest
- docker push $ECR_REPO:$IMAGE_TAG
- echo Writing image definitions file...
- printf '[{"name":"container","imageUri":"%s"}]' $ECR_REPO:$IMAGE_TAG > imagedefinitions.json

artifacts:
files:
- imagedefinitions.json

4 - Build environments

4.1 Managed images

ImageDescription
aws/codebuild/amazonlinux2-x86_64-standard:4.0Amazon Linux 2, multi-runtime
aws/codebuild/amazonlinux2-x86_64-standard:5.0Amazon Linux 2023
aws/codebuild/standard:7.0Ubuntu, multi-runtime

4.2 Compute types

TypevCPUMemoryPrice/min
BUILD_GENERAL1_SMALL33 GB$0.005
BUILD_GENERAL1_MEDIUM715 GB$0.01
BUILD_GENERAL1_LARGE1572 GB$0.02
BUILD_GENERAL1_2XLARGE72145 GB$0.20

4.3 Custom Docker image

# Dockerfile pour environnement de build custom
FROM aws/codebuild/amazonlinux2-x86_64-standard:4.0

# Installer des outils supplémentaires
RUN yum install -y \
terraform \
ansible \
&& yum clean all

# Configurer des outils
COPY scripts/setup.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/setup.sh

5 - Test Reports

5.1 Report configuration

# buildspec.yml
reports:
# Rapports de tests unitaires
unit-tests:
files:
- '**/*'
base-directory: test-results/unit
file-format: JUNITXML

# Couverture de code
coverage:
files:
- 'coverage/cobertura-coverage.xml'
file-format: COBERTURAXML

# Tests Cucumber
cucumber:
files:
- 'reports/cucumber.json'
file-format: CUCUMBERJSON

5.2 Generate reports

# Jest avec rapport JUnit
npm test -- --coverage --reporters=default --reporters=jest-junit

# pytest avec rapport JUnit
pytest --junitxml=test-results/pytest.xml

# Go tests
go test -v ./... 2>&1 | go-junit-report > test-results/report.xml

6 - Cache and optimization

6.1 S3 cache

cache:
paths:
- 'node_modules/**/*'
- '/root/.m2/**/*'
- '/root/.gradle/**/*'
- '/root/.cache/pip/**/*'

6.2 Local cache

cache:
type: LOCAL
modes:
- LOCAL_SOURCE_CACHE # Cache du code source
- LOCAL_DOCKER_LAYER_CACHE # Cache des layers Docker
- LOCAL_CUSTOM_CACHE # Cache personnalisé

6.3 Docker optimization

# Multi-stage build pour réduire la taille
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

7 - Webhooks and triggers

7.1 GitHub webhook

# Créer un webhook
aws codebuild create-webhook \
--project-name mon-projet \
--filter-groups '[
[
{"type": "EVENT", "pattern": "PUSH"},
{"type": "HEAD_REF", "pattern": "^refs/heads/main$"}
],
[
{"type": "EVENT", "pattern": "PULL_REQUEST_MERGED"}
]
]'

7.2 Build badges

<!-- README.md -->
![Build Status](https://codebuild.eu-west-1.amazonaws.com/badges?uuid=abc123&branch=main)

Summary

In this chapter, we learned:

  • The creation and configuration of CodeBuild projects
  • Writing the buildspec.yml file
  • The environments and compute types
  • Test reports and coverage
  • Cache and optimization
  • Webhooks and triggers

Next step

In the next chapter, we will look at AWS CodeDeploy to automate deployments.

→ Next chapter: AWS CodeDeploy


← Back to the table of contents