{"id":2438,"date":"2018-04-01T00:15:41","date_gmt":"2018-03-31T22:15:41","guid":{"rendered":"http:\/\/possiblelossofprecision.net\/?p=2438"},"modified":"2021-05-15T11:46:36","modified_gmt":"2021-05-15T09:46:36","slug":"building-a-custom-fedora-image-to-run-on-google-compute-engine","status":"publish","type":"post","link":"https:\/\/possiblelossofprecision.net\/?p=2438","title":{"rendered":"Building a custom Fedora image to run on Google Compute Engine"},"content":{"rendered":"\n<p>Thankfully the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Fedora_Project\">Fedora Project<\/a> provides <a href=\"https:\/\/dl.fedoraproject.org\/pub\/fedora\/linux\/releases\/27\/CloudImages\/x86_64\/images\/\">cloud images<\/a> that can be directly used or <a href=\"https:\/\/possiblelossofprecision.net\/?p=2433\">easily modified<\/a> to run on almost any cloud environment. Though sometimes, it can be handy to build your own image.<\/p>\n<p><!--more--><\/p>\n<h2>0. Prerequisites<\/h2>\n<p>Fedora images in general and the <a href=\"https:\/\/fedoraproject.org\/wiki\/Changes\/Move_to_ImageFactory_For_Cloud_Image_Creation\">cloud images especially<\/a> are built using <a href=\"http:\/\/imgfac.org\/\">ImageFactory<\/a> which itself uses <a href=\"https:\/\/github.com\/clalancette\/oz\">Oz<\/a>. The latest versions can always be found <a href=\"https:\/\/koji.fedoraproject.org\/koji\/builds?type=image\">on koji<\/a>. To recreate an image locally, there are a couple of tools needed:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndnf install imagefactory imagefactory-plugins* pykickstart\r\n<\/pre>\n<h2>1. Kickstart and template<\/h2>\n<p>To build an image with ImageFactory, you&#8217;ll need two files: a <strong><a href=\"http:\/\/pykickstart.readthedocs.io\/en\/latest\/kickstart-docs.html\">kickstart file<\/a><\/strong> and an <strong><a href=\"http:\/\/imgfac.org\/documentation\/tdl\/TDL.html\">imagefactory template<\/a><\/strong>.<\/p>\n<p>The kickstart files for the (official) Fedora images are part of the <em>fedora-kickstarts<\/em> package and be installed locally with <em>dnf<\/em><\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndnf install fedora-kickstarts\r\n<\/pre>\n<p>of pulled from the fedora-kickstarts git repository at <a href=\"https:\/\/pagure.io\/fedora-kickstarts\">https:\/\/pagure.io\/fedora-kickstarts<\/a>.<\/p>\n<p>The template file is an xml decription of what to build (OS version, architecture, etc.). A sample template file can be seen below:<\/p>\n<pre class=\"brush: xml; title: fedora-cloud-custom.tdl; notranslate\" title=\"fedora-cloud-custom.tdl\">\r\n&lt;template&gt;\r\n    &lt;name&gt;fedora-cloud-custom&lt;\/name&gt;\r\n    &lt;os&gt;\r\n        &lt;name&gt;Fedora&lt;\/name&gt;\r\n        &lt;version&gt;27&lt;\/version&gt;\r\n        &lt;arch&gt;x86_64&lt;\/arch&gt;\r\n        &lt;install type='url'&gt;\r\n            &lt;url&gt;https:\/\/dl.fedoraproject.org\/pub\/fedora\/linux\/releases\/27\/Everything\/x86_64\/os\/&lt;\/url&gt;\r\n        &lt;\/install&gt;\r\n    &lt;\/os&gt;\r\n&lt;\/template&gt;\r\n<\/pre>\n<p>The template file can either have an <em>.xml<\/em> or a <em>.tdl<\/em> extension and is usually automatically generated by the koji build deamon (see <a href=\"https:\/\/pagure.io\/koji\/blob\/dad74a3\/f\/builder\/kojid#_4040\">https:\/\/pagure.io\/koji\/blob\/dad74a3\/f\/builder\/kojid#_4040<\/a> and <a href=\"https:\/\/pagure.io\/koji\/blob\/dad74a3\/f\/builder\/kojid#_3517\">https:\/\/pagure.io\/koji\/blob\/dad74a3\/f\/builder\/kojid#_3517<\/a>)<\/p>\n<h2>2. Modifying Oz default config<\/h2>\n<p>ImageFactory will create a temporary virtual machine that&#8217;s used to install Fedora into a raw disk file. Depending on the package selection <a href=\"https:\/\/docs.fedoraproject.org\/f27\/release-notes\/welcome\/Hardware_Overview.html\">you might need more<\/a> that 1GB of RAM which is the Oz default on Fedora. To modify the memory limit, change the <em>memory<\/em> parameter in the Oz configuration file<\/p>\n<pre class=\"brush: plain; highlight: [8]; title: \/etc\/oz\/oz.cfg; notranslate\" title=\"\/etc\/oz\/oz.cfg\">\r\n...\r\n&#x5B;libvirt]\r\nuri = qemu:\/\/\/system\r\nimage_type = raw\r\n# type = kvm\r\n# bridge_name = virbr0\r\n# cpus = 1\r\nmemory = 2048\r\n<\/pre>\n<p>You can either use your favourite editor or run<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsed -i -e 's\/# memory = 1024\/memory = 2048\/' \/etc\/oz\/oz.cfg\r\n<\/pre>\n<h2>3. Building a raw disk image<\/h2>\n<p>Now it&#8217;s time to build the actual image. Since the kickstart file might be hierarchical, i.e. contain <em>%include<\/em> statements to point to user kickstart files, we need to create a &#8216;flat&#8217; version first:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ntempfile=$(mktemp --suffix=.ks)\r\nksflatten -v F27 -c \/usr\/share\/spin-kickstarts\/fedora-cloud-base.ks &gt; ${tempfile}\r\n<\/pre>\n<p>Of course, the kickstart file can be customized first.<\/p>\n<p>To build the image, run<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nimagefactory base_image \\\r\n  --file-parameter install_script ${tempfile} fedora-cloud-custom.tdl \\\r\n  --parameter offline_icicle true\r\n<\/pre>\n<p>The <em>offline_icicle<\/em> 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.<\/p>\n<p>After a short while ImageFactory will print the UUID of the created image:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n============ Final Image Details ============\r\nUUID: 925b9ac8-7dca-4a9f-b055-330b23e45923\r\nType: base_image\r\nImage filename: \/var\/lib\/imagefactory\/storage\/925b9ac8-7dca-4a9f-b055-330b23e45923.body\r\nImage build completed SUCCESSFULLY!\r\n<\/pre>\n<h2>4. Creating a Google Compute Engine image<\/h2>\n<p>There is a <a href=\"https:\/\/github.com\/redhat-imaging\/imagefactory\/tree\/master\/imagefactory_plugins\/GCE\">GCE plugin<\/a> for ImageFactory that allows you to easily package the created raw disk image:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nimagefactory target_image --id &lt;UUID&gt; gce\r\n<\/pre>\n<p>Unfortunately, that plugin is not packaged for Fedora yet, so this needs to be done manually. Looking at the <a href=\"https:\/\/github.com\/redhat-imaging\/imagefactory\/blob\/master\/imagefactory_plugins\/GCE\/GCE.py\">plugin source code<\/a>, we&#8217;ll have to reproduce what the <em>builder_did_create_target_image<\/em> function does:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nqemu-img convert -O raw \\\r\n  \/var\/lib\/imagefactory\/storage\/925b9ac8-7dca-4a9f-b055-330b23e45923.body \\\r\n  \/var\/lib\/imagefactory\/storage\/80e6d1d6-0207-4831-a68f-6a1f06a6841f.body.tmp\r\ntar cfz fedora-cloud-custom.tar.gz \\\r\n  \/var\/lib\/imagefactory\/storage\/80e6d1d6-0207-4831-a68f-6a1f06a6841f.body.tmp \\\r\n  --sparse --transform=s\/.*tmp\/disk.raw\/\r\n<\/pre>\n<p>The resulting <em>fedora-cloud-custom.tar.gz<\/em> tarball can then be used to create a GCE image:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ngsutil cp fedora-cloud-custom.tar.gz gs:\/\/&lt;bucket&gt;\/\r\ngcloud compute images create --source-uri gs:\/\/&lt;bucket&gt;\/fedora-cloud-custom.tar.gz fedora-cloud-custom\r\ngcloud compute instances create fedora --machine-type f1-micro --image fedora-cloud-custom --zone us-east1-b\r\n<\/pre>\n<p>Resources:<br \/>\n<a href=\"https:\/\/fedoramagazine.org\/building-fedora-rawhide-images-imagefactory\/\">https:\/\/fedoramagazine.org\/building-fedora-rawhide-images-imagefactory\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[7,81],"class_list":["post-2438","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-fedora","tag-gcp"],"_links":{"self":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2438"}],"version-history":[{"count":12,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2438\/revisions"}],"predecessor-version":[{"id":2450,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2438\/revisions\/2450"}],"wp:attachment":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}