xref: /cloud-hypervisor/docs/custom-image.md (revision b440cb7d2330770cd415b63544a371d4caa2db3a)
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