Typically in AWS environment, we use CodePipeline as the orchestrator to build, test and deploy our application/service.
But in some scenario such as deploying static websites, we may just need to achieve simple continuous deployment. In these cases, we don’t need the full blown deployment pipeline for staging and approval process. We can simply use CodeBuild to accomplish the continuous deployment.
Of course we still need a repository to store our source. In this post, we will use AWS CodeCommit to demonstrate the process.
We will showcase using a simple Next.js application that is built to generate static files and then push to a S3 bucket to host as a static website. A buildspec.yml file will be created to tell CodeBuild how to build and deploy the application.
AWS CDK will be used to setup the whole infrastructure and resources needed to carry out the automated deployment.
Infrastructure and resources needed
Here we will discuss what resources are needed to achieve the pipeline. Then we will use CDK to define and create the infrastructure.
CodeCommit Repository: This would be the repository to store the source code of the Next.js application.
CodeBuild Project: Create a CodeBuild project responsible for building the application. The project should also have enough permissions to access and update the corresponding S3 bucket.
CloudWatch event: Establish an event to trigger a CodeBuild project to start building when there is a commit to the repository. We can also specify the event only occurs when commiting to branch named deploy.
S3 Bucket: defined as a publicly accessible static website to host the application.
AWS CDK setup
CDK stands for Cloud Development Kit. It is an open source software development framework to model and provision AWS infrastructure resources using programming languages (Infrastructure as code).
For basic setup, check out Deploy AWS S3 Website using CDK in Python. This section assumes you have the basic CDK setup and will focus the code commands required to build the infrastructure described in last section.
Additional aws-cdk packages are need:
Use pip install to install each package or add them to requirements.txt and run pip install -r requirements.txt.
Create class CicdCodebuildStack with following code:
from aws_cdk import (core, aws_codecommit as _codecommit, aws_s3 as _s3, aws_codebuild as _codebuild, aws_iam as _iam, aws_events_targets as _targets) class CicdCodebuildStack(core.Stack): def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create code commit repository repo = _codecommit.Repository(self, id + "_repo", repository_name= id + "_repo" ) # Create code build project using repository's branch deploy as source project = _codebuild.Project(self, id + "_build-project", source= _codebuild.Source.code_commit(repository= repo, branch_or_ref= "refs/heads/deploy") ) # Create trigger to build the project when commited on branch 'deploy' repo.on_commit('CommitToDeployBranch', branches= ['deploy'], target= _targets.CodeBuildProject(project)) # Create S3 bucket to host as static website bucket = _s3.Bucket(self, id + "-static-website", bucket_name= id + "-static-website", website_index_document= 'index.html', website_error_document= 'error.html', public_read_access= True, removal_policy= core.RemovalPolicy.DESTROY) # Grant permissions for CodeBuild project to push files to S3 bucket project.add_to_role_policy(_iam.PolicyStatement( effect= _iam.Effect.ALLOW, resources= [ bucket.bucket_arn, bucket.bucket_arn + '/*' ], actions= [ 's3:GetBucket*', 's3:List*', 's3:GetObject*', 's3:DeleteObject', 's3:PutObject' ] ))
The above code will create all the resources described. It should be self explanatory. Next is to invoke the class in app.py:
#!/usr/bin/env python3 from aws_cdk import core from cicd_codebuild.cicd_codebuild_stack import CicdCodebuildStack app = core.App() CicdCodebuildStack(app, "cicd-codebuild") app.synth()
I use id = cicd-codebuild. So, the repository name would be cicd-codebuild_repo and S3 bucket name would be cicd-codebuild-static-website.
Run command cdk synth to confirm CloudFormation template is generated successfully. Then execute command cdk deploy to actually create the resources.
Once deployed successfully, I can verify that the resources are created accordingly at AWS Management Console. Going to S3 > cicd-codebuild-static-website > Properties > Static Website Hosting, we can see that it is created successfully with an Endpoint URL ready to access the website:
But browsing to the URL now will yield Found Not Found error as there’s no content yet. Check on CodeCommit also confirms the repository is created.
Setup a simple Next.js application
- Clone the URL of repository cicd-codebuild_repo
- run commands:
- git clone <clone-url>
- npm init next-app
- enter cicd-codebuild_repo (project name)
- select Default starter app
- cd cicd-codebuild_repo
A sample Next.js application should be created. Now add following line to scripts section of package.json:
"export": "next export",
It’s next.js command to generate static files to directory out.We will now add the following buildspec.yml file to the project:
# Do not change version. This is the version of aws buildspec, not the version of your buldspec file. version: 0.2 phases: install: runtime-versions: nodejs: 10 commands: - echo not installing anything else pre_build: commands: - echo Installing source NPM dependencies... - npm install - aws --version build: commands: - echo Build started on `date` - echo Compiling the Node.js code - npm run build - npm run export post_build: commands: - echo Build completed on `date` - aws s3 sync out s3://cicd-codebuild-static-website/
It tells CodeBuid project build Next.js project and generate static files at build phase. Then push code static files to S3 bucket at post build phase.
I first commit the project and push to the master branch using vscode.
Now, it’s time to trigger the deployment process. I checkout a new branch deploy and then push the codes to the branch. Once pushed, I can verify that CodeBuild project is triggered and started the building process.
The build process is done in couple minutes. Revisiting the endpoint URL show the webpage successfully:
Awesome! Now every commit to branch deploy will trigger CodeBuild process to build and push the new updates to S3 static website.