Continuous Deployment (CD) is a software release process where verified changes to a codebase are deployed immediately, and autonomously to a production environment. The main benefit of CD is the removal of human error, as the platform will perform the same steps over and over.
At the Guardian, Riff-Raff is our standard CD platform.
Riff-Raff is configured with a riff-raff.yaml
file.
Tip
- Use this tool to validate your
riff-raff.yaml
configuration file. - If using
@guardian/cdk
, you can auto-generate theriff-raff.yaml
file.
CloudFormation is a service that allows you to define your AWS infrastructure as code. It has various benefits, including changes being made via Pull Requests, confidence in changes to PROD, as they can be tested in CODE beforehand, documentation of non-obvious decisions.
Riff-Raff offers some specific benefits when deploying CloudFormation templates.
When deploying CloudFormation stacks, Riff-Raff will apply the Stack
, Stage
, and App
tags (source),
and the gu:repo
and gu:build-tool
tags (source) to the CloudFormation stack.
A feature of CloudFormation is that (taggable) resources inherit the tags of their parent stack. A change was made to enable the AWS Resource Tagging Standard, which helps DevX understand tag usage. Therefore, using Riff-Raff to deploy CloudFormation is the easiest way to meet the tagging obligation.
For example, let’s say we have this template creating an S3 bucket:
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-bucket
The bucket does not have any tags set. When deployed via Riff-Raff, the S3 bucket will have the Stack
, Stage
, App
, gu:repo
, and gu:build-tool
tags “for free”.
If tags were explicitly declared on the resource, the parent’s tags will be additive to them.
We'll define a stateful resource as one that will cause downtime for users of the application if accidentally deleted. This may include, for example:
- Databases
- Messaging streams (Kinesis, SNS, SQS)
- S3 Buckets
Riff-Raff has two modes of deploying CloudFormation stacks. By default, MostlyHarmless
is used.
In this mode, the stack’s policy is set such that stateful resources are prevented from being deleted.
This helps protect against unintentional changes that could cause service interruption. The Dangerous
mode is the opposite - all actions are enabled.
For our EC2 based applications, there are various requirements for the underlying instances, including regular rotation.
This can be done when deploying CloudFormation stacks with Riff-Raff via the amiParametersToTags
configuration.
It’s worth noting a scheduled deployment needs to be created and rotation can also be achieved with the ami-cloudformation-parameter
type.
This isn’t exclusive to CloudFormation deployments. Riff-Raff keeps a history of deployments, with information such as the date, the commit, the status, etc.
It is also possible to rollback to a previous version, either by triggering a deployment with an older build number, or redeploying a previous deployment.
As mentioned above, Riff-Raff applies some tags to the CloudFormation stack. Riff-Raff also assumes an IAM role when applying changes.
Therefore, searching for CloudFormation stacks without the gu:repo
tag, or this role, is a good approximation.
The best code infrastructure is the code infrastructure that doesn’t exist!
That is, before starting this work, it might be worth checking if the CloudFormation stack is still needed.
If it isn’t, delete it.
The first place to start is to locate the repository where the CloudFormation template resides. This might be the application’s repository, or a “platform” repository. If you’re unable to immediately identify the repository, an available option is to identify a unique string in the stack’s template, and perform a GitHub search for that string.
Tip
See https://github.com/guardian/editorial-tools-platform for some examples of deploying CloudFormation templates within a "platform" repository.
With the GitHub repository identified we create, or update, a riff-raff.yaml
file.
In the most minimal form, the file would look similar to this:
# This application has a CODE and PROD stage
allowedStages:
- CODE
- PROD
# This application is deployed in eu-west-1
regions:
- eu-west-1
# The stack determines the AWS account this application deploys into.
# See https://riffraff.gutools.co.uk/deployinfo/data?key=credentials%3Aaws-cfn-role
stacks:
- deploy
deployments:
cloudformation:
type: cloud-formation
app: my-application
# See https://riffraff.gutools.co.uk/docs/magenta-lib/types#cloudformation for all configuration options
parameters:
templatePath: my-template.yaml
# Discover the CFN stack via the Stack, Stage, App tags...
cloudFormationStackByTags: true
# ...if it can't be found, do NOT create a new CFN stack
createStackIfAbsent: false
With the riff-raff.yaml
file created, we can use the GitHub Action guardian/actions-riff-raff
to upload the riff-raff.yaml
file, and the CloudFormation template file(s) for deployment with Riff-Raff.
With your project configuration uploaded to Riff-Raff, we can preview the deployment to understand which Cloudformation stack it’ll use.
There are three possible outcomes:
-
When using
cloudFormationStackByTags: true
, the preview will show something similar to this: -
When using
cloudFormationStackName
, the preview will show something similar to this: -
Riff-Raff will error at the preview stage if it cannot find a CloudFormation stack at all.
We’ve now confirmed Riff-Raff will impact the correct CloudFormation stack, let’s deploy!
Up until this point, we’ve not made any changes to the template. You might expect this first deployment to be a no-op, however, as described above, Riff-Raff will apply some tags to the CloudFormation stack. Therefore, the changes in this first deployment will be the application of these tags.