Alpine Linux

2019-06-11

Alpine Linux is an awesome Linux distro. Minimal, simple, secure.

I have often longed for a simpler, more secure, more understandable, more correct operating system. That search led me to the various BSD variants, to illumos, SmartOS and while they had awesome features: Dtrace, ZFS, containers that are more secure than VMs etc using them didn't make my life simpler.

Most of my clients, and therefore most of my work, was (and is) on Linux, so I had to know and stay up to date on multiple OSes. I had to resolve odd (and often harry) bugs that only showed up in non-Linux environments. Then too Linux has been gaining ground on those awesome features: Linux now has eBPF which is a reasonable replacement for DTrace, the ZFS on Linux project is now the de facto "Master" for ZFS development, and Docker is the container run time that is eating the world and to be fair, Docker's APIs are a lot nicer than SmartOS's where, and for running trusted code alongside trusted code we don't need the additional isolation.

I've also found that a worse is better approach in regards file systems is better. ZFS really is an awesome file system, perhaps the last word on file systems, and maybe in another 10 years we'll all be running it. But until then ext4 and traditional snapshoting and backup tools, along with some Docker volume management is just a more practical solution for the small to medium (ie 10-100 million/year in revenue) companies I like to work with.

It's been sad to see Joyent's public cloud's end of life and I'll miss ZFS, and in particular Manta but truth be told I'd already mostly stopped using them earlier this year.

So what have I turned to as a simple, better solution than a BSD Unix, or SmartOS, or Debian/Ubuntu? Alpine.

As a server solution Alpine let's you keep the — the truly awesome SmartOS practice — of complete separation of OS and application. If you haven't used SmartOS it might come as a surprise that you can't modify the OS. You don't have to worry about someone installing malware or messing with the OS configuration, it is immutable. You also don't have to provision a partition on disk, it will just boot from a USB thumb drive, load itself into RAM, and then you have the full machine to run your application on.

On the desktop Alpine has all of Linux's advantages — namely drivers for laptop and desktop grade hardware and a plethora of window managers / desktop environments.

As a container OS, the docker community has already embraced it for it's small size, fast package manager etc. So many official images have a Alpine option.

Lastly while the hardened kernel that used to ship as the default for versions prior to 3.8 didn't play nicely with Docker as a host, Alpine 3.8 and onward work excellently out-of-the-box as docker hosts.

The only thing that is left is how to run it everywhere. Many cloud providers don't (yet?) offer it as an official image. But where you can bring your own image (ie AWS, Google, Azure) the Alpine community has some [packer scripts to get you started](https://github.com/mcrute/alpine-ec2-ami). In places where that won't work, you can do the more esoteric (& fun) option of installing Alpine from inside another OS. And no that doesn't require a dual boot, after rebooting you will have a clean Alpine install.

Here is a script that I use to install Alpine on a bare metal host at OVH:

#!/bin/sh

set -ex

PATH=/bin:/sbin:/usr/bin:/usr/sbin
HOST=alpine
USER=pioneer
ROOT_FS=ext4
BOOT_FS=ext4
FEATURES="ata base ide scsi usb virtio $ROOT_FS"
MODULES="sd-mod,usb-storage,$ROOT_FS"
REL=3.8 # from https://alpinelinux.org don't use third dot
MIRROR=http://dl-cdn.alpinelinux.org/alpine
REPO=$MIRROR/v$REL/main
# from https://pkgs.alpinelinux.org/packages?name=apk-tools-static&branch=v3.8&arch=x86_64
APKV=2.10.1-r0
DEV=/dev/sda
BOOT_DEV=${DEV}1
ROOT_DEV=${DEV}2
ROOT=/mnt
BOOT=/mnt/boot
ARCH=$(uname -m)

sgdisk --zap-all $DEV
sgdisk --new 1:0:+512M $DEV
# the type is from

sgdisk --list-types` 8300 is Linux filesystem sgdisk --typecode 1:8300 $DEV sgdisk --change-name 1:boot $DEV sgdisk --new 2:0:0 $DEV # zero means max here sgdisk --typecode 2:8300 $DEV sgdisk --change-name 2:root $DEV sgdisk --attributes 1:set:2 $DEV

# -m reserved-blocks-percentage # -q Quiet execution. # -L new-volume-label mkfs.$BOOT_FS -m 0 -q -L boot $BOOT_DEV mkfs.$ROOT_FS -q -L root $ROOT_DEV mount $ROOT_DEV $ROOT mkdir $BOOT mount $BOOT_DEV $BOOT

curl -s $MIRROR/v$REL/main/$ARCH/apk-tools-static-${APKV

.apk | tar xz

./sbin/apk.static --repository $REPO \ --update-cache \ --allow-untrusted \ --root $ROOT \ --initdb add alpine-base syslinux dhcpcd linux-vanilla

cat << EOF > $ROOT/etc/fstab $ROOT_DEV / $ROOT_FS defaults,noatime 0 0 $BOOT_DEV /boot $BOOT_FS defaults 0 2 EOF

echo $REPO > $ROOT/etc/apk/repositories

cat /etc/resolv.conf > $ROOT/etc/resolv.conf

cat << EOF > $ROOT/etc/update-extlinux.conf overwrite=1 vesa_menu=0 default_kernel_opts="quiet" modules=$MODULES root=$ROOT_DEV verbose=0 hidden=1 timeout=1 serial_port= serial_baud=115200 password='' EOF

cat << EOF > $ROOT/etc/network/interfaces auto lo iface lo inet loopback

auto eth0 iface eth0 inet dhcp hostname $HOST EOF

mount --bind /proc $ROOT/proc mount --bind /dev $ROOT/dev mount --bind /sys $ROOT/sys

chroot $ROOT /bin/sh -x << CHROOT apk update apk add openssh

setup-hostname -n $HOST

rc-update -q add devfs sysinit rc-update -q add dmesg sysinit rc-update -q add mdev sysinit rc-update -q add hwdrivers sysinit

rc-update -q add hwclock boot rc-update -q add modules boot rc-update -q add sysctl boot rc-update -q add hostname boot rc-update -q add bootmisc boot rc-update -q add syslog boot rc-update -q add networking boot rc-update -q add urandom boot rc-update -q add dhcpcd boot

rc-update -q add mount-ro shutdown rc-update -q add killprocs shutdown rc-update -q add savecache shutdown

rc-update -q add acpid default rc-update -q add crond default rc-update -q add sshd default

echo features=""$FEATURES"\" > /etc/mkinitfs/mkinitfs.conf

extlinux -i /boot dd bs=440 conv=notrunc count=1 if=/usr/share/syslinux/gptmbr.bin of=$DEV update-extlinux CHROOT

chroot $ROOT passwd chroot $ROOT adduser -s /bin/ash -D $USER chroot $ROOT passwd $USER

umount $ROOT/proc umount $ROOT/dev umount $ROOT/sys umount $BOOT umount $ROOT `