Skip Navigation

Assignment 4: Prepare a MicroSD Card for Alpine Linux

For this assignment, you will use Raspberry Pi OS to download Alpine Linux and create a MicroSD card containing the initial Alpine Linux installation environment. The finished installation will take place over the following two assignments.

Page Contents

Background

For the first three assignments, we’ve used the official Raspberry Pi OS to test the Pi hardware and provide an operating environment. While Raspberry Pi OS is the Linux distribution promoted by the Raspberry Pi Foundation for use with these devices, it isn’t the only choice. Other distributions may provide different experiences and software stack availability, making them more suitable for different kinds of applications.

One alternative distribution that supports the Raspberry Pi is Alpine Linux. Alpine Linux is a distribution that is widely used in Docker containers due to its compact size and lightweight design. However, Alpine Linux is also fully usable as a general-purpose Linux distribution. In this role, Alpine Linux provides several distinct advantages over distributions like Raspberry Pi OS. For our purposes, these advantages are the smaller installation size, use of the musl C library, and lack of systemd.

Small Installation Size

Alpine Linux is optimized for small installation size using a combination of packaging techniques and compiler optimizations that support generating smaller binary files. This smaller size results in an Alpine Linux installation requiring less space on the MicroSD card. While smaller MicroSD cards can be used, yielding a modest cost savings, the bigger advantage is that flash memory storage generally has better performance and reliability when more free space is available. As data are written to the persistent storage, wear-leveling algorithms move the data around the physical storage media in order to avoid writing to one region of flash memory repeatedly, which can cause premature failure of the storage device. Wear leveling tends to be more effective when free space is readily available for new data writes.

The musl C Library

Unlike most Linux distributions, Alpine Linux uses the musl C library instead of the GNU C Library (glibc). The GNU C Library dates back to the late 1980s and has accumulated some technical debt, including some non-standard deviations from the C programming specification (which are sometimes marketed as “features”). On the other hand, musl is a much newer implementation (first released in 2011) that is intended to be small, portable, and standards-conforming.

Since most software on a Linux system is compiled from source, either by the distribution maintainer or the end user, it is normally possible to build applications against musl instead of glibc. For commercial, closed-source applications that have been built against glibc, libraries such as gcompat can be used to provide a compatibility layer. Alternatively, it is also possible to install a glibc-based distribution inside a chroot environment or container, or to use a solution like Flatpak to enable a glibc environment on top of Alpine Linux.

Lack of systemd

The majority of Linux distributions have adopted systemd as their runtime initialization systems and service managers. Had the systemd developers simply focused on an initialization and service management system using a loosely coupled, highly cohesive design, there might not be any advantage to omitting it from the system. However, the systemd developers instead decided to add unrelated functionality that goes far beyond system initialization and service management. This functionality is all over the place in terms of scope, including network management, DNS resolution with a history of security vulnerabilities, network time synchronization, bootloader management, and even systemd-homed, which allows user home directories to be mounted in arbitrary locations for the subset of systems for which that feature is actually useful. The lead author of systemd also hasn’t done the project any favors by his dismissive attitude toward security vulnerabilities, leading to the project receiving the lamest vendor award in 2017 for making software that is easy to compromise.

Linux systems using systemd have experienced various kinds of breakage due to bugs found in the software. A major issue with the tightly coupled, non-cohesive design of systemd is that it is a massive code base, already exceeding 1.2 million lines in 2019. Most or all of this code runs as the root user with elevated privileges, making it a ripe target for exploits. A great deal of it also runs as PID 1 on the system. If PID 1 crashes, the Linux kernel typically panics, resulting in a hard lockup. Both software bugs and exploits against systemd are thus excellent candidates for launching denial of service attacks.

Alpine Linux uses OpenRC, which is certainly not without its own faults. However, the amount of code running in PID 1 is significantly smaller, and the OpenRC project is far more focused on delivering an initialization and service management system. All the other bells and whistles can be added (if they are even necessary for a given system) using other software packages.

Procedure

This assignment is organized as a step-by-step tutorial. Be sure that you have a second MicroSD card available for this assignment. You will use Raspberry Pi OS on your first MicroSD card to download Alpine Linux and copy its initial set of files to the second MicroSD card. You’ll then be able to swap the MicroSD card and boot into the Alpine Linux installation environment.

Step 1: Obtain Alpine Linux

Begin by booting into Raspberry Pi OS. Use the Web browser (Firefox or Chromium, depending on which one you selected) to go to https://www.alpinelinux.org

On the Alpine Linux website, click the Downloads link at the top of the page. Scroll down to the Raspberry Pi section, and download the top aarch64 option. The download filename should end in .tar.gz. If you get a .img file instead, then you picked the wrong download.

Once the .tar.gz file has been downloaded, click the sha256 button immediately next to the download for the .tar.gz file. You should get a file ending in .tar.gz.sha256 (again, if it ends in .img.gz.sha256, then you downloaded the wrong one). Once this file has been downloaded, open a Terminal window and run the following commands:

cd Downloads
ls
sha256sum -c alpine-rpi-3.20.3-aarch64.tar.gz.sha256

Note that Alpine Linux may make a new point release at any time, so the version you get may be 3.20.4 (or later). Adjust the instructions accordingly.

If all goes well, you should see the following output:

alpine-rpi-3.20.3-aarch64.tar.gz: OK

Again, if a new update comes out the .3 might be a .4 or later version. What’s important is the “OK” at the end. If you see an error message, then something went wrong with the download. Remove both files and try this step again in this case, as bad things await if you’re starting from a corrupt file. Assuming the file is “OK,” proceed to the next step.

Step 2: Prepare the Second MicroSD Card

Plug your second MicroSD card into the USB adapter, and plug the USB adapter into any of the USB ports on the Raspberry Pi. You may see a dialog appear regarding a removable disk. Click the Cancel button, as we will be using the command line.

Run the command:

sudo dmesg

At the bottom of the output, you should see the device node that was created when you plugged in the USB adapter. Unless you have another USB drive attached to the Pi, this node will be sda.

By default, a “blank” MicroSD card contains a single FAT32 partition, which Raspberry Pi OS mounts automatically. To check this, run:

mount

If you see an entry for /dev/sda1, then the first step is to unmount:

sudo umount /dev/sda1

Now, let’s get rid of the FAT32 file system and the partition table on the MicroSD card. Run the following commands:

sudo wipefs -a /dev/sda1
sudo wipefs -a /dev/sda

Verify the partition table has been removed by running:

sudo fdisk -l /dev/sda

(Note: the -l is a dash followed by a lowercase L, short for “list.”)

You should see 5 lines of output, starting with an identifier for the disk (/dev/sda), followed by additional information about the disk type, units, sector size, and I/O size. If any partitions are listed under the I/O size, then the partition table has not been fully wiped. Re-check the above steps.

Step 3: Partition the MicroSD Card

Now, let’s partition the MicroSD card. We’re going to create a single 500 MiB FAT32 partition at the start of the card, followed by a single Linux partition that consumes the rest of the card. We need a DOS-style partition table for the Raspberry Pi, so we’re going to use the fdisk command in interactive mode:

sudo fdisk /dev/sda

Inside the fdisk program, you will see a prompt. You can type m and press Enter to see a list of available commands. To begin, print the partition table by running the p command. Verify that the “Disklabel type” is “dos” and that no partitions are listed after the line that begins with “disk identifier.”

Step 3.1: Create /dev/sda1

Create the first partition by running the n command. DOS partition tables support two categories of partitions: primary and extended. The reason for extended partitions is historical, and we won’t be using them here. Type p and press Enter to create a primary partition.

For the partition number, you can just press Enter to accept the default (1). Press Enter a second time to accept the default first sector (2048). We skip the first 2048 sectors of the drive for alignment purposes. 2048 sectors times the sector size of 512 means that we skip the first 1,048,576, or the first 1 MiB, of the drive before starting the first partition. This value was chosen as the default since it works for all modern hard disk drives, flash storage, and solid state drives. Physical sector sizes can vary across these devices, but 1 MiB winds up being a common multiple of all of them.

For the last sector, we want to limit the size of this partition to 500 MiB. This partition will be our boot partition, and it will only be used to hold the Linux kernel, initial ramdisk, and some firmware files needed by the Raspberry Pi. We’ll also temporarily use this partition to hold the installer files for Alpine Linux. To limit the size of this partition to 500 MiB, type +500M and then press Enter.

You will see a confirmation that the new partition was created. Run the p command to show the partition table. You should see a device labeled /dev/sda1, starting at sector 2048, and ending at sector 1026047, yielding a size of 500M. Note that the partition Id shows up as 83 with type Linux, which we need to fix.

Step 3.2: Change the Partition Type for /dev/sda1

To change the partition type, run the t command. Partition 1 will be selected automatically. For the hex code, type L and press Enter to list the codes. You will need to scroll up in the terminal window to see the whole list. Find the hex code for “W95 FAT32 (LBA),” which means the Windows 95 partition code for the FAT32 file system with logical block addressing. Once you find that hex code, type it into the prompt, and press Enter. You should see confirmation that the partition type has been changed from Linux to W95 FAT32 (LBA). Run the p command to verify that you change was successful.

Step 3.3: Set the Bootable Flag on /dev/sda1

Now we need to set the bootable flag on this partition, which is a legacy of DOS partition tables. To set this flag, run the a command. Partition 1 will be selected automatically. Run the p command again, and verify that the partition is bootable by the asterisk (*) under the Boot column in the output.

Step 3.4: Create /dev/sda2

Once our FAT32 partition has been created, our next step is to leave a partition into which we’ll install Alpine Linux later. To do this, create a second primary partition using the n command, and just press Enter to accept the default values for each setting. Run the p command again to verify. You should have a partition named /dev/sda2 with a starting sector at 1026048. Its size should be roughly the size of your MicroSD card less the 500 MiB we used for the first partition. For a 64 GB MicroSD card, the size should read around 59G. The partition id should be 83, with type Linux.

Step 3.5: Write and Verify the Partition Table

To finish partitioning the MicroSD card, we need to write the new partition table to the card. Run the w command in fdisk. You should see that the partition table has been written, and that fdisk has exited to the command prompt. Verify that the device nodes for the new partitions are present by running:

ls /dev/sda*

There should be 3 entries in the output:

Step 4: Create the FAT32 Filesystem on /dev/sda1

Partitioning a drive with fdisk only creates the disk partitions and sets flags to use when interpreting the partition table. It doesn’t create the data structures required by the actual file systems that will occupy the partitions. For now, we really only need to create the first file system, which will hold the Alpine Linux installation files. This will be our FAT32 file system, which is also known as “vfat” in Linux.

To create this file system on /dev/sda1, run the following command:

sudo mkfs.vfat /dev/sda1

If all is successful, the only output you will see is “mkfs.fat” with a version number and release date (4.2 and 2021-01-31 as of the time of this writing).

We will wait to create our second file system until after we’ve booted into the Alpine Linux installation environment.

Step 5: Mount /dev/sda1

Now we need to copy the Alpine Linux files onto the newly created FAT32 partition on the second MicroSD card. To do this, we must first mount the new partition inside Raspberry Pi OS. Run the following command:

sudo mount -o noatime /dev/sda1 /mnt

You’ll be using the “-o noatime” option for every mount operation performed as part of the installation procedure. This mount option disables file access timestamps, which would otherwise be written each time a file is read. Each write operation sent to the MicroSD card contributes to wear, so disabling access times will help to improve card longevity. In my early student research days, I once saw the atime writes completely destroy a compact flash card (an early kind of flash storage predating MicroSD) in a single weekend when a Linux system was left on for testing purposes. For this reason, I always recommend disabling atimes on any kind of flash media, including all solid state drives. Only a few relatively ancient pieces of software depend on atimes, with the command-line Mutt email client often cited.

Step 6: Untar the Alpine Archive into /mnt

Change directory to /mnt:

cd /mnt

Verify that you’re in /mnt by looking at the command prompt. Run the “pwd” command if you aren’t completely sure.

Now extract the Alpine Linux files by running (substitute the version you downloaded for 3.20.3, if necessary):

sudo tar xvf ~/Downloads/alpine-rpi-3.20.3-aarch64.tar.gz

For good measure, run:

ls

You should see a few directories in the output (apks, boot, and overlays), along with a bunch of .dtb files, the config.txt file, and several other files.

Step 7: Unmount /mnt

To be able to unmount /mnt successfully, we need to change the working directory of the shell to another directory first. The easiest way is to go back to the home directory by running:

cd

Now, unmount using:

sudo umount /mnt

Step 8: Shut Down and Swap Cards

Shut down Raspberry Pi OS correctly. This step can be performed by using the desktop menu or by running:

sudo poweroff

Wait for the green light to go out at the end of the Pi next to the MicroSD slot. Unplug the type C power adapter to be safe.

Remove the USB MicroSD card adapter from the Pi. Swap the MicroSD card from the adapter into the Pi, and put the MicroSD card containing Raspberry Pi OS (the one that started in the Pi) into the USB adapter to keep it from getting lost in your backpack.

Step 9: Boot the Alpine Linux Installation Environment

Plug in the type C power adapter, and the Pi should boot automatically. After a brief delay, the Alpine Linux installation environment will boot to a screen welcoming you to Alpine Linux and prompting you to log in to the machine (named localhost).

Type root and press Enter to log in as root with no password. You will see a greeting message followed by a command prompt.

Submission Checklist

Once you’ve booted into the installation environment and have logged in as root, use your cell phone to take a photo of the screen. Upload the photo to Moodle as the submission for this assignment.

If you are planning to stop here and continue with the next assignment later, run the following command to turn off the Pi properly:

poweroff

Once the screen has gone blank and the green light on the Pi next to the MicroSD slot has changed to red, unplug the USB power supply.

ABET Assessment

Successful completion of this assignment satisfies the following performance indicator: