Fedora CoreOS on Raspberry Pi 4

Fedora CoreOS on Raspberry Pi 4

A guide that walks through the steps to build and use coreos-assembler to install Fedora CoreOS on a Pi 4.

This guide walks through the steps to assemble a Fedora CoreOS image that targets aarch64, and then continues to installing it onto a USB drive. Afterward, the USB drive is updated to include UEFI for the Raspberry Pi to facilitate booting.

  1. Required Items
  2. First-time Set Up
    1. Build the CoreOS Assembler image
    2. Configure the cosa Bash function
    3. Initialize the CoreOS working directory
    4. Install coreos-installer
  3. Assemble a CoreOS Image
  4. Install CoreOS to a target drive
    1. Run coreos-installer to write CoreOS
    2. Add UEFI to the new EFI partition
    3. Remove 3gb RAM limit

Required Items

The following items are used in this guide:

  1. A host Raspberry Pi 4 running either Fedora 32 Server or Fedora 32 Workstation, and relevant peripherals and USB drive.

    • This Raspberry Pi 4 should have one blue USB 3.0 port available.
  2. A target USB drive
  3. The latest release of Raspberry Pi 4 UEFI Firmware (homepage) downloaded and available.1

First-time Set Up

The following steps will only need to be run once to set up the environment for assembling CoreOS images.

Build the CoreOS Assembler image

The official CoreOS Assembler images target other architectures. In order to use CoreOS Assembler from a Raspberry Pi, a new image that targets aarch64 needs to be built. Start by cloning the source repository:

[robert@pi4 ~]$ git clone https://github.com/coreos/coreos-assembler.git
Cloning into 'coreos-assembler'...
remote: Enumerating objects: 37555, done.
remote: Total 37555 (delta 0), reused 0 (delta 0), pack-reused 37555
Receiving objects: 100% (37555/37555), 30.24 MiB | 4.30 MiB/s, done.
Resolving deltas: 100% (22698/22698), done.
Updating files: 100% (3663/3663), done.

Downloading the source for COSA

With the source downloaded, change into the source directory and start the image build with podman build:

[robert@pi4 ~]$ cd coreos-assembler
[robert@pi4 coreos-assembler]$ podman build -t localhost/coreos-assembler .
STEP 1: FROM registry.fedoraproject.org/fedora:32
Getting image source signatures
Copying blob 1bfcc9281f78 [=================>--------------------] 31.6MiB / 66.8MiB

Beginning the aarch64 image build for COSA

Image creation took roughly one hour to complete for me, so expect to wait some time for it. Once complete, it should finish with output that looks similar to the following:

STEP 14: WORKDIR /srv/
--> 64d9e81c52f
STEP 15: RUN chown builder: /srv
--> f7c3e9149ce
STEP 16: RUN rm -rf /root/containerbuild
--> c2fc11389b2
STEP 17: RUN chmod g=u /etc/passwd
--> 5e2364b0c49
STEP 18: USER builder
--> 51c73f86b8d
STEP 19: ENTRYPOINT ["/usr/bin/dumb-init", "/usr/bin/coreos-assembler"]
STEP 20: COMMIT localhost/coreos-assembler
--> 7660ad1d9f0
[robert@pi4 coreos-assembler]$

Completion of the COSA image build

With the image built, some configuration needs to be set in order to facilitate use of it.

Configure the cosa Bash function

Add the command from coreos/coreos-assembler into ~/.bashrc. In this example, the function is wrapped with echo '...' >> ~/.bashrc to directly add it from the command line.2

[robert@pi4 coreos-assembler]$ cd
[robert@pi4 ~]$ echo 'cosa() {
>    env | grep COREOS_ASSEMBLER
>    set -x
>    podman run --rm -ti --security-opt label=disable --privileged                                    \
>               --uidmap=1000:0:1 --uidmap=0:1:1000 --uidmap 1001:1001:64536                          \
>               -v ${PWD}:/srv/ --device /dev/kvm --device /dev/fuse                                  \
>               --tmpfs /tmp -v /var/tmp:/var/tmp --name cosa                                         \
>               ${COREOS_ASSEMBLER_CONFIG_GIT:+-v $COREOS_ASSEMBLER_CONFIG_GIT:/srv/src/config/:ro}   \
>               ${COREOS_ASSEMBLER_GIT:+-v $COREOS_ASSEMBLER_GIT/src/:/usr/lib/coreos-assembler/:ro}  \
>               ${COREOS_ASSEMBLER_CONTAINER_RUNTIME_ARGS}                                            \
>               ${COREOS_ASSEMBLER_CONTAINER:-quay.io/coreos-assembler/coreos-assembler:latest} "$@"
>    rc=$?; set +x; return $rc
> }' >> ~/.bashrc

Adding COSA function to .bashrc

The cosa Bash function uses a few environment variables to configure its specific use. The primary one that is relevant here is the COREOS_ASSEMBLER_CONTAINER variable, which causes the cosa function to run using the locally created image.

[robert@pi4 ~]$ echo "export COREOS_ASSEMBLER_CONTAINER=localhost/coreos-assembler" >> ~/.bashrc

Configure COSA to use locally built COSA image

After the configuration has been applied to future initializations of Bash, it helps to also include the configuration into the currently running instance as well.

[robert@pi4 ~]$ . ~/.bashrc

Sourcing .bashrc again to pick up new COSA function and configuration

Initialize the CoreOS working directory

To initialize the CoreOS build, create a new directory to track the assembly process. In this example, fcos is used to match the documentation from coreos/coreos-assembler

[robert@pi4 ~]$ mkdir fcos
[robert@pi4 ~]$ cd fcos

Creating a working directory for CoreOS assembly

Inside this directory, initialize an assembly configuration with cosa init.

[robert@pi4 fcos]$ cosa init https://github.com/coreos/fedora-coreos-config
+ podman run --rm -ti --security-opt label=disable --privileged --uidmap=1000:0:1 --uidmap=0:1:1000 --uidmap 1001:1001:64536 -v /home/robert/fcos:/srv/ --device /dev/kvm --device /dev/fuse --tmpfs /tmp -v /var/tmp:/var/tmp --name cosa localhost/coreos-assembler init https://github.com/coreos/fedora-coreos-config
+ mkdir -p src
+ cd src
+ test -e config
+ case "${source}" in
+ git clone --recurse-submodules https://github.com/coreos/fedora-coreos-config config
Cloning into 'config'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 5551 (delta 14), reused 18 (delta 8), pack-reused 5527
Receiving objects: 100% (5551/5551), 1.10 MiB | 4.34 MiB/s, done.
Resolving deltas: 100% (3008/3008), done.
+ '[' -n '' ']'
+ set +x
Config commit: 5836c2366a448b8fd8278ab4939a1920e1a6a9af
+ manifest=config/manifest.yaml
+ '[' -f config/manifest.yaml ']'
+ mkdir -p cache
+ mkdir -p builds
+ mkdir -p tmp
+ mkdir -p overrides/rpm
+ mkdir -p overrides/rootfs
+ rc=0
+ set +x

Initializing the Fedora CoreOS working directory

As an optional final step to the assembly configuration, change the configuration to the stable branch.

[robert@pi4 fcos]$ cd src/config/
[robert@pi4 config]$ git checkout stable
Branch 'stable' set up to track remote branch 'stable' from 'origin'.
Switched to a new branch 'stable'
[robert@pi4 config]$ cd -

Switching to the stable configurartion branch

Now the CoreOS assembly configuration is ready.

Install coreos-installer

The coreos-installer application will later be used to write Fedora CoreOS to the target drive. While performing the one-time set up for other parts of the assembly, the installer can also be installed.

Install coreos-installer from a terminal, like the following:

[robert@pi4 ~]$ sudo dnf install -y coreos-installer
Last metadata expiration check: 0:26:53 ago on Mon 07 Sep 2020 10:06:35 PM CDT.
Dependencies resolved.
 Package                Architecture  Version               Repository     Size
 coreos-installer       aarch64       0.6.0-1.fc32          updates       1.6 M

Transaction Summary
Install  1 Package

Total download size: 1.6 M
Installed size: 5.5 M
Downloading Packages:
coreos-installer-0.6.0-1.fc32.aarch64.rpm       984 kB/s | 1.6 MB     00:01
Total                                           860 kB/s | 1.6 MB     00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : coreos-installer-0.6.0-1.fc32.aarch64                  1/1
  Running scriptlet: coreos-installer-0.6.0-1.fc32.aarch64                  1/1
  Verifying        : coreos-installer-0.6.0-1.fc32.aarch64                  1/1



Installing coreos-installer for later usage.

Assemble a CoreOS Image

With everything prepared, CoreOS can now be assembled. To save time, both the cosa fetch and cosa build commands can be performed in succession.

[robert@pi4 fcos]$ cosa fetch && cosa build metal
+ podman run --rm -ti --security-opt label=disable --privileged --uidmap=1000:0:1 --uidmap=0:1:1000 --uidmap 1001:1001:64536 -v /home/robert/fcos:/srv/ --device /dev/kvm --device /dev/fuse --tmpfs /tmp -v /var/tmp:/var/tmp --name cosa localhost/coreos-assembler fetch
Config commit: 8f9328e14e37c82340170a67f82987f5680f479e
Using manifest: /srv/src/config/manifest.yaml
Running: rpm-ostree compose tree --repo=/srv/tmp/repo --cachedir=/srv/cache --touch-if-changed /srv/tmp/treecompose.changed --unified-core /srv/src/config/manifest.yaml --download-only --ex-lockfile=/srv/src/config/manifest-lock.overrides.aarch64.yaml
Loaded lockfiles:
rpm-ostree version: 2020.4
No previous commit for fedora/aarch64/coreos/stable
Enabled rpm-md repositories: fedora-coreos-pool
⠉ Updating metadata for 'fedora-coreos-pool'  28% [█████░░░░░░░░░░░░░░░] (1s)

Fetching and assembling CoreOS

Similar to building the CoreOS Assembler image, this will also take a long time. Go brew and drink a few cups of coffee or tea while you wait.

When the assembly has completed, the last few lines of output should look similar to the following:

+ cosa meta --workdir /srv --build 32.20200907.dev.0 --artifact metal --artifact-json /srv/tmp/build.metal/meta.json.new
/srv/builds/32.20200907.dev.0/aarch64/meta.json wrote with version stamp 1599467889158279969
+ /usr/lib/coreos-assembler/finalize-artifact fedora-coreos-32.20200907.dev.0-metal.aarch64.raw /srv/builds/32.20200907.dev.0/aarch64/fedora-coreos-32.20200907.dev.0-metal.aarch64.raw
+ rm -rf /srv/tmp/build.metal
+ rm -rvf /srv/builds/32.20200907.dev.0/aarch64/.metal.building
removed '/srv/builds/32.20200907.dev.0/aarch64/.metal.building'
+ rc=0
+ set +x
[robert@pi4 fcos]$

A completed Fedora CoreOS assembly

Install CoreOS to a target drive

With the CoreOS image assembled, it’s time to install it. Assuming that the host Raspberry Pi 4 has booted from a drive in one of the blue USB 3.0 ports, insert the target USB drive into the other blue USB 3.0 port.

If running from Fedora 32 Workstation, ensure that any existing partitions are unmounted – but not ejected – before continuing.

Run coreos-installer to write CoreOS

Start the installation by running coreos-installer.

In the example command below, the ignition file is specified as /path/to/file.ign. Change this to the path of the intended ignition file.

The command below assumes that the target drive is /dev/sdb. This should be the case for any Raspberry Pi 4 running Fedora according to my previous guides; double-check the device identifier prior to running the command.

[robert@pi4 fcos]$ sudo coreos-installer install /dev/sdb --ignition-file /path/to/file.ign --image-file builds/latest/aarch64/fedora-coreos-32.*-metal.aarch64.raw --offline --insecure
Copying image from builds/latest/aarch64/fedora-coreos-32.20200907.dev.0-metal.aarch64.raw
Reading signature from builds/latest/aarch64/fedora-coreos-32.20200907.dev.0-metal.aarch64.raw.sig
Couldn't read signature file: No such file or directory (os error 2)
Signature not found; skipping verification as requested
> Read disk 2.7 GiB/2.7 GiB (100%)
Writing Ignition config
Install complete.

Installing Fedora CoreOS to a USB drive

Fedora CoreOS is now installed to the USB drive; however, it is not yet bootable from a Raspberry Pi 4.

Add UEFI to the new EFI partition

The CoreOS assembler and installer assume that EFI is available on the target system. Because of this, no effort is made to include u-boot, UEFI, or other shim that facilitates Raspberry Pi boot.

Create a directory to mount the EFI partition, then mount the EFI partition onto it:

[robert@pi4 fcos]$ sudo mkdir -p /mnt/fcos-efi
[robert@pi4 fcos]$ sudo mount /dev/sdb2 /mnt/fcos-efi

Mounting the CoreOS EFI partition

Unpack UEFI into the EFI partition.1

[robert@pi4 fcos]$ cd /mnt/fcos-efi
[robert@pi4 fcos-efi]$ sudo unzip ~/RPi4_UEFI_Firmware_v1.19.zip
Archive:  /home/robert/RPi4_UEFI_Firmware_v1.19.zip
  inflating: RPI_EFI.fd
  inflating: Readme.md
  inflating: bcm2711-rpi-4-b.dtb
  inflating: config.txt
  inflating: fixup4.dat
  inflating: overlays/miniuart-bt.dtbo
  inflating: start4.elf

Unpacking UEFI into the EFI partition

As with the guides for Fedora 32 Server and Workstation, I similarly recommend to disable the rainbow square splash screen:

[robert@host rpi-uefi]$ echo "disable_splash=1" | sudo tee -a config.txt

Disabling the rainbow square splash screen

Finally, unmount and clean up.

[robert@pi4 fcos-efi]$ cd -
[robert@pi4 fcos]$ sudo umount /mnt/fcos-efi
[robert@pi4 fcos]$ sudo rmdir /mnt/fcos-efi

Cleaning up after installing UEFI on the target drive

The USB drive is now ready for booting.

Remove 3gb RAM limit

On the first boot, it is recommended to disable the RAM limit in UEFI. For steps to do this, refer to the Configure UEFI to disable the RAM limiter section of my guide on Installing Fedora 32 Server.

  1. A fresh unpack of UEFI is used in this guide. Actually, UEFI can be copied from the running system, but I opt against this to avoid copying any boot configuration that was set up by the host Pi’s Fedora.


    Ultimately, it doesn’t make much difference: The fresh install requires disabling the RAM limiter again; while the copied install requires either waiting several minutes for PXE to timeout or adjusting the boot order. ↩︎ ↩︎2

  2. The command without Bash output is listed here to facilitate copy and paste:

      echo 'cosa() {
         env | grep COREOS_ASSEMBLER
         set -x
         podman run --rm -ti --security-opt label=disable --privileged                                    \
                    --uidmap=1000:0:1 --uidmap=0:1:1000 --uidmap 1001:1001:64536                          \
                    -v ${PWD}:/srv/ --device /dev/kvm --device /dev/fuse                                  \
                    --tmpfs /tmp -v /var/tmp:/var/tmp --name cosa                                         \
                    ${COREOS_ASSEMBLER_CONFIG_GIT:+-v $COREOS_ASSEMBLER_CONFIG_GIT:/srv/src/config/:ro}   \
                    ${COREOS_ASSEMBLER_GIT:+-v $COREOS_ASSEMBLER_GIT/src/:/usr/lib/coreos-assembler/:ro}  \
                    ${COREOS_ASSEMBLER_CONTAINER_RUNTIME_ARGS}                                            \
                    ${COREOS_ASSEMBLER_CONTAINER:-quay.io/coreos-assembler/coreos-assembler:latest} "$@"
         rc=$?; set +x; return $rc
      }' >> ~/.bashrc