1# How to create a custom Ubuntu image 2 3In the context of adding more utilities to the Ubuntu cloud image being used 4for integration testing, this quick guide details how to achieve the proper 5modification of an official Ubuntu cloud image. 6 7## Create the image 8 9Let's go through the steps on how to extend an official Ubuntu image. These 10steps can be applied to other distributions (with a few changes regarding 11package management). 12 13### Get latest Ubuntu cloud image 14 15```bash 16wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img 17``` 18 19### Check the file format is QCOW2 20 21```bash 22file focal-server-cloudimg-amd64.img 23focal-server-cloudimg-amd64.img: QEMU QCOW2 Image (v2), 2361393152 bytes 24``` 25 26### Convert QCOW2 into RAW 27 28```bash 29qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw 30``` 31 32### Identify the Linux partition 33 34The goal is to mount the image rootfs so that it can be modified as needed. 35That's why we need to identify where the Linux filesystem partition is located 36in the image. 37 38```bash 39sudo fdisk -l focal-server-cloudimg-amd64.raw 40Disk focal-server-cloudimg-amd64.raw: 2.2 GiB, 2361393152 bytes, 4612096 sectors 41Units: sectors of 1 * 512 = 512 bytes 42Sector size (logical/physical): 512 bytes / 512 bytes 43I/O size (minimum/optimal): 512 bytes / 512 bytes 44Disklabel type: gpt 45Disk identifier: A1171ABA-2BEA-4218-A467-1B2B607E5953 46 47Device Start End Sectors Size Type 48focal-server-cloudimg-amd64.raw1 227328 4612062 4384735 2.1G Linux filesystem 49focal-server-cloudimg-amd64.raw14 2048 10239 8192 4M BIOS boot 50focal-server-cloudimg-amd64.raw15 10240 227327 217088 106M EFI System 51 52Partition table entries are not in disk order. 53``` 54 55### Mount the Linux partition 56 57```bash 58mkdir -p /mnt 59sudo mount -o loop,offset=$((227328 * 512)) focal-server-cloudimg-amd64.raw /mnt 60``` 61 62### Set up DNS 63 64The next step describes changing the root directory to the rootfs contained by 65the cloud image. For DNS to work in the root directory, you will need to first bind-mount 66the host `/etc/resolv.conf` onto the mounted linux partition of the cloud image. 67 68```bash 69sudo mount -o bind /etc/resolv.conf /mnt/etc/resolv.conf 70``` 71 72### Change root directory 73 74Changing the root directory will allow us to install new packages to the rootfs 75contained by the cloud image. 76 77```bash 78sudo chroot /mnt 79mount -t proc proc /proc 80mount -t devpts devpts /dev/pts 81``` 82 83### Install needed packages 84 85In the context Cloud Hypervisor's integration tests, we need several utilities. 86Here is the way to install them for a Ubuntu image. This step is specific to 87Ubuntu distributions. 88 89```bash 90apt update 91apt install fio iperf iperf3 socat stress 92``` 93 94### Remove counterproductive packages 95 96* snapd: 97 98This prevents snapd from trying to mount squashfs filesystem when the kernel 99might not support it. This might be the case when the image is used with direct 100kernel boot. This step is specific to Ubuntu distributions. 101 102* pollinate: 103 104Remove this package which can fail and lead to the SSH daemon failing to start. 105See #2113 for details. 106 107```bash 108apt remove --purge snapd pollinate 109``` 110 111 112### Cleanup the image 113 114Leave no trace in the image before unmounting its content. 115 116```bash 117umount /dev/pts 118umount /proc 119history -c 120exit 121umount /mnt/etc/resolv.conf 122umount /mnt 123``` 124 125### Rename the image 126 127Renaming is important to identify this is a modified image. 128 129```bash 130mv focal-server-cloudimg-amd64.raw focal-server-cloudimg-amd64-custom-$(date "+%Y%m%d")-0.raw 131``` 132 133The `-0` is the revision and is only necessary to change if multiple images are 134updated on the same day. 135 136### Create QCOW2 from RAW 137 138Last step is to create the QCOW2 image back from the modified image. 139 140```bash 141qemu-img convert -p -f raw -O qcow2 focal-server-cloudimg-amd64-custom-$(date "+%Y%m%d")-0.raw focal-server-cloudimg-amd64-custom-$(date "+%Y%m%d")-0.qcow2 142``` 143 144## Switch CI to use the new image 145 146### Upload to Azure storage 147 148The next step is to update both images (QCOW2 and RAW) stored as part of the 149Azure storage account, replacing them with the newly created ones. This will 150make these new images available from the integration tests. This is usually 151achieved through the web interface. 152 153### Update integration tests 154 155Last step is about updating the integration tests to work with this new image. 156The key point is to identify where the Linux filesystem partition is located, 157as we might need to update the direct kernel boot command line, replacing 158`/dev/vda1` with the appropriate partition number. 159 160Update all references to the previous image name to the new one. 161