Author: Michael Wittig

Continuously integrating and deploying your source code is the new standard in many successful internet companies. But what about your infrastructure? Can you deploy a change to your infrastructure in an automated way? Can you run automated tests on your infrastructure to ensure that a change has no unintended side effects? In this post I will show you how you can apply the same processes to your AWS infrastructure that you apply to your source code. You will learn how the AWS services CloudFormation, CodePipeline and Lambda can be combined to continuously deploy infrastructure.

Precondition

You may think: “Source code is text files, but my infrastructure is different. I don’t have a source file for my infrastructure.” Infrastructure as Code as defined by Martin Fowler is a concept that is helping bring software development practices to infrastructure practices.

Infrastructure as code is the approach to defining computing and network infrastructure through source code that can then be treated just like any software system.

– Martin Fowler

AWS CloudFormation is one implementation of Infrastructure as Code. CloudFormation is a high quality and free service offered by AWS. To understand CloudFormation you need to know about templates and stacks. The template is the source code, a textual representation of your infrastructure. The stack is the actual running infrastructure described by the template. So a CloudFormation template is exactly what we need, a plain text file. The CloudFormation service interprets the template and turns it into a running infrastructure.

Now, our infrastructure is defined by a text file which is exactly what we need to apply the same processes to it that we have for source code.

The Pipeline

The pipeline to build and deploy is a sequence of steps that are necessary to ship changes to your users. Starting with a change in the code repository and ending in your production environment. The following figure shows a Pipeline that runs inside AWS CodePipeline, the AWS CD service.

Whenever a git push is made to a repository hosted on GitHub the pipeline starts to run by fetching the current version of the repository. After that, the pipeline creates or updates itself because the pipeline definition itself is also treated as source code. After that, the up-to-date pipeline creates or updates the test environment. After this step, infrastructure in the test environment looks exactly as it was defined in the template. This is also a good place to deploy the application to the test environment. I’m using Elastic Beanstalk to host the demo application. Now it’s time to check if the infrastructure is still in a good shape. We want to make sure that everything runs as it is defined in the tests. The tests may check if a certain port is reachable, if a certain user can login via SSH, if a certain port is NOT reachable, and so on, and so forth. If the tests are successful, the production environment is adapted to the new template and the new application version is deployed.

Implementation

CodePipeline has native support for GitHub, CloudFormation, Elastic Beanstalk, and Lambda. So I can use all the services and tie them together using CodePipeline. You can find the full source code and detailed setup instructions in this GitHub repository: michaelwittig/automation-for-the-people

The following template snippet shows an excerpt of the full pipeline description. Here you see how the pipeline can be configured to checkout the GitHub repository and create/update itself:

--- AWSTemplateFormatVersion: '2010-09-09' Description: 'Pipeline' Parameters: GitHubUserName: Type: String GitHubOAuthToken: Type: String NoEcho: true Resources: Pipeline: Type: 'AWS::CodePipeline::Pipeline' Properties: ArtifactStore: #[...] Name: 'automation-for-the-people' RestartExecutionOnUpdate: true RoleArn: #[...] Stages: - Name: Source Actions: - Name: SourceAction ActionTypeId: Category: Source Owner: ThirdParty Provider: GitHub Version: 1 Configuration: Owner: !Ref GitHubUserName Repo: 'automation-for-the-people' Branch: master OAuthToken: !Ref GitHubOAuthToken OutputArtifacts: - Name: Zip RunOrder: 1 - Name: DeployPipeline Actions: - Name: DeployPipelineAction ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: 1 Configuration: ActionMode: CREATE_UPDATE Capabilities: CAPABILITY_IAM RoleArn: #[...] StackName: 'aftp-pipeline' TemplatePath: 'Zip::infrastructure/pipeline.yaml' ParameterOverrides: !Sub '{"GitHubUserName": "${GitHubUserName}", "GitHubOAuthToken": "${GitHubOAuthToken}"}' InputArtifacts: - Name: Zip RunOrder: 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 -- - AWSTemplateFormatVersion : '2010-09-09' Description : 'Pipeline' Parameters : GitHubUserName : Type : String GitHubOAuthToken : Type : String NoEcho : true Resources : Pipeline : Type : 'AWS::CodePipeline::Pipeline' Properties : ArtifactStore : #[...] Name : 'automation-for-the-people' RestartExecutionOnUpdate : true RoleArn : #[...] Stages : - Name : Source Actions : - Name : SourceAction ActionTypeId : Category : Source Owner : ThirdParty Provider : GitHub Version : 1 Configuration : Owner : ! Ref GitHubUserName Repo : 'automation-for-the-people' Branch : master OAuthToken : ! Ref GitHubOAuthToken OutputArtifacts : - Name : Zip RunOrder : 1 - Name : DeployPipeline Actions : - Name : DeployPipelineAction ActionTypeId : Category : Deploy Owner : AWS Provider : CloudFormation Version : 1 Configuration : ActionMode : CREATE_UPDATE Capabilities : CAPABILITY_IAM RoleArn : #[...] StackName : 'aftp-pipeline' TemplatePath : 'Zip::infrastructure/pipeline.yaml' ParameterOverrides : ! Sub '{"GitHubUserName": "${GitHubUserName}", "GitHubOAuthToken": "${GitHubOAuthToken}"}' InputArtifacts : - Name : Zip RunOrder : 1

Summary

Infrastructure as Code enables you to apply the same CI & CD processes to infrastructure that you already know from software development. On AWS, you can use CloudFormation to turn a text representation of your infrastructure into a running environment stack. CodePipeline can be used to orchestrate the deployment process and you can implement custom logic, such as infrastructure tests, in a programming language that you can run on AWS Lambda. Finally you can treat your infrastructure as code and deploy each commit with confidence into production.

About the Author

Michael Wittig is author of Michael Wittig is author of Amazon Web Services in Action (Manning) and writes frequently about AWS on cloudonaut.io . He helps his clients to gain value from Amazon Web Services. As a software engineer he develops cloud-native real-time web and mobile applications. He migrated the complete IT infrastructure of the first bank in Germany to AWS. He has expertise in distributed system development and architecture, with experience in algorithmic trading and real-time analytics.