Part 2 sprouting some website goodness - A practical example for DevOps on AWS
What’s The Problem
If you’ve read my first post (and you have, haven’t you), you either thought “that’s absolute crap, why would I bother” or “hey, that’s pretty neat, but what can I do with it”. If you were the former, then avert your eyes because this post is targeted firmly at the latter.
In this post I will be covering how to extend an Inception Pipeline to do something useful. In this instance, it is creating the infrastructure to host a single page application. On the projects I’m currently involved with, this is always the first piece of infrastructure we need (well, after first inceptioning up the pipeline).
What Technologies Are We Going To Use
What Are The Prerequisites
The obvious first prerequisite is an existing Inception Pipeline. So, if you don’t have one, jump across to the original post and create yourself one.
The next prerequisite is to manually create a couple of AWS resources:
- The first one to create is an AWS Certificate Manager managed SSL certificate in the
us-east-1region. This is the only region that CloudFront will look for the certificate. So, unless you’re creating the stack in
us-east-1, you’re going to need to create it yourself. This also gives you the option to verify the certificate by email or DNS (email is the only option when it is created via CloudFormation). You can find out more here.
- The second manual step is to ensure you have a Route 53 Hosted Zone. All that you need is the
HostedZoneIdas it is a parameter to the CloudFormation template discussed below.
Incidentally, using the CloudFormation template discussed in this post will get you an ‘A’ grade.
How It All Works
What this template does for you:
- Creates an S3 bucket for holding the website files. These files do not need to be publicly accessible. In fact, we hide them away in the S3 Bucket Policy so that only CloudFront can serve them.
- Creates an S3 bucket to hold the CloudFront access logs.
- Creates a CloudFront distribution that sits in front of the S3 website bucket.
- Creates a CloudFront origin access identity so that no-one can access the S3 bucket outside of CloudFront
404errors to the
index.htmlpage. This is needed for single page applications (like AngularJS/Angular) that create browser friendly URLs that do not map to S3 files. The high-level flow is the S3 gives
403, CloudFront serves the
index.htmlwhich kicks off the SPA that reads the URI and starts serving the right content.
- Send access logs to an S3 bucket.
- Uses an existing SSL certificate, and makes sure everything is accessing it via HTTPS
- Creates a DNS ‘A’ record in the specified Route 53 hosted zone. This hides the CloudFront domain behind your friendly domain name.
Where Do I Get The Seed Files
The files are on the Part 2 branch in the GitHub repository.
What Are The Files
|aws_infrastructure.yml||The magnum opus; the CloudFormation template that makes it all work|
|aws_infrastructure.json||These are the parameters used by the CloudFormation template during execution|
|aws_seed.yml||Gets a new CloudFormation deployment action snippet as described below which executes the
Taking It For A Spin
Getting started is super simple and easy.
Add the following parameter to your
aws_seed.jsonfile. Obviously, you need to replace the value with the CloudFormation stack name of your choosing:
Add the following snippet to the
Parameterssection of your
StageAdministerInfrastructureStackName: Type: String Description: The name of the stack that administers the website infrastructure
Add the following snippet under the
AdministerPipelinestage in the CodePipeline resource in
- Name: 'AdministerInfrastructure' Actions: - Name: 'AdministerWebsiteInfrastructure' ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: '1' Configuration: ActionMode: REPLACE_ON_FAILURE RoleArn: !GetAtt [CloudFormationDeployActionRole, Arn] StackName: !Ref StageAdministerInfrastructureStackName TemplateConfiguration: !Join ['', [!Ref RepositoryName, 'Source', '::aws_infrastructure.json']] TemplatePath: !Join ['', [!Ref RepositoryName, 'Source', '::aws_infrastructure.yml']] InputArtifacts: - Name: !Join ['', [!Ref RepositoryName, 'Source']] RunOrder: '10'
- Copy the
aws_infrastructure.jsoninto the same folder as
- Replace the parameter values in
aws_infrastructure.jsonwith appropriate values.
- Commit the changes and push to CodeCommit.
If you sit and watch the pipeline execution, you’ll notice its starts executing, realises there is a structural change and then restarts execution from the top. In my not-so-humble opinion, this is one of the best features of an Inception Pipeline; it just manages itself effortlessly.
In this post I covered how you can extend an Inception Pipeline to do something useful. And in the next post, we’ll take this idea one step further…