Automating AMI creation with Packer Amazon EBS is a game-changer for DevOps teams. By using Packer's Amazon EBS builder, you can create consistent, reproducible AMIs in minutes, not hours.
This process is made possible by Packer's ability to snapshot EBS volumes, which can be used to create new AMIs. Packer's EBS builder leverages this feature to automate the creation of AMIs.
With Packer Amazon EBS, you can create AMIs from scratch, using a base image and a set of configuration files. This allows you to create consistent, reproducible AMIs that can be easily rolled out to production.
Packer Template
A Packer template is a crucial component when working with Packer, and it's essential to understand how it works. The template file uses the .pkr.hcl extension and consists of two main blocks: source and build.
The source block describes the base image from which a new AMI is to be built. In our case, we specified that ami-007855ac798b5175e is to be used as the base AMI and use the t2.micro type of EC2 instance to build the new AMI. We also specified that ‘ubuntu’ is to be used as the user name for connecting to the instance for further provisioning, if any.
Packer connects to AWS using the security credentials, spins a t2.micro instance, deploys ami-007855ac798b5175e on it, and builds the new AMI named glarimy-ubuntu. The build block doesn't have any type or label associated with it, but it does have one argument: sources.
Here's a summary of the source block arguments:
- Base image: ami-007855ac798b5175e
- Instance type: t2.micro
- User name: ubuntu
- AMI name: glarimy-ubuntu
The build block takes a list of sources, and Packer builds the AMIs based on these sources. Validating, formatting, and building the template should happen smoothly.
EBS Settings
EBS Settings are crucial when building images with Packer on Amazon EBS. You can specify whether to create the AMI by setting `skip_create_ami` to `true` during a build test stage.
The `ami_block_device_mappings` option allows you to add one or more block device mappings to the AMI, which will be attached when booting a new instance from your AMI. These mappings can include options like `delete_on_termination`, which indicates whether the EBS volume is deleted on instance termination.
To encrypt the root device, you can add the `encrypt_boot` key-value pair to your build template. This will ensure that the root volume for any EC2 instance using the AMI is encrypted. The `kms_key_id` option exists for `launch_block_device_mappings` but not `ami_block_device_mappings`, and it's used for boot volume encryption.
Here's a summary of the EBS settings options:
Settings
The Settings section of EBS is where you can customize your experience to fit your needs. You can adjust the time zone to match your location, ensuring that your schedule and deadlines are always accurate.
The default time zone is set to UTC, but you can easily change it to your local time zone. This will affect the display of dates and times throughout the platform.
To change the time zone, simply click on the clock icon in the top right corner of the screen and select your preferred time zone from the dropdown menu. This is a quick and easy process that will save you time and hassle in the long run.
EBS also allows you to set custom reminders and notifications to keep you on track. By setting reminders for upcoming deadlines and events, you'll be able to stay organized and focused.
You can set reminders to notify you at specific times or dates, and even set recurring reminders for regular events. This feature is especially useful for managing multiple projects and tasks simultaneously.
To access the notification settings, click on the gear icon in the top right corner of the screen and select "Notifications" from the dropdown menu. From there, you can customize your notification preferences to suit your needs.
Block Device Mappings
Block Device Mappings are a crucial part of EBS settings, allowing you to define how volumes are attached to your instance. You can use either ami_block_device_mappings or launch_block_device_mappings to specify the block devices.
These mappings can be used to add one or more block devices to your AMI, which will be attached when booting a new instance from your AMI. You can also use them to add instance store volumes or EBS volumes in addition to the root device volume.
To add a block device during the Packer build, you can use the launch_block_device_mappings field. This will create a block device mapping for the specified volume, which will be attached to the instance when it's launched.
You can also use the ami_block_device_mappings field to add block devices to your AMI. This will create a block device mapping for the specified volume, which will be attached to the instance when it's launched.
To specify the block device mappings, you need to provide the device name, which is the device name exposed to the instance. This is required for every device in the block device mapping.
Here are the fields you can use to specify the block device mappings:
You can use these fields to specify the block device mappings for your instance. For example, you can use the delete_on_termination field to indicate whether the EBS volume is deleted on instance termination.
It's also worth noting that you can use the launch_block_device_mappings field to add a block device before the Packer build starts. This will create a block device mapping for the specified volume, which will be attached to the instance when it's launched.
In addition, you can use the ami_block_device_mappings field to add block devices to your AMI. This will create a block device mapping for the specified volume, which will be attached to the instance when it's launched.
You can also use the no_device field to suppress the specified device included in the block device mapping of the AMI. This is useful if you want to exclude a specific device from the block device mapping.
Finally, you can use the virtual_name field to specify the virtual device name. This is only applicable for ephemeral (instance) volumes, and any EBS-backed volume will have a snapshot_id instead. The volume virtual_name should be in the ephemeral[0-23] form, e.g. ephemeral1.
Instance Configuration
Instance Configuration is a crucial aspect of setting up your Amazon EBS with Packer. You can configure block devices to be attached when launching your instance, and these options may vary depending on the type of VM you use.
You can specify the device name, which is exposed to the instance, and it's required for every device in the block device mapping. For example, you can use /dev/sdh or xvdh.
The encrypted option allows you to specify whether or not to encrypt the volume, and by default, Packer will keep the encryption setting to what it was in the source image. You can also set the volume type, such as gp2 or io1, and the volume size in GiB.
Here are some key options for block devices in Packer:
These options will help you customize your instance configuration to meet your specific needs.
Packer Template Config
You can configure Packer templates to use fast launch settings, which allow you to disable fast launch settings on a region level.
The fast_launch configuration consists of four options: enable_fast_launch, template_id, template_name, and template_version.
The enable_fast_launch option is a boolean that determines whether to enable fast launch settings. If unset, it will default to the region's default behavior.
You can specify a template ID or name using the template_id and template_name options, respectively. However, you cannot specify both options at the same time.
If you specify a template ID or name, you can omit the template_version option, and Packer will default to the latest version available for the template.
Here's a summary of the fast launch configuration options:
By configuring Packer templates with fast launch settings, you can improve the efficiency of your build process.
Block Devices
Block devices can be nested in the ami_block_device_mappings or the launch_block_device_mappings array.
To configure block devices, you'll need to specify the device name, which is the name exposed to the instance, such as /dev/sdh or xvdh. This is a required field for every device in the block device mapping.
You can also specify the volume type, such as gp2 or io1, and the volume size, which is the size of the volume in GiB. If you're not specifying a snapshot ID, you'll need to include the volume size.
Here are the available options for block device mappings:
You can also specify additional options, such as enabling enhanced networking or adding block device mappings to the AMI.
Metadata Settings
To configure metadata settings, you'll need to define two key attributes. The first is the http_endpoint, which can be enabled or disabled by setting it to "enabled" or "disabled" respectively.
The http_tokens attribute determines whether the use of IMDSv2 is optional or required, with options being "optional" or "required". This setting defaults to "optional".
You can also set an upper limit for the amount of hops allowed when communicating with IMDS endpoints using the http_put_response_hop_limit attribute. This numerical value defaults to 1.
Access to instance metadata tags can be enabled or disabled using the instance_metadata_tags attribute, which accepts either "enabled" or "disabled". However, please note that access to instance metadata tags is only available for commercial regions.
Here's a summary of the metadata settings:
WinRM Connection
WinRM connection is a crucial aspect of configuring your instance. You can connect to Windows instances using WinRM by configuring WinRM on the instance.
To do this, you'll need to create a PowerShell script that enables WinRM via HTTPS on port 5986 and creates a self-signed certificate. This script can be supplied to AWS using the "user_data_file" option.
If you're using a certificate from a CA, you can omit the "winrm_insecure" option. Packer will ask AWS to provide a random password that it generates automatically, so you don't need to define a user or password in the script.
Installing
Installing Packer is a straightforward process, and it's available on most popular platforms.
You can install Packer on any Linux platform using the following commands.
If your DevOps team is using Mac, Homebrew can be used to install Packer, and all you need to do is run the latest version of Homebrew.
Once Packer is installed, you can verify the installation by running the following command on the command prompt.
Debugging and Troubleshooting
Debugging and Troubleshooting is a crucial part of the Packer Amazon EBS process.
To access your instance for debugging, run the builder with the -debug flag. This flag enables debug mode, which saves the private key in the current directory.
In debug mode, the Amazon builder will also output the DNS or IP information, making it easier to access your instance as it's running.
You can use this information to troubleshoot any issues that arise during the build process.
Launch and Deployment
Packer is a powerful tool for creating consistent environments, and Amazon EBS is a key part of its deployment process.
With Packer, you can create an Amazon EBS-backed image in just a few minutes.
To get started, you'll need to install the Packer Amazon EBS builder, which is a plugin that allows you to create EBS images.
The Packer Amazon EBS builder supports both Linux and Windows operating systems.
Once you've installed the builder, you can create a Packer configuration file that specifies the EBS image to be created.
In the configuration file, you'll need to specify the Amazon region, the instance type, and the EBS volume size.
You can also specify additional settings, such as the EBS volume type and the instance type.
After creating the configuration file, you can run Packer to create the EBS image.
Packer will then create the EBS image and store it in your Amazon S3 bucket.
You can then use the EBS image to launch new instances in your Amazon EC2 environment.
The entire process is automated and efficient, saving you time and effort.
Artifacts and Output
In Packer, artifacts refer to newly generated files like AMIs.
Packer helps handle these artifacts using post processors, which can register an AMI with a different registry or move it to a different location.
A post-processor can create a file on the local machine with the details of the newly created artifact.
For example, adding a manifest post-processor to the build block in the ami.pkr.hcl file creates a file named 'glarimy-ubuntu.json' with the manifest details of the newly built AMI artifact.
The manifest is generated in a file, such as 'glarimy-ubuntu.json' in my case.
Security and Identity
When executing Packer on Amazon EBS, security and identity are crucial aspects to consider. One way to secure your role assumption is by setting a specific Amazon Resource Name (ARN) for the IAM Role to assume.
You can restrict the assume role session duration to a specified number of seconds using the `duration_seconds` option.
The `external_id` option allows you to pass an external ID to the AssumeRole call, but it's optional and will not be passed if omitted.
You can further restrict permissions for the IAM Role being assumed using an IAM Policy JSON, which can be specified using the `policy` option.
Here are the possible options for further restricting permissions:
Encrypting Root Device
Encrypting the root device of an AMI is a crucial step in securing our infrastructure. We can add the JSON key-value pair “encrypt_boot”: true to the Packer template to achieve this.
This simple addition tells Packer to encrypt the root volume of the instance. Once added, we can run the Packer build command and see the AMI being created in the AWS console.
To confirm that the root device is indeed encrypted, we can launch an instance using this AMI and verify that it is encrypted.
Assume Role
Assume Role is a feature that allows you to set configuration options for assuming a special role when executing Packer.
You can set the Amazon Resource Name (ARN) of the IAM Role to assume with the role_arn option. This is a required field to assume a role.
The duration_seconds option lets you restrict the assume role session duration in seconds. This is a useful feature to prevent unintended role assumption.
You can also pass an external ID to use when assuming the role with the external_id option. If omitted, no external ID is passed to the AssumeRole call.
The policy option lets you describe further restricting permissions for the IAM Role being assumed with an IAM Policy JSON.
Here's a summary of the AssumeRoleConfig options:
- role_arn (string) - Amazon Resource Name (ARN) of the IAM Role to assume.
- duration_seconds (int) - Number of seconds to restrict the assume role session duration.
- external_id (string) - The external ID to use when assuming the role.
- policy (string) - IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.
- policy_arns ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being
- session_name (string) - Session name to use when assuming the role.
- tags (map[string]string) - Map of assume role session tags.
- transitive_tag_keys ([]string) - Set of assume role session tag keys to pass to any subsequent sessions.
Customization and Options
Packer allows you to customize your AMI with various options, including enhanced networking and block device mappings.
You can enable enhanced networking on HVM-compatible AMIs by setting the `ena_support` or `sriov_support` option to `true`. This will require you to add `ec2:ModifyInstanceAttribute` to your AWS IAM policy.
The `ebs_volumes` option allows you to add block device mappings to your AMI, including instance store volumes and EBS volumes. This will create snapshots of the source instance's root volume and any other EBS volumes described here.
You can apply tags to the volumes of the instance that is launched to create EBS Volumes using the `run_volume_tags` or `run_volume_tag` option. However, note that these tags will be temporarily applied to volumes and replaced with the tags configured in the `ebs_volumes` section as soon as the instance is reported as 'ready'.
Using Variables
Using variables in Packer HCL templates is a great way to make your templates more reusable and flexible. You can define variables in the same template file or in a separate file, which is a better approach for obvious reasons.
One way to define variables is to use a separate file called `variables.pkr.hcl`. This file can contain definitions for variables, such as their data type, default value, and validation rules.
For example, you can define a variable named `uname` with a default value of `ubuntu` and a data type of `string`. Here's an example of what the `variables.pkr.hcl` file might look like:
```hcl
variable "uname" {
type = string
default = "ubuntu"
description = "The username to use for SSH"
}
```
Once you've defined your variables, you can use them in your template by referring to them by name. For example, you can use the `uname` variable in the `source` block of your template.
You can also initialize variables in different ways, such as using environmental variables or command line arguments. However, in the example provided, the variables are initialized with default values.
Using variables in your Packer templates can make them more maintainable and easier to reuse. By defining variables in a separate file, you can keep your template code clean and organized.
SSH Options to Use
If you're using Packer to automate your infrastructure, you'll need to decide which SSH options to use to securely connect to your instances.
Using the `ssh_password` option will enable Packer to ssh authenticate with a username and given password.
Here's a breakdown of what happens when you set different SSH options:
If you choose to use a private key file, Packer will ssh authenticate with it, making it a more secure option.
Using a temporary key pair with a particular name can be useful if you need to keep track of multiple keys.
Selecting Base Dynamically
Packer can dynamically locate the source image from a named data source, which is super helpful in automated CI/CD processes.
You can specify a data source type, such as 'amazon-ami', and a label, like 'ubuntu', to narrow down the search. This block uses filters like virtualization-type, name expression, and root device type to find matching AMIs.
Packer connects to the AWS AMI Registry to find all matching AMIs, and you can use the 'most-recent=true' argument to select the latest AMI among them.
The selected ID can be referred to dynamically in the source block, like this:
This allows you to pick up the latest Ubuntu AMI automatically as the source, no matter what its ID.
Customizing the
Customizing the AMI is where Packer really shines. You can add provisioning to your template file to make your new AMI Docker-ready.
To do this, you'll need to edit the build block in your ami.pkr.hcl file. You can keep the data block and source blocks as they are, but the build block is where the magic happens.
The build block has two provisioner blocks of type 'shell'. These blocks tell Packer to run certain shell commands after deploying the source AMI on the instance and before creating the snapshot for the new AMI.
You can supply the shell commands inline or in a separate file. For example, in the above template, the first provisioner is supplied with an inline command that waits till the booting is complete so that you can run the other commands.
The second provisioner is supplied with a file named 'docker.sh'. This file must be present for the Packer to run, and it contains commands to install Docker.
Here are some optional settings you can use to customize your AMI:
These settings can be used to customize your AMI and make it more suitable for your needs.
Optional: Customizing the
Customizing the session manager port is an optional feature in Packer. You can specify a local port on the host machine to use as the local end of the session tunnel to the remote host. If not specified, Packer will find an available port to use.
If you need to grant Systems Manager permissions to the EC2 instance, you can use the temporary_iam_instance_profile_policy_document. This is an alternative to using an existing iam_instance_profile.
You can also customize the build template data by using the available variables. These variables include the BuildRegion, SourceAMI, SourceAMICreationDate, SourceAMIName, SourceAMIOwner, SourceAMIOwnerName, and SourceAMITags.
Here are the available variables:
You can also customize the block device mappings in the AMI by using the ebs_volumes option. This will add the block device mappings to the AMI and create snapshots of the source instance's root volume and any other EBS volumes.
Sources
- https://github.com/hashicorp/packer-plugin-amazon/blob/main/docs/builders/ebs.mdx
- https://blog.compozelabs.com/encrypted-by-default-aws-ebs-packer
- https://developer.hashicorp.com/packer/integrations/hashicorp/amazon/latest/components/builder/ebs
- https://developer.hashicorp.com/packer/integrations/hashicorp/amazon/latest/components/builder/ebsvolume
- https://www.opensourceforu.com/2023/07/building-amazon-machine-images-with-hashicorp-packer/
Featured Images: pexels.com