In this guide we will discuss how one can create a customized RHEL 8 / CentOS 8 AMI for AWS using Image Builder. For those new to Image Builder, it is a tool used to create customized system images of Red Hat Enterprise Linux, including system images prepared for deployment on cloud platforms.
The image Builder automatically handles server setup details for each image output hence it is faster than manual methods of image creation. A command line tool composer-cli, is available, as well as a graphical user interface in the Cockpit web console.
Image Builder Blocks
- Blueprint – This define customized system images by listing packages and customizations that will be part of the system. Blueprints are presented to the user as plain text in the Tom’s Obvious, Minimal Language (TOML) format.
- Compose – Composes are individual builds of a system image, based on a particular version of a particular blueprint.
- Customization – These are are specifications for the system, which are not packages. This includes users, groups, and SSH keys.
Image Builder output formats
The Image Builder enables you to build images for multiple output formats. See table below.
Description | CLI name | file extension |
---|---|---|
QEMU QCOW2 Image | qcow2 |
.qcow2 |
Ext4 File System Image | ext4-filesystem |
.img |
Raw Partitioned Disk Image | partitioned-disk |
.img |
Live Bootable ISO | live-iso |
.iso |
TAR Archive | tar |
.tar |
Amazon Machine Image Disk | ami |
.ami |
Azure Disk Image | vhd |
.vhd |
VMware Virtual Machine Disk | vmdk |
.vmdk |
Openstack | openstack |
.qcow2 |
Step 1: Install Image Builder packages
Before you can use Image Builder, the following packages need to be installed.
sudo yum -y install vim lorax-composer composer-cli cockpit-composer bash-completion
Enable Image Builder to start after each reboot:
sudo systemctl enable --now lorax-composer.socket
For UI access via Cockpit, enable it:
sudo systemctl enable --now cockpit.socket
sudo firewall-cmd --add-service=cockpit && sudo firewall-cmd --add-service=cockpit --permanent
Load the shell configuration script so that the autocomplete feature for the composer-cli command starts working immediately without reboot:
source /etc/bash_completion.d/composer-cli
Step 2: Create Blueprint for Image Builder
We’ll use command line interface for this operation. But the same can be done from Cockpit web console. To use the interface, run the composer-cli command with suitable options and arguments.
This is the workflow Image Builder:
- Export (save) the blueprint definition to a plain text file
- Edit this file in a text editor
- Import (push) the blueprint text file back into Image Builder
- Run a compose to build an image from the blueprint
- Export the image file to download it
Add your $USER to the weldr group.
sudo usermod -aG weldr $USER
newgrp weldr
Creating an Image Builder blueprint:
$ vim rhel8-base.toml
Mine has been modified to look like below:
name = "rhel-8-base"
description = "A RHEL 8 Base Image"
version = "0.0.1"
groups = []
[[modules]]
name = "vim"
version = "*"
[[packages]]
name = "openssh-server"
version = "*"
[[packages]]
name = "rsync"
version = "*"
[[packages]]
name = "tmux"
version = "*"
[[packages]]
name = "git"
version = "*"
[[packages]]
name = "tree"
version = "*"
[[packages]]
name = "bash-completion"
version = "*"
[[packages]]
name = "lvm2"
version = "*"
[[packages]]
name = "wget"
version = "*"
[[packages]]
name = "firewalld"
version = "*"
[[packages]]
name = "python3"
version = "*"
[[packages]]
name = "python3-pip"
version = "*"
[[packages]]
name = "telnet"
version = "*"
[customizations.kernel]
append = "net.ifnames=0"
[[customizations.user]]
name = "rheladmin"
description = " RHEL Admin User"
password = "hashed-user-password"
key = "your-ssh-pub-key"
home = "https://computingforgeeks.com/home/rheladmin/"
shell = "https://computingforgeeks.com/usr/bin/bash"
groups = ["users", "wheel"]
Check documentation page for all entries and customizations.
Push the blueprint back into Image Builder:
$ composer-cli blueprints push rhel8-base.toml
List available Image builders:
$ composer-cli blueprints list
example-atlas
example-development
example-http-server
rhel-8-base
Step 3: Create a system image with Image Builder
Pass the start option to build the image for your CentOS / RHEL machine.
$ composer-cli compose start BLUEPRINT-NAME IMAGE-TYPE
To see available image types, run:
$ composer-cli compose types
alibaba
ami
ext4-filesystem
google
live-iso
openstack
partitioned-disk
qcow2
tar
vhd
vmdk
So I’ll now start a compose using the blueprint created and output type.
$ composer-cli compose start rhel-8-base ami
Compose 036fb329-0443-48ad-9444-a1c70caa4b36 added to the queue
To check the status of the compose:
$ composer-cli compose status
036fb329-0443-48ad-9444-a1c70caa4b36 RUNNING Sat Apr 4 15:41:12 2020 rhel-8-base 0.0.1 ami
$ composer-cli compose status
036fb329-0443-48ad-9444-a1c70caa4b36 FINISHED Sat Apr 4 15:46:52 2020 rhel-8-base 0.0.1 ami 4668260352
Once the compose is finished, download the resulting image file:
$ composer-cli compose image UUID
-- Example ---
$ composer-cli compose image 036fb329-0443-48ad-9444-a1c70caa4b36
036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami: 4452.00 MB
Step 4: Upload AMI Image to AWS
Install Python 3 and the pip tool:
sudo yum -y install python3 python3-pip
Install the AWS command-line tools with pip:
sudo pip3 install awscli
Configure the AWS command-line client according to your AWS access details:
$ aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]:
Default output format [None]:
Configure the AWS command-line client to use your bucket:
$ BUCKET=ami-image-bucket
$ aws s3 mb s3://$BUCKET
Confirm bucket creation:
$ aws s3 ls
2020-04-04 15:49:47 ami-image-bucket
Create a vmimport S3 Role in IAM and grant it permissions to access S3:
printf '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "vmie.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals":{ "sts:Externalid": "vmimport" } } } ] }' > trust-policy.json
printf '{ "Version":"2012-10-17", "Statement":[ { "Effect":"Allow", "Action":[ "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket" ], "Resource":[ "arn:aws:s3:::%s", "arn:aws:s3:::%s/*" ] }, { "Effect":"Allow", "Action":[ "ec2:ModifySnapshotAttribute", "ec2:CopySnapshot", "ec2:RegisterImage", "ec2:Describe*" ], "Resource":"*" } ] }' $BUCKET $BUCKET > role-policy.json
aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json
aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document file://role-policy.json
Uploading an AMI image to AWS:
$ BUCKET=ami-image-bucket
$ AMI=036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami
$ aws s3 cp $AMI s3://$BUCKET
upload: ./036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami to s3://ami-image-bucket/036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami
After the upload to S3 ends, import the image as a snapshot into EC2:
printf '{ "Description": "my-image", "Format": "raw", "UserBucket": { "S3Bucket": "%s", "S3Key": "%s" } }' $BUCKET $AMI > containers.json
aws ec2 import-snapshot --disk-container file://containers.json
Sample output:
{
"ImportTaskId": "import-snap-0617ccf6944d82089",
"SnapshotTaskDetail": {
"DiskImageSize": 0.0,
"Format": "RAW",
"Progress": "3",
"Status": "active",
"StatusMessage": "pending",
"UserBucket": {
"S3Bucket": "ami-image-bucket",
"S3Key": "036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami"
}
}
}
Confirm import process:
$ aws ec2 describe-import-snapshot-tasks --filters Name=task-state,Values=active
{
"ImportSnapshotTasks": [
{
"ImportTaskId": "import-snap-0617ccf6944d82089",
"SnapshotTaskDetail": {
"DiskImageSize": 4668260352.0,
"Format": "RAW",
"Progress": "94",
"SnapshotId": "snap-0fd61ffa2f2cd4ad0",
"Status": "active",
"StatusMessage": "Preparing snapshot",
"UserBucket": {
"S3Bucket": "ami-image-bucket",
"S3Key": "036fb329-0443-48ad-9444-a1c70caa4b36-disk.ami"
}
},
"Tags": []
}
]
}
Login to AWS and confirm existence of Snapshot.
Create an image from the uploaded snapshot right clicking Snapshot on EC2 and selecting Create Image:
Give Image a name and set virtualization type, disk size, description e.t.c.
After creation, the image will be available on the AMI section.
Reference:
- CentOS Composer page
- Weldr documentation
Similar guides: