Docker on Alpine Linux

2021/04/10

I am trying out Pi-hole on a Raspberry Pi, but more on the specifics in another post. Alpine Linux is not one of the supported Linux distributions, so instead I use the offical Docker image with Pi-hole.

I have previously written about installing Alpine Linux on a Raspberry Pi, but now I use the default Alpine approach of running the OS from memory. I use the rest of the SD card as cache and storage.

Installing Alpine Linux

I prepare the SD card on another computer running Ubuntu.

Format SD card

The first thing is to identify the SD card. With a new SD card I see something like this:

$ lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
mmcblk0     179:0    0  14,9G  0 disk
└─mmcblk0p1 179:2    0  14,9G  0 part /media/robert/3636-3339

When the SD card is formatted as described below I see this instead (with mount points for mmcblk0p2 for mmcblk0p3):

$ lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
mmcblk0     179:0    0  14,9G  0 disk
├─mmcblk0p1 179:1    0   255M  0 part
├─mmcblk0p2 179:2    0   1,8G  0 part
└─mmcblk0p3 179:3    0  12,9G  0 part

If some partitions are mounted, they should be unmounted with sudo umount /path/to/mountpoint. Inspired by https://vincentserpoul.github.io/post/alpine-linux-rpi0 I create three partitions:

  1. The boot partition with Alpine Linux itself.
  2. A partition for cache and config files.
  3. A “storage” partition for e.g. Docker images.

This can be achieved with GNU parted(8):

sudo parted --script -a optimal /dev/mmcblk0 \
    mklabel msdos \
    mkpart primary fat32 0% 256MiB \
    mkpart primary ext4 256MiB 1GiB \
    mkpart primary ext4 1GiB 100% \
    set 1 boot on

Afterwards the result can be inspected with fdisk(8):

$ sudo fdisk -l /dev/mmcblk0

Device         Boot   Start      End  Sectors  Size Id Type
/dev/mmcblk0p1 *       2048   524287   522240  255M  c W95 FAT32 (LBA)
/dev/mmcblk0p2       524288  2097151  1572864  768M 83 Linux
/dev/mmcblk0p3      2097152 31115263 29018112 13,9G 83 Linux

If the boot partition does not have a * in the Boot column the Raspberry Pi does not boot. This happens if the parted command has e.g. mklabel gpt instead of mklabel msdos and the result is visible with fdisk:

$ sudo fdisk -l /dev/mmcblk0

Device           Start      End  Sectors  Size Type
/dev/mmcblk0p1    2048   524287   522240  255M EFI System
/dev/mmcblk0p2  524288  4194303  3670016  1,8G Linux filesystem
/dev/mmcblk0p3 4194304 31115263 26920960 12,9G Linux filesystem

When the partitions are created successfully they must be formatted:

sudo mkfs.vfat -F 32 /dev/mmcblk0p1
sudo mkfs.ext4 /dev/mmcblk0p2
sudo mkfs.ext4 /dev/mmcblk0p3

Install Alpine Linux

Download a suitable tar ball from Alpine’s web page. At the time of writing the latest version is 3.13.3. The tar ball has to be extracted onto the boot partition of the SD card, which we do by mounting this partition.

sudo mkdir /mnt/alpine
sudo mount /dev/mmcblk0p1 /mnt/alpine
sudo tar -xzf /path/to/alpine-rpi-3.13.3-armhf.tar.gz --no-same-owner -C /mnt/alpine
sudo umount /mnt/alpine
sudo rmdir /mnt/alpine

On the Pi

When the Pi is turned on you should soon see the login prompt. Login as root with an empty password.

First we mount the second and third partition. This ensures that the upcoming setup can use mmcblk0p2.

mkdir /media/mmcblk0p2
mkdir /media/mmcblk0p3
mount /dev/mmcblk0p2 /media/mmcblk0p2
mount /dev/mmcblk0p3 /media/mmcblk0p3

Run the setup and remember to set config and cache partition to mmcblk0p2:

setup-alpine

To keep the installation small all changes has to be explicitly persisted using the lbu command – known as Alpine local backup. Run lbu commit to persist the settings so far.

There are some shell commands that I use constantly when navigating. I set these system wide in /etc/profile to ensure that they also work for root.

alias ll='ls -l'
alias la='ls -la'
alias ..='cd ..'

(To enable the system wide settings when changing to root from another user we use su -. Notice the dash.)

Finally, I want to auto mount mmcblk0p3 by editing the file /etc/fstab. In my case it should look like this by adding the last line:

/dev/cdrom      /media/cdrom    iso9660 noauto,ro 0 0
/dev/usbdisk    /media/usb      vfat    noauto,ro 0 0
/dev/mmcblk0p1 /media/mmcblk0p1 vfat ro,relatime,fmask=0022,dmask=0022,errors=remount-ro 0 0
/dev/mmcblk0p2 /media/mmcblk0p2 ext4 rw,relatime 0 0
/dev/mmcblk0p3 /media/mmcblk0p3 ext4 rw,relatime 0 0

Non-root user

I prefer to have a non-root user that has permission to change to root. The user is named robert, has its own group named robert and is also a member of the wheel group:

addgroup robert
adduser robert robert
adduser robert wheel

This creates the home folder for robert in /home/robert. To allow users in the wheel group to change to root, we must edit the file /etc/sudoers. The safe way to do this is with visudo that we get with sudo.

apk update
apk add sudo

Run visudo and uncomment the line wheel ALL=(ALL) ALL.

To make SSH access easier I setup SSH keys. First create ~/.ssh. On another computer I setup the Pi as pihole in ~/.ssh/config. Then I can copy the relevant public key to the Pi with scp:

scp ~/.ssh/id_rsa.pub pihole:~/.ssh/authorized_keys

Note from https://wiki.alpinelinux.org/wiki/Alpine_local_backup that by default lbu only cares about /etc. To persist the changes in elsewhere we must add this to lbu’s watch list. I do not include the entire home dir since this will also include shell history.

lbu include /home/robert/.ssh/authorized_keys

Docker

Docker is available for Alpine in a “community” repository. Edit /etc/apk/repositories to include:

http://dl-cdn.alpinelinux.org/alpine/latest-stable/community

Now Docker (and here also Docker Compose) can be installed:

apk update
apk add docker
apk add docker-compose

The user robert should also have permission to run docker commands, here achieved by adding robert to the docker group.

adduser robert docker
rc-update add docker boot
service docker start

Docker image location

Docker images are big and I want store them on the “storage” partition of the SD card. By default, Docker images are stored in /var/lib/docker. This folder can be moved in the following manner as root:

service docker stop
cp --archive /var/lib/docker /media/mmcblk0p3/

Create the file /etc/docker/daemon.json with the content

{
   "data-root": "/media/mmcblk0p3/docker"
}

Finally, Docker can be started again:

service docker start

Remember to persist the changes. If this works as intended the folder /var/lib/docker can be removed.

>> Home