Demonstrates an automated AMI baking process to build a "boilerplate" AMI, using Ansible.
I recommend you read the below sections, but if you can't wait, here is the how, without the what and why.
- Create a GitHub Personal access token, with the permissions
repo
admin:repo_hook
- Create the CloudFormation Stacks
- Check CodePipeline console for build to complete
If it goes badly, the relevant comics are here:
Amazon Machine Images (AMIs) provide the starting point for new Elastic Compute Cloud (EC2) Instances. Public AMIs are often copies of disks (called snapshots) after a base operating system has been installed, such as Windows, Red Hat Linux, and Ubuntu Linux. When a new EC2 Instance is launched from an AMI, copies of the snapshots are created as new disks (called volumes), and are then specific to that Instance moving forward.
AMI Baking is the process of taking raw ingredients, mixing them in to an EC2 instance, and then "baking" a new AMI for future use. Baking is typically done automatically with an automation "pipeline" process.
The raw ingredients can include:
- The Base Operating System AMI
- Recent security patches
- Additional application software
The AWS AMI Design AWS Answer goes in to further detail on considerations needed for AMI Baking.
- Reduced launch time - the launched EC2 instance has less work to get ready to serve it's purpose.
- Common "agents", such as for centralised logging, monitoring can be preinstalled.
- Workload specific application software can be preinstalled, and only runtime configuration be required.
- Reproducible - the instructions to create the AMI are described in code, and therefore repeatable without human-error. This code can then be stored in a source version control to show changes over time.
- Consistent
- EC2 instances launched from the same AMI will have the same software versions. Manually built systems may have different software versions over time.
- The same AMI can be used across all environments (Non-Production, Production, and DR)
- Testable - the produced AMI can be run through various testing tools to ensure any launched EC2 Instances pass compliance requirements.
The above is an automated AMI Baking Process, utilising:
- GitHub for Source Version Control
- CodePipeline to orchestrate the fetching of code, and delivery to CodeBuild
- CodeBuild to fetch and execute Packer/Ansible
- Packer creates launches temporary EC2 Instances that Ansible can customise, and then bake.
- Ansible is a configuration management tool to customise the Base AMI, as described in Ansible Playbooks
CodePipeline needs to be able to access the GitHub source repository, and be notified of changes. To facilitate this, an authorisation token (OAuth) is needed.
For GitHub, a personal access token needs to be created, with the following permissions:
repo
admin:repo_hook
This will allow CodePipeline to read private repositories, and register itself for change notifications (webhooks).
There are three CloudFormation templates that will deploy everything needed to create multiple AMI Baking CodePipelines.
pipeline-common; IAM ManagedPolicies and Roles that can be used by different CodePipelines, and an S3 Artifact Bucket used by CodePipeline to store artifacts consumed and produced in each stage of the pipeline. This is intended to create one CloudFormation Stack per AWS Account only.
- Inputs: None.
ami-common; creates IAM ManagedPolicies and Roles specific to CodeBuild creating AMIs. The IAM policy mostly comes from the Packer AMI Builder documentation. This is intended to create one CloudFormation Stack per AWS Account only.
- Inputs
- The CloudFormation
pipeline-common
Stack Name, so it can include the correct authorisation to the S3 Artifact Bucket
pipeline; creates a CodePipeline Instance, with integrations to GitHub, and CodeBuild Project. Each CloudFormation Stack will reference a different GitHub Source Repository.
- Inputs:
- The CloudFormation
pipeline-common
Stack Name- The CloudFormation
ami-common
Stack Name- The GitHub Source Repository, in
user/repo
format- The Git Branch of the GitHub Source Repository, usually
master
- The previously create OAuth token to grant CodePipeline access to GitHub
In the CodePipeline console, locate the CodePipeline and check it's status. CodePipeline should have fetched the latest code from GitHub, and CodeBuild should either be in progress, or complete.
If this doesn't work, visit the Troubleshooting section.
This boilerplate currently builds only one AMI, and has a simplified Ansible Playbook, which assumes the use of Ubuntu.
The first customisation is to change the name from boiler
to your own project.
You'll need:
- Duplicate and modify
packer/boiler.json
(Packer Template)- Update the
variables
section - Update the
ansible_playbook
variable to your new project name - Update tagging to match your requirements (
run_tags
,run_volume_tags
, andtags
) - Have a good read through the rest, using the Packer
amazon-ebs
Builder Documentation as reference
- Update the
- Update the
packer/ubuntu-source.json
Packer Variable File to use a more recent version of Ubuntu, if your workload supports it - Modify
buildspec.yml
(CodeBuild Build Specification)- Replace references to
packer/boiler.json
with your own Packer Template
- Replace references to
- Duplicate and modify
ansible/boiler.yaml
to your own project name. - Create Ansible Roles for each specific AMI customisation step. For example, we already have the installation of a Simple Network Management Protocol (SNMP) agent, and deployment of a Linux user (with SSH key). If you're new to Ansible, start with the Intro to Playbooks Ansible Documentation page.
It is possible for Packer to launch the EC2 instance as a Spot Instance. This reduces the EC2 compute cost significantly, with the downside that builds may fail if there is insufficient capacity in your region (either at or during build). Baking AMIs is not a critical task, and therefore loss of a temporary EC2 Instance is acceptable.
This has been used in the past, however is a little unreliable at this stage due to needing to have workable IAM Service-Linked Roles.
The features/neilramsay/spot
branch of this repository includes the relevant Packer instructions, and IAM configuration to enable Spot Instance builds.
- Check the OAuth Token has been correctly copied in to the
pipeline
CloudFormation Stack.
- Check the GitHub repository exists
- Check the GitHub repository has the named branch
- Check the GitHub Personal Access Token (OAuth) is authorised for both
repo
andadmin:repo_hook
.
Packer by default uses the "Default VPC" to perform builds, and assumes it will be present. If you have deleted your Default VPC, you'll need to explicitly tell Packer which VPC to use, and ensure CodeBuild can connect to the launched temporary EC2 Instance.
See the vpc_id
and subnet_id
settings in the Packer amazon-ebs
builder.
Add the relevant configuration to the packer/boiler.json file.