Amazon Web Services recently enabled the Sydney region, allowing our company to finally make the decision to use it. However, when preparing to launch the first EC2 instance, we found that there were no official CentOS AMIs (Amazon Machine Images) available for selection, only third-party community-made AMIs. For us, who are particular about system purity, using third-party images is not reassuring. Therefore, my task this time was to create my own AMI. To create a custom AMI, I used two methods: one was to package an existing system into an image and upload it; the other was to create a new image on the existing system and upload it, which AWS officially refers to as ‘Creating an Instance Store-Backed AMI From a Loopback‘. Unfortunately, although both methods allowed the EC2 to run successfully, the kernel would change upon startup. As of writing this article, I haven’t found a solution, so I’m recording this experience.
1. Convert Existing System and Upload
This method involves compressing the system on the VM into an image using Amazon’s command-line tools and uploading it to S3, then registering it as an AMI. The specific steps are as follows:
1. Install ec2-ami-tools and ec2-api-tools
Install ec2-ami-tools using the following command:
|
1
|
yum install http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm
|
For ec2-api-tools, please refer to the official documentation for installation: ‘Setting Up the Amazon EC2 Command Line Tools‘
2. Modify System Configuration
First, remove the HWADDRESS from ifcfg-eth0 and add “NM_Controlled no”. Then, install cloud-init (using yum directly) and modify the configuration according to the official guidelines.
3. Obtain Keys and Package
In the AWS console, under ‘Security Credentials’ in your account, find ‘X.509’, generate key.pem and cert.pem, and then use the following command to generate and package the image file:
|
1
|
ec2-bundle-vol -c cert.pem -k pk.pem -u <account-id> -d /image -e /image -r x86_64 –no-inherit
|
Here, is your account ID, -d specifies the directory where the image will be placed, and -e represents directories to ignore—you must include this, otherwise it will cause an infinite loop.
4. Upload
Find your Access Key ID and Secret Access Key under ‘Access Keys’ in your account, and then use the following command to upload to S3:
|
1
|
ec2-upload-bundle -b <bucket name> -m /image/image.manifest.xml -a <access id> -s <secret access id>
|
5. Register AMI
|
1
2
3
4
5
6
7
|
Set variables to run ec2-register directly
export EC2_HOME=/usr/local/ec2/ec2-api/
export PATH=$PATH:$EC2_HOME/bin
export AWS_ACCESS_KEY=&lt;access key>
export AWS_SECRET_KEY=&lt;secret key>
ec2-register <bucket name>/image.manifest.xml –region ap-southeast-2
|
Here, you must use –region to specify the region to upload to. ap-southeast-2 indicates the Sydney region.
2. Create New System on Existing Environment and Upload
The principle behind this method is: first, create an image file on the original system, then mount it to a directory, use yum groupinstall Base to install the system into that image file, and finally package and upload the file. You can refer to the following articles for installing a system within an image file: ‘Create your own CentOS AMI Image (S3 Backed)‘, ‘Build your own Core CentOS 5.x AMI for Amazon EC2‘
The packaging and uploading commands are as follows:
|
1
2
3
4
5
6
7
8
|
Package
–image specifies the location of the image file
–destination specifies the location of the packaged files
ec2-bundle-image –image /image/ami-centos5.8-64bit-base-img –prefix ami-centos5.8-64bit-base –cert cert-.pem –privatekey pk.pem –user <account-id> –destination /home/public
/EC2AMIFILES –arch x86_64
Upload
ec2-upload-bundle -b crazysalesamistore -m /home/public/EC2AMIFILES/ami-centos5.8-64bit-base.manifest.xml -a <access-key> -s <secret-key>
|
After uploading, you can register the AMI using the first method, or use the graphical interface in the AWS console to register it.
Creating a CentOS6 AMI without Marketplace Code in AWS EC2
References:
https://www.caseylabs.com/remove-the-aws-marketplace-code-from-a-centos-ami/
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/storage_expand_partition.html
Background:
In AWS EC2, you can conveniently select the latest official CentOS6 Minimal version AMI from the Marketplace to create an Instance.
However, there is a major pitfall here: all Instances created based on AMIs from the Marketplace will carry a Marketplace code.
This prevents you from expanding the root partition by creating Snapshots and new Volumes for the existing EBS Volume hosting the root partition.
After detaching the Volume hosting the current root partition, you cannot reattach it to the Instance. When attaching a new Volume, you will encounter the same error:
Client.OperationNotPermitted: 'vol-xxxxxxx' with Marketplace codes may not be attached as a secondary device.
As the name suggests, this Marketplace code is intended to protect paid AMIs from being cloned arbitrarily, but it is unclear why separate handling was not implemented for the $0 CentOS6 AMI.
The above limitation mainly affects the default CentOS6 Instance, where the EBS Volume for the root partition is only 8GB. Even if you specify a 50GB EBS Volume during creation, the resulting root partition space will only be 8GB. This size is insufficient for production needs, requiring expansion. However, due to the Marketplace code restriction, expansion becomes difficult.
Fortunately, by referring to the two articles mentioned above, I removed the Marketplace code from the official CentOS6 AMI and successfully expanded the root partition and created the corresponding AMI.
Specific Steps:
1. Remove Marketplace Code from Existing CentOS6 AMI
1.1 Search for CentOS6 AMI in the AWS Marketplace and create an Instance with a root partition EBS Volume of 8GB (default size);
1.2 In the AWS EC2 web console, create a new 8GB EBS Volume;
1.3 Attach the newly created EBS Volume to the Instance. It is usually identified as /dev/xvdj by default (HVM version AMIs identify it as /dev/xvdf);
1.4 SSH into the Instance and clone the EBS Volume hosting the root partition using dd (HVM version AMIs identify the EBS Volume hosting the root directory as /dev/xvda):
dd bs=65536 if=/dev/xvde of=/dev/xvdj
1.5 Once cloning is complete, shut down the Instance;
1.6 Detach the EBS Volume hosting the current root partition;
1.7 Detach the newly created EBS Volume and reattach it to the Instance as /dev/sda (HVM version AMIs need to specify /dev/sda1);
1.8 Start the Instance;
1.9 After confirming the Instance starts normally, right-click the Instance in the EC2 web console and select ‘Create Image’ to create a new CentOS6 AMI without Marketplace code. I usually name it official_centos6_x86_64_minimal_ebs8g.
2. Expand the EBS Volume Hosting the Root Partition of the Existing AMI to 50GB and Create a New AMI official_centos6_x86_64_minimal_ebs50g
2.1 Create an Instance based on the AMI official_centos6_x86_64_minimal_ebs8g;
2.2 Create a Snapshot of the EBS Volume hosting the Instance;
2.3 Create a new 50GB Volume containing the just-created Snapshot;
2.4 Attach the newly created Volume to the Instance as the second EBS Volume. It is usually identified as /dev/xvdj by default (HVM version AMIs identify it as /dev/xvdf);
2.5 Expand the second EBS Volume on the Instance. Detailed steps are as follows (HVM version AMIs identify the EBS Volume hosting the root directory as /dev/xvda):
[root@ip-172-17-4-12 ~]# parted /dev/xvdj GNU Parted 2.1 Using /dev/xvdj Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) unit s (parted) print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdj: 104857600s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 16777215s 16775168s primary ext4 boot (parted) rm 1 (parted) mkpart primary 2048s 100% (parted) print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdj: 104857600s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 104857599s 104855552s primary ext4 (parted) set 1 boot on (parted) print Model: Xen Virtual Block Device (xvd) Disk /dev/xvdj: 104857600s Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 2048s 104857599s 104855552s primary ext4 boot (parted) quit Information: You may need to update /etc/fstab. [root@ip-172-17-4-12 ~]# e2fsck -f /dev/xvdj1 e2fsck 1.41.12 (17-May-2010) Superblock needs_recovery flag is clear, but journal has data. Run journal anyway<y>? yes /dev/xvdj1: recovering journal Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/xvdj1: ***** FILE SYSTEM WAS MODIFIED ***** /dev/xvdj1: 18425/524288 files (0.2% non-contiguous), 243772/2096896 blocks [root@ip-172-17-4-12 ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvde 202:0 0 8G 0 disk └─xvde1 202:1 0 8G 0 part / xvdj 202:80 0 50G 0 disk └─xvdj1 202: 0 50G 0 part [root@ip-172-17-4-12 ~]# resize2fs /dev/xvdj1 resize2fs 1.41.12 (17-May-2010) Resizing the filesystem on /dev/xvdj1 to 13106944 (4k) blocks. The filesystem on /dev/xvdj1 is now 13106944 blocks long.
2.6 Shut down the Instance;
2.7 Detach the EBS Volume hosting the current root partition;
2.8 Detach the expanded second EBS Volume and reattach it to the Instance as /dev/sda (HVM version AMIs need to specify /dev/sda1);
2.9 Start the Instance;
2.10 After confirming the Instance starts normally, right-click the Instance in the EC2 web console and select ‘Create Image’ to create a new CentOS6 AMI with a root partition size of 50GB. I usually name it official_centos6_x86_64_minimal_ebs50g.
PS: If you want your custom image to support specifying a custom SSH Public Key at creation time, ensure that /etc/rc.local contains the following code, and delete the /root/.ssh/authorized_keys file from the image.
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
# set a random pass on first boot
if [ -f /root/firstrun ]; then
dd if=/dev/urandom count=50|md5sum|passwd --stdin root
passwd -l root
rm /root/firstrun
fi
if [ ! -d /root/.ssh ]; then
mkdir -m 0700 -p /root/.ssh
restorecon /root/.ssh
fi
# Get the root ssh key setup
ReTry=0
while [ ! -f /root/.ssh/authorized_keys ] && [ $ReTry -lt 10 ]; do
sleep 2
curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/.ssh/pubkey
if [ 0 -eq 0 ]; then
mv /root/.ssh/pubkey /root/.ssh/authorized_keys
fi
ReTry=$[Retry+1]
done
chmod 600 /root/.ssh/authorized_keys && restorecon /root/.ssh/authorized_keys
Creating Your Own AMI
Some AMIs provided in the Amazon AMI Marketplace contain Market Codes (which prevent the root partition from being mounted as a secondary partition on another instance to modify root partition content). Some AMIs do not support specific instance types (for example, AMIs provided by CentOS.org do not support c3 series). Therefore, it is necessary to create your own AMIs. The creation methods and steps are as follows:
(1) Install a minimal version of CentOS in a suitable location. Try to keep the installation as minimal as possible because you will sync all system file contents to Amazon later. You can also directly import the virtual machine into AWS. During installation, use /dev/sda1 for the root partition and /dev/sda1 swap partition. Do not use LVM. In the example, we create a 1GB VMware disk. Do not use dynamic extension; try to use one-time allocation. Then partition /dev/sda1 with 768M, and allocate the remaining MB entirely to swap. The size must be a power of 2, otherwise, you might see warnings like ‘partition doesn’t end with disk boundry’.
(2) The second step is to get the system content onto AWS. Here are two solutions:
First, on a machine configured with AWS tools (recommended: an EC2 created from an Amazon AMI), create a 25GB EBS volume, attach it, format the partitions (17GB /, 8GB swap, precise to MB), and then
mkfs.ext4 /dev/xvdj1; e2label /dev/xvdj1 / (set label); mkswap -L swap /dev/xvdj2(also set label), # then mount mount /dev/xvdj1 /ebs(create your own mount point)
Use rsync to sync the file system of the just-installed virtual machine to the above mount point:
rsync -avx -e "ssh -i xxxxx.pem" /* user@ip:/ebs/
Use the ec2-import-volume command to import the virtual machine disk into an EBS disk in AWS. The command is as follows:
ec2-import-volume centos6.5.disk -f raw -b <your_s3_bucket_name> --region ap-southeast-1 -O <access_key_id> -W <secret_access_key> -o <access_key_id> -w <secret_access_key>
-f specifies the format: kvm, xen are raw, vmware is vmdk, hyper-v is vhd (vhdx format is not currently supported, needs conversion to vhd format), -b specifies the s3 bucket consistent with the import region, because this process goes through S3. Then you will get a disk, attach it to the EC2 of the aforementioned Amazon AMI, and copy the content out.
(3) Enter /ebs to modify the file system you just synced.
Check /etc/grub.conf. By default, it uses UUID to specify partitions, but the copied VM UUIDs are different, so change them to LABEL format, as follows:
default=0 timeout=5 splashimage=(hd0,0)/boot/grub/splash.xpm.gz hiddenmenu title CentOS (2.6.32-358.el6.x86_64) root (hd0,0) kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=LABEL=/ console=ttyS0 initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
Modify /etc/sysconfig/network-scripts/ifcfg-eth0 (note: only one network card when installing the virtual machine), change it to the following:
DEVICE=eth0 BOOTPROTO=dhcp ONBOOT=yes
Modify /etc/fatab, change to use LABEL mounting, as follows: (keep defaults for lines starting with none):
LABEL=/ / ext4 defaults 1 1 LABEL=swap swap swap defaults 0 0
(4) Make a snapshot of the modified EBS disk and obtain the snapshot ID for later use.
(5) Use the ec2-register command on the work machine to register the AMI:
ec2-register -n "CentOS6.4" -d "CentOS6.4" -a x86_64 -K pk-xxxxxx.pem -C cert-mod.pem --root-device-name /dev/sda1 -b /dev/sda=snap-a40edf49:25:true --kernel aki-503e7402 --region ap-southeast-1
This step requires your account’s X.509 Certificates key pair (found in security credentials) and the kernel ID. For details on which AKI to use, see this official documentation link:
AmazonKernelImageIDs
(6) Try creating an instance based on your custom AMI, customize it inside, and then right-click the instance to register it as your personalized AMI (I usually install CloudWatch and write a README saying this AMI was made by me, don’t delete Cloudwatch).
Done.
Importing Virtual Machines to AWS
With ec2-import-instance, we can import our virtual machines into EC2 instances in AWS.
~$ ec2-import-instance centos6.4-vm01.disk -f raw -p Linux -t m3.large -a x86_64 -b <your_s3_bucket> --region ap-southeast-1 -O <access_key_id> -W <secret_access_key> -o <access_key_id> -w <secret_access_key>
(Parentheses for multiple letters indicate double dashes, I don’t know why mine always shows as multiple -, regardless of how many -. For example, the –region parameter. Note the same applies below.)
Then you can use the ec2-describe-conversion-tasks command to view the import process. Use the ec2-cancel-conversion-task command to cancel the import task.
~$ ec2-describe-conversion-tasks --region ap-southeast-1 import-i-ffm0xv71 -O xxxx -W
xxxxx (import-i-ffm0xv71 is the task ID of the ec2-import-instance task, shown in the command output results)
If everything goes smoothly, you will get an EC2 instance in the specified region, which is off by default.
During this process, pay attention to the following points:
When importing a virtual machine, the virtual machine only supports one DHCP network card. Delete multiple network cards. The CD-ROM can be deleted (at least it shouldn’t be mounted with an ISO state during import). If there are multiple disks, this command can only import the virtual disk hosting the root partition (note: not the partition hosting the root partition). Other disks should be imported using the ec2-import-volume command introduced below.
The configuration type of the imported virtual machine is limited (Linux virtual machines have limitations, Windows virtual machines have no limitations).
We support importing Windows instances into any instance type. Linux instances can be imported into the following instance types: m3.xlarge, m3.2xlarge, hi1.4xlarge, hs1.8xlarge, cc1.4xlarge, cg1.4xlarge, cc2.8xlarge, cr1.8xlarge.
If you right-click the imported virtual machine to register it as an AMI (if you use the default AKI), it will result in your AMI only being able to create specific types of EC2 instances. You need to choose the appropriate AKI, see the sharing link in the previous document.
Use ec2-import-volume to import virtual machine disks to AWS EBS:
~$ ec2-import-volume centos6.4.disk -f raw -b <your-s3-bucket> --region ap-southeast-1 -O xxxx -W xxxxxxxx -o xxxx -w xxxxxx
Use ec2-describe-conversion-tasks to view the import progress. After completion, you will get an EBS Volume with a status of Available.