Building a custom Fedora image to run on Google Compute Engine

Thankfully the Fedora Project provides cloud images that can be directly used or easily modified to run on almost any cloud environment. Though sometimes, it can be handy to build your own image.

0. Prerequisites

Fedora images in general and the cloud images especially are built using ImageFactory which itself uses Oz. The latest versions can always be found on koji. To recreate an image locally, there are a couple of tools needed:

dnf install imagefactory imagefactory-plugins* pykickstart

1. Kickstart and template

To build an image with ImageFactory, you’ll need two files: a kickstart file and an imagefactory template.

The kickstart files for the (official) Fedora images are part of the fedora-kickstarts package and be installed locally with dnf

dnf install fedora-kickstarts

of pulled from the fedora-kickstarts git repository at

The template file is an xml decription of what to build (OS version, architecture, etc.). A sample template file can be seen below:

        <install type='url'>

The template file can either have an .xml or a .tdl extension and is usually automatically generated by the koji build deamon (see and

2. Modifying Oz default config

ImageFactory will create a temporary virtual machine that’s used to install Fedora into a raw disk file. Depending on the package selection you might need more that 1GB of RAM which is the Oz default on Fedora. To modify the memory limit, change the memory parameter in the Oz configuration file

uri = qemu:///system
image_type = raw
# type = kvm
# bridge_name = virbr0
# cpus = 1
memory = 2048

You can either use your favourite editor or run

sed -i -e 's/# memory = 1024/memory = 2048/' /etc/oz/oz.cfg

3. Building a raw disk image

Now it’s time to build the actual image. Since the kickstart file might be hierarchical, i.e. contain %include statements to point to user kickstart files, we need to create a ‘flat’ version first:

tempfile=$(mktemp --suffix=.ks)
ksflatten -v F27 -c /usr/share/spin-kickstarts/fedora-cloud-base.ks > ${tempfile}

Of course, the kickstart file can be customized first.

To build the image, run

imagefactory base_image \
  --file-parameter install_script ${tempfile} fedora-cloud-custom.tdl \
  --parameter offline_icicle true

The offline_icicle parameter is necessary to tell Oz that it should rather mount the disk image and chroot into it instead of spawning a temporary throwaway VM and ssh-ing into it to run RPM commands.

After a short while ImageFactory will print the UUID of the created image:

============ Final Image Details ============
UUID: 925b9ac8-7dca-4a9f-b055-330b23e45923
Type: base_image
Image filename: /var/lib/imagefactory/storage/925b9ac8-7dca-4a9f-b055-330b23e45923.body
Image build completed SUCCESSFULLY!

4. Creating a Google Compute Engine image

There is a GCE plugin for ImageFactory that allows you to easily package the created raw disk image:

imagefactory target_image --id <UUID> gce

Unfortunately, that plugin is not packaged for Fedora yet, so this needs to be done manually. Looking at the plugin source code, we’ll have to reproduce what the builder_did_create_target_image function does:

qemu-img convert -O raw \
  /var/lib/imagefactory/storage/925b9ac8-7dca-4a9f-b055-330b23e45923.body \
tar cfz fedora-cloud-custom.tar.gz \
  /var/lib/imagefactory/storage/80e6d1d6-0207-4831-a68f-6a1f06a6841f.body.tmp \
  --sparse --transform=s/.*tmp/disk.raw/

The resulting fedora-cloud-custom.tar.gz tarball can then be used to create a GCE image:

gsutil cp fedora-cloud-custom.tar.gz gs://<bucket>/
gcloud compute images create --source-uri gs://<bucket>/fedora-cloud-custom.tar.gz fedora-cloud-custom
gcloud compute instances create fedora --machine-type f1-micro --image fedora-cloud-custom --zone us-east1-b


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.