{"id":2605,"date":"2024-07-31T16:37:11","date_gmt":"2024-07-31T22:37:11","guid":{"rendered":"https:\/\/mrguitar.net\/?p=2605"},"modified":"2024-11-01T14:54:15","modified_gmt":"2024-11-01T20:54:15","slug":"bootable-containers-on-the-raspberry-pi-4","status":"publish","type":"post","link":"https:\/\/mrguitar.net\/?p=2605","title":{"rendered":"Bootable containers on the Raspberry Pi 4"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"548\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-1024x548.jpg\" alt=\"\" class=\"wp-image-2615\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-1024x548.jpg 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-300x161.jpg 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-768x411.jpg 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-1536x823.jpg 1536w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/PXL_20240731_2121113022-2048x1097.jpg 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>After moving my <a href=\"https:\/\/mrguitar.net\/?p=2579\" data-type=\"post\" data-id=\"2579\">home server<\/a> to <a href=\"https:\/\/docs.fedoraproject.org\/en-US\/bootc\/getting-started\/\">fedora-bootc<\/a>, and <em>gitting<\/em> a really nice <a href=\"https:\/\/mrguitar.net\/?p=2587\" data-type=\"post\" data-id=\"2587\">git workflow in place<\/a>, I remembered that I have this Raspberry Pi 4 sitting around collecting dust. This was a really nice system that I bought to run <a href=\"https:\/\/octoprint.org\/download\/\">Octopi<\/a> to manage my two Prusa Mini printers. Now that I&#8217;ve upgraded to the MK4, I don&#8217;t feel the need to use Octoprint any more. &#8230;but having a useful aarch container host on the network *is* appealing to me especially since I do a decent amount of container work on my M3 Mac using <a href=\"https:\/\/podman-desktop.io\/\">Podman Desktop<\/a>. Fortunately, it&#8217;s pretty simple to get fedora-bootc working great on the Pi4. So grab your RPi, blow the dust off, and get ready to get some value out of it.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">It all starts with the Containerfile<\/h2>\n\n\n\n<p>Below is just a simple example to get you started. I&#8217;ve pulled a couple snippets from <a href=\"https:\/\/gitlab.com\/fedora\/bootc\/examples\">this repository<\/a> to help inject my SSH keys and create users. This Containerfile has a clever if\/then statement will intentionally fail if the podman build command does not contain something like &#8211;build-arg &#8220;sshpubkey=$(cat ~\/.ssh\/mykey.pub)&#8221;. Feel free to adapt this for your setup. Some obvious recommendations are to include quadlet files, add rpms, or really anything else you want.  <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM quay.io\/fedora\/fedora-bootc:latest\n\nRUN dnf -y install cockpit cockpit-ws cockpit-podman git vim-enhanced tree &amp;&amp; dnf clean all &amp;&amp; systemctl enable cockpit.socket\n\nCOPY etc etc\n\nARG sshpubkey\n\nRUN if test -z \"$sshpubkey\"; then echo \"must provide sshpubkey\"; exit 1; fi; \\\n    useradd -G wheel core &amp;&amp; \\\n    mkdir -m 0700 -p \/home\/core\/.ssh &amp;&amp; \\\n    echo $sshpubkey &gt; \/home\/core\/.ssh\/authorized_keys &amp;&amp; \\\n    chmod 0600 \/home\/core\/.ssh\/authorized_keys &amp;&amp; \\\n    chown -R core: \/home\/core\n\nRUN set -eu; mkdir -p \/usr\/ssh &amp;&amp; \\\n    echo 'AuthorizedKeysFile \/usr\/ssh\/%u.keys .ssh\/authorized_keys .ssh\/authorized_keys2' &gt;&gt; \/etc\/ssh\/sshd_config.d\/30-auth-system.conf &amp;&amp; \\\n    echo ${sshpubkey} &gt; \/usr\/ssh\/root.keys &amp;&amp; chmod 0600 \/usr\/ssh\/root.keys<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Podman Desktop makes life easy<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/50bce158-5219-4fd0-a5eb-8047afed540f-1024x512.png\" alt=\"\" class=\"wp-image-2617\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/50bce158-5219-4fd0-a5eb-8047afed540f-1024x512.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/50bce158-5219-4fd0-a5eb-8047afed540f-300x150.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/50bce158-5219-4fd0-a5eb-8047afed540f-768x384.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/50bce158-5219-4fd0-a5eb-8047afed540f.png 1280w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>I love CLIs as much as anyone, but I have to admit that I&#8217;m sucker for eye candy too! <a href=\"https:\/\/podman-desktop.io\/\">Podman Desktop<\/a> is all the eye candy you could ever want for your containers and it makes some fairly complex operations really simple. It runs on any OS, but everything in this post was done using my Mac. If you attempt using the bootc plugin section on a Linux system, I think you&#8217;ll need to run a podman machine for it to work. YMMV. Anyway, on a Mac the installation is super easy and it will get a podman machine up and working in no time. <\/p>\n\n\n\n<p>Once you have your Containerfile setup on Podman up and running, click on the Images button on the lefthand menu followed by Build. Here we&#8217;ll browse to the Containerfile and select a couple other options. LIKE INCLUDING YOUR PUBLIC SSH KEY IF YOU EVER WANT TO LOGIN. :)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"506\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-1024x506.png\" alt=\"\" class=\"wp-image-2607\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-1024x506.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-300x148.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-768x380.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-1536x759.png 1536w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.37.55\u202fPM-2048x1013.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>Next we&#8217;ll use the bootc extension to create a raw image that we&#8217;ll eventually <code>dd<\/code> on to the RPI&#8217;s microSD card. Click the adorable seal button on the menu:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignleft size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"96\" height=\"124\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/image.png\" alt=\"\" class=\"wp-image-2609\" style=\"width:96px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"563\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-1024x563.png\" alt=\"\" class=\"wp-image-2608\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-1024x563.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-300x165.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-768x422.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-1536x844.png 1536w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.44.10\u202fPM-2048x1125.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>Then select the container we built earlier, raw image, desired file system, and ensure that Arm is highlighted. Once this is in place click build.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Let&#8217;s Flash that image<\/h2>\n\n\n\n<p>Now that we have our image, open the handy-dandy <a href=\"https:\/\/www.raspberrypi.com\/software\/\">Raspberry Pi Imager utility<\/a>. All we need to do is select your model, the raw file we just created (note: the utility doesn&#8217;t allow the selection of raw files, change the file type to &#8220;all files&#8221; to select it), and your microSD card (or other storage device). Click Next and watch the progress bar with the enthusiasm of a child waiting for St Nick to visit.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"724\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.52.35\u202fPM-1024x724.png\" alt=\"\" class=\"wp-image-2610\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.52.35\u202fPM-1024x724.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.52.35\u202fPM-300x212.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.52.35\u202fPM-768x543.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-4.52.35\u202fPM.png 1350w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Fun with firmware!<\/h2>\n\n\n\n<p>If you thought we were ready to pop the microSD card if you RPi and boot, you&#8217;d be wrong. :) Arm systems often require some extra love to ensure the proper firmware, device tree blobs, etc are in place. Fortunately, our friends who make <a href=\"https:\/\/fedoraproject.org\/coreos\/\">Fedora CoreOS<\/a> have a <a href=\"https:\/\/docs.fedoraproject.org\/en-US\/fedora-coreos\/provisioning-raspberry-pi4\/\">really great write up<\/a> to get the files necessary. Feel free to follow the steps as it, I tweaked it a bit to be able to fetch on a Mac using a super lame script. Save this file as fetch_efi.sh and chmod +x the file<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\nRELEASE=40\n\nmkdir -p \/tmp\/efi\/boot\/efi\ndnf install -y --downloadonly --release=$RELEASE --forcearch=aarch64 --destdir=\/tmp\/efi\/ uboot-images-armv8 bcm283x-firmware bcm283x-overlays\nfor rpm in \/tmp\/efi\/*rpm; do rpm2cpio $rpm | cpio -idv -D \/tmp\/efi\/; done\nmv \/tmp\/efi\/usr\/share\/uboot\/rpi_arm64\/u-boot.bin \/tmp\/efi\/boot\/efi\/rpi-u-boot.bin<\/code><\/pre>\n\n\n\n<p>Once you have that script ready to go, simply make a directory called tmp in your working directory place the script in it. Next, we&#8217;ll run this to grab the files: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>podman run -ti --rm -v $(pwd)\/tmp:\/tmp fedora-bootc \/tmp\/fetch_efi.sh<\/code><\/code><\/pre>\n\n\n\n<p>Let that run and the files we need will be under $(pwd)\/tmp\/efi\/boot\/efi Open that directory in finder along with the microSD boot partition. I found that I needed to reinsert my microSD card as the RPI image utility will eject it after flashing it. It shows up as a &#8220;NO NAME&#8221; drive on my system.  Simply drag the files over to the microSD card&#8217;s root directory and eject it when the copy is finished. <\/p>\n\n\n\n<p>&#8230;and yes, I&#8217;m fully aware that if you&#8217;re reading this blog you just lost all respect for me that I didn&#8217;t copy these files on the command line. Well, I did that on my <a href=\"https:\/\/universal-blue.org\/\">Universal Blue system <\/a>earlier, but I didn&#8217;t want to burn the calories to figure out where disks mount on a Mac &#8211; remember I&#8217;m a Linux guy. Maybe next time!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"610\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-1024x610.png\" alt=\"\" class=\"wp-image-2618\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-1024x610.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-300x179.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-768x457.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-1536x915.png 1536w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-31-at-5.10.11\u202fPM-2048x1220.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">It&#8217;s go time!<\/h2>\n\n\n\n<p>Toss the microSD into your RPi and power it on. If you gave your container image a proper [registry]\/[user]\/[image]:[tag] format earlier in Podman Desktop, it will automatically update when you build and push your next image. That feature alone is worth the price of admission IMO and opens the door for all type of slick automation. Don&#8217;t worry if you missed this, simply push your next container build to the registry and run <code>bootc switch [registry]\/[user]\/[image]:[tag]<\/code> and you&#8217;re good to go!<\/p>\n\n\n\n<p>Getting this up and running was really easy, and while the firmware section might seem like a drag, keep in mind you only need to do that once. Future updates won&#8217;t blow away your firmware. In fact, it probably wouldn&#8217;t be too difficult to adapt that script to run as a quadlet on boot that would update the firmware bits in place. That could easily be included in the bootc image, but that&#8217;s something to tackle for another day!<\/p>\n\n\n\n<p>My next steps are to add this as a runner to my Gitea server for doing automation jobs. That&#8217;s way cooler than collecting dust!!<\/p>\n\n\n\n<p><strong>Update #1<\/strong>: I left out partition\/filesystem resizing. As we don&#8217;t really know the size of your microSD (why not get a 64G to 128? They&#8217;re crazy cheap!) card, bootc-image-builder will assume a simple 10G size.  Two commands will resize the main partition and file systems:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#Resizing the partition can happen on the RPi when it's booted &amp; running:\nsudo growpart \/dev\/mmcblk0 3\n#Resizing the root filesystem live isn't supported. I slapped the card in my Universal Blue laptop and used the output of sudo dmesg to make sure I had the right device:\nsudo resize2fs \/dev\/sdc3<\/code><\/pre>\n\n\n\n<p>Now, you can use the full storage of the card, easy peasy. Please leave a comment if I screwed up anything else. Thanks!<\/p>\n\n\n\n<p><strong>Update #2<\/strong>: Connect to wifi using: sudo nmcli device wifi connect [SSID] &#8211;ask <\/p>\n\n\n\n<p>I use nmcli once every 3 years so I always have to reference the docs. This setting will persist across reboots\/upgrades like you&#8217;d want. It works great.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After moving my home server to fedora-bootc, and gitting a really nice git workflow in place, I remembered that I have this Raspberry Pi 4 sitting around collecting dust. This was a really nice system that I bought to run Octopi to manage my two Prusa Mini printers. Now that I&#8217;ve upgraded to the MK4, &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/mrguitar.net\/?p=2605\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Bootable containers on the Raspberry Pi 4&#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,125,106,129,127,128],"class_list":["post-2605","post","type-post","status-publish","format-standard","hentry","category-open-sourcenerd-stuff","tag-bootc","tag-fedora-bootc","tag-podman","tag-podman-desktop","tag-raspberry-pi","tag-rpi"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2605","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=2605"}],"version-history":[{"count":5,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2605\/revisions"}],"predecessor-version":[{"id":2672,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2605\/revisions\/2672"}],"wp:attachment":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}