Creating your own image with pure CentOS 8.1 in the Amazon cloud

This guide is a "fork" of the eponymous Articles about CentOS 5.9, and takes into account the features of the new OS. There is currently no official Centos8 image from centos.org in AWS Marketplace.

As you know, in the Amazon cloud, virtual instances are launched based on images (the so-called AMI). Amazon provides a large number of them, you can also use public images prepared by third parties, for which the cloud provider, of course, does not bear any responsibility. But sometimes you need an image of a clean system with the right parameters, which is not in the list of images.

Then the only way out is to make your own AMI.

The official documentation describes way creating an "instance store-backed AMI".

The disadvantage of this approach is that the finished image will also need to be converted into an β€œEBS-backed AMI”. Also worth noting is the Cockpit Image Builder. It will allow you to create custom images, in CLI or WEB GUI mode, but when you already have Centos 8.

How to create your own EBS-backed AMI in the Amazon cloud without intermediate steps will be discussed in this article.

Action plan

  • Prepare environment
  • Install a clean system, make the necessary settings
  • Take a snapshot of the disk
  • Register AMI

Preparing the Environment

For our purposes, any official Centos 7 instance any shape, even t2.micro. You can start it via CLI:

aws ec2 run-instances 
  --image-id ami-4bf3d731 
  --region us-east-1 
  --key-name alpha 
  --instance-type t2.micro 
  --subnet-id subnet-240a8618 
  --associate-public-ip-address 
  --block-device-mappings DeviceName=/dev/sda1,Ebs={VolumeSize=8} 
  --block-device-mappings DeviceName=/dev/sdb,Ebs={VolumeSize=4}

The command will raise an instance in the VPC to which the specified subnet-id belongs. The subnet is supposed to be public and SG 'default' allows everything.

Now log in to the instance via ssh, update the system, install dnf and reboot:

sudo yum update -y && sudo yum install -y dnf && sudo reboot

All further operations will be performed from root.

Installing clean Centos 8.1

File system layout and partition mounting

DEVICE=/dev/xvdb
ROOTFS=/rootfs
parted -s ${DEVICE} mktable gpt
parted -s ${DEVICE} mkpart primary ext2 1 2
parted -s ${DEVICE} set 1 bios_grub on
parted -s ${DEVICE} mkpart primary xfs 2 100%

mkfs.xfs -L root ${DEVICE}2
mkdir -p $ROOTFS
mount ${DEVICE}2 $ROOTFS

mkdir $ROOTFS/{proc,sys,dev,run}
mount --bind /proc $ROOTFS/proc
mount --bind /sys $ROOTFS/sys
mount --bind /dev $ROOTFS/dev
mount --bind /run $ROOTFS/run

Creating a directory tree

The RPM system allows you to easily and quickly prepare the directory tree of the future OS:

PKGSURL=http://mirror.centos.org/centos/8/BaseOS/x86_64/os/Packages
rpm --root=$ROOTFS --initdb
rpm --root=$ROOTFS -ivh 
  $PKGSURL/centos-release-8.1-1.1911.0.8.el8.x86_64.rpm 
  $PKGSURL/centos-gpg-keys-8.1-1.1911.0.8.el8.noarch.rpm 
  $PKGSURL/centos-repos-8.1-1.1911.0.8.el8.x86_64.rpm

dnf --installroot=$ROOTFS --nogpgcheck --setopt=install_weak_deps=False 
   -y install audit authselect basesystem bash biosdevname coreutils 
   cronie curl dnf dnf-plugins-core dnf-plugin-spacewalk dracut-config-generic 
   dracut-config-rescue e2fsprogs filesystem firewalld glibc grub2 grubby hostname 
   initscripts iproute iprutils iputils irqbalance kbd kernel kernel-tools 
   kexec-tools less linux-firmware lshw lsscsi ncurses network-scripts 
   openssh-clients openssh-server passwd plymouth policycoreutils prefixdevname 
   procps-ng  rng-tools rootfiles rpm rsyslog selinux-policy-targeted setup 
   shadow-utils sssd-kcm sudo systemd util-linux vim-minimal xfsprogs 
   chrony cloud-init 

I consider the last command to be optimally performed in this way, installing specific packages, and be sure to ignore the recommended packages.

If you wish, you can use something like this:

dnf --installroot=$ROOTFS groupinstall base core 
    --excludepkgs "NetworkManager*" 
     -e "i*-firmware"

Π’ yum no --excludepkgs, and before you had to install groups, and then remove packages.

The list of packages and dependent groups can be viewed with the command dnf group info core for the group core.

OS file customization

Let's create configs for network, fstab, grub2 and use AWS internal 169.254 addresses for DNS and NTP.

cat > $ROOTFS/etc/resolv.conf << HABR
nameserver 169.254.169.253
HABR

cat > $ROOTFS/etc/sysconfig/network << HABR
NETWORKING=yes
NOZEROCONF=yes
HABR

cat > $ROOTFS/etc/sysconfig/network-scripts/ifcfg-eth0  << HABR
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=dhcp
HABR

cat > $ROOTFS/etc/fstab << HABR
LABEL=root / xfs defaults,relatime 1 1
HABR

sed -i  "s/cloud-user/centos/" $ROOTFS/etc/cloud/cloud.cfg
echo "server 169.254.169.123 prefer iburst minpoll 4 maxpoll 4" >> $ROOTFS/etc/chrony.conf
sed -i "/^pool /d" $ROOTFS/etc/chrony.conf
sed -i "s/^AcceptEnv/# /" $ROOTFS/etc/ssh/sshd_config

cat > $ROOTFS/etc/default/grub << HABR
GRUB_TIMEOUT=1
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto console=ttyS0,115200n8 console=tty0 net.ifnames=0 biosdevname=0"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
HABR

It is here, in GRUB_CMDLINE_LINUX, that I recommend specifying selinux=0, for those who are still afraid of SELinux.

Rebuilding initramfs in chroot

After editing the grub and fstab files, you need to rebuild.
Performing an update:

KERNEL=$(ls $ROOTFS/lib/modules/) 
chroot $ROOTFS dracut -f -v /boot/initramfs-$KERNEL.img $KERNEL
chroot $ROOTFS grub2-mkconfig -o /boot/grub2/grub.cfg
chroot $ROOTFS grub2-install $DEVICE
chroot $ROOTFS update-crypto-policies --set FUTURE

Here update-crypto-policies - optional, for the paranoid πŸ™‚

For "sell", you can do this:

chroot $ROOTFS fips-mode-setup --enable
chroot $ROOTFS grub2-mkconfig -o /boot/grub2/grub.cfg
chroot $ROOTFS grub2-install $DEVICE

After booting the OS, the command update-crypto-policies --show will issue FIPS.

Autorun and Garbage Cleanup

chroot $ROOTFS systemctl enable network.service
chroot $ROOTFS systemctl enable sshd.service
chroot $ROOTFS systemctl enable cloud-init.service
chroot $ROOTFS systemctl mask tmp.mount
dnf --installroot=$ROOTFS clean all
truncate -c -s 0 $ROOTFS/var/log/*.log
rm -rf var/lib/dnf/*
touch $ROOTFS/.autorelabel

autorelabel - Needed to automatically install the SELinux file context on first boot.

Now let's unmount the drive:

sync
umount $ROOTFS/{proc,sys,dev,run}
umount $ROOTFS

AMI Registration

To get ami from an ebs disk, you must first take a snapshot of the disk:

aws ec2 create-snapshot 
    --volume-id vol-09f26eba4c50da110  --region us-east-1 
    --description 'centos-release-8.1-1.1911.0.8 4.18.0-147.5.1 01'

Some time will have to wait. Let's check the status by the received SnapshotId:

aws ec2   describe-snapshots  --region us-east-1 --snapshot-ids snap-0b665542fc59e58ed

When we get "State": "completed", you can register an AMI and make it public:

aws ec2 register-image 
    --region us-east-1 
    --name 'CentOS-8.1-1.1911.0.8-minimal' 
    --description 'centos-release-8.1-1.1911.0.8 4.18.0-147.5.1 01' 
    --virtualization-type hvm --root-device-name /dev/sda1 
    --block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs": { "SnapshotId": "snap-0b665542fc59e58ed", "VolumeSize":4,  "DeleteOnTermination": true, "VolumeType": "gp2"}}]' 
    --architecture x86_64 --sriov-net-support simple --ena-support

aws ec2 modify-image-attribute 
    --region us-east-1 
    --image-id ami-011ed2a37dc89e206 
    --launch-permission 'Add=[{Group=all}]'

That's all. Now you can launch instances.

In this way, you can make an image, most likely with any Linux distribution. At least for sure Debian (using debootstrap to install a clean system) and the RHEL family.

UPDATED At the request of readers. This process can be automated Packer, only Automate. Here an example template is provided.

Source: habr.com

Add a comment