{"id":2579,"date":"2024-07-24T21:14:06","date_gmt":"2024-07-25T03:14:06","guid":{"rendered":"https:\/\/mrguitar.net\/?p=2579"},"modified":"2024-07-25T07:33:16","modified_gmt":"2024-07-25T13:33:16","slug":"migrating-my-fedora-server-to-fedora-bootc","status":"publish","type":"post","link":"https:\/\/mrguitar.net\/?p=2579","title":{"rendered":"Migrating my Fedora Server to fedora-bootc"},"content":{"rendered":"\n<p>Earlier this year I put together an <a href=\"https:\/\/mrguitar.net\/?p=2524\" data-type=\"post\" data-id=\"2524\">upgraded home server<\/a>. In all honesty, I&#8217;ve been loving it. Not only has the hardware &amp; disk layout worked really, but deploying all my applications as containers has made everything <em>just work<\/em> and I haven&#8217;t had to put my hands on the system once. Everything is self updating. &#8230;.until something inevitably breaks, but I&#8217;ll worry about that later. ;)<\/p>\n\n\n\n<p>My goal from the beginning was to deploy this using <a href=\"https:\/\/github.com\/containers\/bootc\">bootc<\/a>, but due to some time pressure at work that wasn&#8217;t possible. I finally made some time and successfully moved the system over to fedora-bootc, and I&#8217;m going to share my experience for others considering doing the same. Keep in mind that I don&#8217;t expect details of this post to age very well as the tech is moving pretty fast. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-1024x576.png\" alt=\"\" class=\"wp-image-2582\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-1024x576.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-300x169.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-768x432.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration.png 1057w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Yes, I put this blog post together from a presentation I gave!<\/figcaption><\/figure>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Why use a bootc image for the OS?<\/h2>\n\n\n\n<p>For the past decade we&#8217;ve been using containers to decouple applications from the OS. It&#8217;s an amazing concept that has probably done more to move the industry forward since virtualization or cloud computing. This separation has led to immutable OS&#8217;s, often inspired by CoreOS, to facilitate running containers. I&#8217;ve been a huge fan of these offerings, but there&#8217;s always an amount of customization needed that is challenging. What&#8217;s amazing about bootc is we can build, deploy, &amp; manage the OS as if it&#8217;s a container. If you&#8217;re not familiar with it, a good place to get up to speed is <a href=\"https:\/\/red.ht\/imagemode\">here.<\/a>  Personally, the biggest advantage for my setup is to unify the management of my apps &amp; OS. I&#8217;ve long wanted to use git as a means to handle OS updates and rollouts, and bootc is perfect for that. <\/p>\n\n\n\n<p>The OS becomes a simple Containerfile and most configurations are just text files that we&#8217;ll copy into the OS. Here&#8217;s an illustrative example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM quay.io\/fedora\/fedora-bootc:40\n\nRUN dnf install -y &#91;system agents] &#91;dependencies] &amp;&amp; dnf clean all\n\nCOPY &#91;unpackaged application]\nCOPY &#91;configuration files]<\/code><\/pre>\n\n\n\n<p>Here&#8217;s the approach I used to migrate my system<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Identify installed rpms<\/h2>\n\n\n\n<p>A quick look at the output of <code>rpm -qa | sort | less<\/code> makes it easy to see what rpms need to be added. You really only need to grab the packages you care about. Don&#8217;t worry about low-level ones like the kernel, grub, firmware, systemd, etc. For my setup, this is what my Containerfile looks like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM quay.io\/fedora\/fedora-bootc:40\nCOPY etc etc\n\nRUN dnf install -y cockpit cockpit-podman cockpit-storaged cockpit-ws cockpit-pcp cockpit-machines cockpit-selinux bash-completion borgbackup bwm-ng cups cups-browsed ethtool firewalld git lm_sensors nfs-utils nss-mdns pcp pcp-selinux samba sysstat tftp-server tuned wget &amp;&amp; dnf clean all\n\nRUN systemctl enable lm_sensors sysstat tuned fstrim.timer caddy-build.timer podman-auto-update.timer cockpit.socket\n\n#these are the various mounts I use\nRUN mkdir -p \/backups\/family \/backups\/general \/backups\/office \/backups\/work \/data \/data0 \/data1 \/data\/share<\/code><\/pre>\n\n\n\n<p>See how simple and straightforward that is? All of the workloads get handled in the next section, but for the main operating system this is crazy easy!!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Grab files from \/etc<\/h2>\n\n\n\n<p>Grab everything you want to keep from \/etc and we&#8217;ll copy it into the container via the <code>COPY etc etc<\/code> line. For my setup the biggest things were quadlets in \/etc\/containers\/systemd, network keyfiles in \/etc\/NetworkManager\/system-connections\/ and custom unit files under \/etc\/systemd\/system. I also had a handful of other config files that were easy to grab. I&#8217;ll note that for most environments &amp; use cases networking configs should be handled via kagrs, kickstart, or cloud-init or ignition. Keep that in mind if you&#8217;re using one image for multiple systems which is the most common scenario. For this specific system, I have a ALB bond w\/ a static IP and since it will only live on this one system, it&#8217;s actually really nice to have the configs inside the image.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Create a Kickstart<\/h2>\n\n\n\n<p>If you&#8217;re wondering, &#8220;how does booting a container work!?&#8221;, this is where it will all start to make sense. Even though we have the full OS packaged inside the container image, there&#8217;s no concept of partitioning or disk layout. Since I&#8217;m targeting a bare metal box here, anaconda\/kickstart will handle the disk partitioning, pull the container image, write it to disk, and finally setup our users. It&#8217;s definitely possible to completely configure the OS inside of the container image, but unless it&#8217;s an embedded-style use case, I typically prefer injecting users, keys, etc via cloud-init for VM\/cloud instances or kickstart for bare metal. In my case, it was paramount to not loose any data.  This is where <code>ignoredisk --only-use=nvme0n1<\/code> is a life saver. I always have some typos w\/ kickstart (well, anything computer related) and this option helped me iterate w\/o fear!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>text\nnetwork --bootproto=dhcp --device=link --activate --hostname=&#91;hostname]\n\nkeyboard --vckeymap=us --xlayouts='us'\nlang en_US.UTF-8\n\nignoredisk --only-use=nvme0n1\nbootloader --append=\"i915.enable_guc=2\"\npart \/boot\/efi --fstype=\"efi\" --onpart=nvme0n1p1\npart \/boot --fstype=\"xfs\" --recommended --onpart=nvme0n1p2\npart pv.01 --onpart=nvme0n1p3\nvolgroup fedora pv.01\nlogvol \/ --fstype=\"xfs\" --name=\"root\" --vgname=\"fedora\" --size=800000\nreboot\n\nostreecontainer --url &#91;registry]\/&#91;account]\/&#91;image]:&#91;tag]\nuser --name=&#91;user] --groups=wheel --iscrypted --password= &#91;hash]\nsshkey --username mrguitar \"ssh-rsa AAAAB3NzaC1yc2EA...\n\nrootpw --iscrypted &#91;hash]\nsshkey --username root \"ssh-rsa AAAAB3NzaC1yc2EA...<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: fstab or mounts?<\/h2>\n\n\n\n<p>My original system had all the mounts defined in \/etc\/fstab, as one would expect. I originally thought I would grab generated mount units under: <code>\/run\/systemd\/generator\/*.mount<\/code> and include additional mounts in container image. I think this would work really well, but I ended up copying my original fstab into my image as old_fstab and just manually moved the relevant parts over. I&#8217;m not saying this is the best option, but it was effective here, and you only have to touch it once. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Back up Podman Volumes<\/h2>\n\n\n\n<p>I had a handful of podman volumes that I didn&#8217;t want to lose data. Fortunately these are crazy easy to backup via <code>podman volume export<\/code>. I found a script that will cycle through and backup the volumes in one shot. The script is simple, but effective! <a href=\"http:\/\/podman-volume-backup.sh\">podman-volume-backup.sh<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What went well?<\/h2>\n\n\n\n<p>Ultimately, I was really happy with everything. The whole process was easier than I was expecting. I had no data loss and all of my containerized apps came back on-line w\/ zero intervention.  The combination of using quadlet &amp; volumes made it soooooo easy! <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-1024x576.jpg\" alt=\"\" class=\"wp-image-2580\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-1024x576.jpg 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-300x169.jpg 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration-768x432.jpg 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Fedora-Bootc-Migration.jpg 1057w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Here&#8217;s cockpit running on my system<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What could have used improvement?<\/h2>\n\n\n\n<p>I originally planned to deploy the container image w\/o using kickstart, and instead use bootc-install (covering this is out of scope for this post but it&#8217;s awesome for different reasons). There are limitations using bootc-install on an LVM system. Had I picked kickstart from the beginning this whole process would have taken less time. I did kick the system 8 times. Now most of these, maybe 5 were due to dumb typos, the rest were over partitioning anomalies. I was pretty frustrated that there wasn&#8217;t an interactive installer option. Since this is a one-off install there&#8217;s not a whole lot of value in having it defined in kickstart. I later learned that if a kickstart file only contains the ostreecontainer command, that anaconda will provide the exact interactive experience I was wanting. This is a great tip for others! I also forgot to backup my firewall rules. These weren&#8217;t too bad to add in after the fact, but it would have been ideal to not have to recreate these as I do have a couple complex rules. Finally I forgot some packages like vim &amp; git. Those were super easy to add to my containerfile and add during the next update.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Speaking of updates, how does that work?<\/h2>\n\n\n\n<p>It&#8217;s crazy easy to create updates. First, create the updated image as you would build any other container: <code>podman build -f [containerfile] -t [image:tag]<\/code> Second, make the image available on a registry: <code>podman push [image:tag] <\/code>Finally, <code>bootc-fetch-apply-updates.timer<\/code> will take care of the rest! I do recommend adding a systemd drop-in to adjust the timer to run when it&#8217;s appropriate for your environment. Some will inevitably disable the timer and be better served applying updates manually. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Your turn!<\/h2>\n\n\n\n<p>Anyway, the results are amazing. Updates are flawless, I have perfect OS &amp; app isolation, and the whole setup is crazy easy to automate. I&#8217;ll write another post soon with my Gitea setup showing how container rebuilds are done. In the meantime here are some helpful links to help you get started:<\/p>\n\n\n\n<p>Get involved:&nbsp;&nbsp;<\/p>\n\n\n\n<p>Forum <a href=\"https:\/\/discussion.fedoraproject.org\/tag\/bootc-initiative\">https:\/\/discussion.fedoraproject.org\/tag\/bootc-initiative<\/a><\/p>\n\n\n\n<p>Matrix <a href=\"https:\/\/matrix.to\/#\/#bootc:fedoraproject.org\">https:\/\/matrix.to\/#\/#bootc:fedoraproject.org<\/a><\/p>\n\n\n\n<p>Bootc Images:<\/p>\n\n\n\n<p><a href=\"http:\/\/quay.io\/fedora\/fedora-bootc:40\">quay.io\/fedora\/fedora-bootc:40<\/a><\/p>\n\n\n\n<p>quay.io\/centos-bootc\/centos-bootc:stream9<\/p>\n\n\n\n<p>Awesome Projects:<\/p>\n\n\n\n<p><a href=\"https:\/\/podman-desktop.io\">https:\/\/podman-desktop.io<\/a> &#8211; check out the bootc extension (included with the red hat extension pack)<\/p>\n\n\n\n<p><a href=\"http:\/\/projectbluefin.io\">projectbluefin.io<\/a> &#8211; what I&#8217;m running on my daily driver laptop. I highly recommend Bluefin!<\/p>\n\n\n\n<p>Docs:<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.fedoraproject.org\/en-US\/bootc\">https:\/\/docs.fedoraproject.org\/en-US\/bootc<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/containers.github.io\/bootc\/intro.html\">https:\/\/containers.github.io\/bootc\/intro.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Earlier this year I put together an upgraded home server. In all honesty, I&#8217;ve been loving it. Not only has the hardware &amp; disk layout worked really, but deploying all my applications as containers has made everything just work and I haven&#8217;t had to put my hands on the system once. Everything is self updating. &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/mrguitar.net\/?p=2579\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Migrating my Fedora Server to fedora-bootc&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6],"tags":[126,32,125],"class_list":["post-2579","post","type-post","status-publish","format-standard","hentry","category-open-sourcenerd-stuff","tag-bootc","tag-fedora","tag-fedora-bootc"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2579"}],"version-history":[{"count":4,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2579\/revisions"}],"predecessor-version":[{"id":2586,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2579\/revisions\/2586"}],"wp:attachment":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}