An Amazon Machine Image (AMI) is a supported and maintained image provided by AWS that provides the information required to launch an instance. You must specify an AMI when you launch an instance. You can launch multiple instances from a single AMI when you require multiple instances with the same configuration. You can use different AMIs to launch instances when you require instances with different configurations.
An AMI provides the information required to launch an instance, which may include Base Operating system, application dependencies, and other runtime libraries required.
An AMI includes the following:
- One or more Amazon Elastic Block Store (Amazon EBS) snapshots, or, for instance-store-backed AMIs, a template for the root volume of the instance (for example, an operating system, an application server, and applications).
- Launch permissions that control which AWS accounts can use the AMI to launch instances.
- A block device mapping that specifies the volumes to attach to the instance when itβs launched.
Related content:
- How to use terraform to Launch an AWS EC2 Instance
- How to use Terraform AWS EC2 user_data β aws_instance
- Terraform AWS VPC with Public and Private subnets with NAT
- How to Create AWS VPC Peering in same account/region using Terraform
What is Packer?
Packer is a free and open source tool for creating golden images for multiple platforms from a single source configuration. It is lightweight, runs on every major operating system, and is highly performant, creating machine images for multiple platforms in parallel. It is made by Hashicorp to create identical machine images for multiple platforms from a single JSON config file. It gives you the flexibility of building your custom AMI for use in AWS EC2 platform.
What is Packer provisioners?
Provisioners are components of Packer that install and configure software within a running machine prior to that machine being turned into a static image. They perform the major work of making the image contain useful software. Example provisioners include shell scripts, ansible, Chef, Puppet, etc.
Ensure packer is installed
Since we are using packer, we have to make sure that it is installed before proceeding.
If you are an ubuntu user, use these commands to install packer:
|
|
If you are using rhel based OS like Rocky Linux or Alma linux:
|
|
If you are using mac or homebrew package manager, use this command to install:
|
|
For other operating systems, checkout packer downloads page here.
Create packer project
Create a project directory and switch to it:
|
|
Under the project, create a folder called scripts that we will use for our provisioner.
|
|
This is my current directory structure
|
|
Creating Packer templates
Packer reads its configuration either from a json or hcl file. In this guide, we are going to create our configuration template in json. We are going to define variables, builders and provisioners.
Let us create an example nginx web server. Open a webserver.json
template file using your favourite text editor, I am using vim in my case:
|
|
Add this content to the file:
|
|
Under variables
key section, set required variables. In my case I am setting the image name, aws region which is obtained from the env variable AWS_REGION
, subnet id and vpc id.
Under builders
key section, set the aws properties for the source image and the name of the image to build. The source_ami_filter will filter the latest rocky instance to use for the build. Consult the AMI Builder documentation for more details.
On provisioners
section, provide the paths to your scripts to be executed during build. In my case, I am defining a script in scripts/webserver.sh
.
Create provisioners scripts
Finally, let us define the script that will be executed when the ami is being build. In our case, since we want to set up nginx to serve basic content, we will install nginx and create a hello world file to be served.
Open the script file with your text editor:
|
|
Add this content to the file:
|
|
Run the packer build
First ensure that you are logged in to aws. You I have a profile called citizix
where I have added my credentials. The commands below will set the AWS region and citizix profile to be active.
|
|
Next let is build our ami. We can save the build log to build-artifact.log
so we can refer to it in future.
|
|
Once done with provisioning, packer will Stop and destroy temporary instance used, then create an AMI. AMI ID is printed at the end.
Testing AMI Created
In this section, I’ll use Terraform to provision a new instance with created AMI. The same can be done from AWS console. We are going to create an AWS instance using the image we build. We will use terraform to achieve this.
Before proceeding, ensure that you have terraform installed. confirm with this command:
|
|
Create terraform
projects directory.
|
|
We are querying the latest ami matching the webserver ami we created then using it. Add these content to main.tf
.
|
|
The next section is to create the resources usig terraform. Initialize terraform using this command:
|
|
Show an execution plan.
|
|
Finally apply the changes. You will be shown the execution plan then prompted to confirm the changes by typing yes.
|
|
The new instance will be created and its public IP will be shown as part of the outputs. You can also see it in AWS console.
To confirm that out provisioner is working, visit http://server_ip/hello.html
.
Once you are done with the test, you should delete the resources to avoid incurring costs. To destroy your test infrastructure, run this command:
|
|
Conclusion
In this guide we learnt how to use packer to package an AWS ami with the help of a script provisioner.