Compare commits
No commits in common. "1c7c029c734805a0cb76e907c01976603961e009" and "b2a357c0c2c8b8025864f438dba9f4d918f0baa4" have entirely different histories.
1c7c029c73
...
b2a357c0c2
|
@ -1,168 +0,0 @@
|
||||||
---
|
|
||||||
title: Alpine Linux Homelab
|
|
||||||
date: 2023-12-22
|
|
||||||
tags:
|
|
||||||
- computers
|
|
||||||
---
|
|
||||||
|
|
||||||
A few days ago, my root filesystem crashed.
|
|
||||||
|
|
||||||
This isn't as big a deal as it would have been before containers:
|
|
||||||
because the filesystem was happy enough that docker could start,
|
|
||||||
all of my services were able to run, since they live on another filesystem.
|
|
||||||
Weird.
|
|
||||||
But still,
|
|
||||||
it needed to be repaired,
|
|
||||||
so I could run things like `git` (which had become corrupted).
|
|
||||||
|
|
||||||
A few of my pals have been using Alpine Linux for a while.
|
|
||||||
I've used similar distributions--tinycore and OpenWRT--so
|
|
||||||
I sort of knew what Alpine was about.
|
|
||||||
And I've used Alpine a whole lot in container images,
|
|
||||||
because it's just so gosh darn small.
|
|
||||||
So I dove in on that.
|
|
||||||
|
|
||||||
2 hours later, I had a whole working system,
|
|
||||||
running my containerized services just like before.
|
|
||||||
This is an absolutely bonkers fast redeployment,
|
|
||||||
and I owe a lot of that to how dead simple Alpine is.
|
|
||||||
|
|
||||||
Setup
|
|
||||||
-----
|
|
||||||
|
|
||||||
I've got Alpine booting on my Raspberry Pi in "diskless" mode.
|
|
||||||
That means it loads the entire operating system into RAM.
|
|
||||||
It then mounts my 12TB btrfs array,
|
|
||||||
which has all the containerized services,
|
|
||||||
and launches podman to start them all up.
|
|
||||||
|
|
||||||
If I need to make system-wide changes,
|
|
||||||
I can just edit files in `/etc` and run
|
|
||||||
`lbu commit`, which will pick up changes and write them out
|
|
||||||
as a tarball
|
|
||||||
to my normally read-only SD card.
|
|
||||||
This is a Big Deal when you're booting from an SD card,
|
|
||||||
because those things can't handle lots of writes.
|
|
||||||
I've also got a service running that copies the tarballs
|
|
||||||
onto the 12TB btrfs system,
|
|
||||||
so I should be able to get back online in under an hour if I lose this card.
|
|
||||||
|
|
||||||
I moved from Docker to Podman because the latter uses about half the space on the root filesystem.
|
|
||||||
That's important to me,
|
|
||||||
because the root filesystem is in RAM.
|
|
||||||
|
|
||||||
|
|
||||||
RAM Disk
|
|
||||||
--------
|
|
||||||
|
|
||||||
Running a production machine entirely from RAM may seem foolish,
|
|
||||||
especially on a Raspberry Pi.
|
|
||||||
But it's actually pretty svelte:
|
|
||||||
|
|
||||||
Filesystem Size Used Available Use% Mounted on
|
|
||||||
tmpfs 3.8G 108.8M 3.7G 3% /
|
|
||||||
|
|
||||||
That's right, the entire host OS,
|
|
||||||
including all the junk needed for networking and podman,
|
|
||||||
takes up 108MB of the 8GB on this system.
|
|
||||||
That's just 1.35%!
|
|
||||||
|
|
||||||
I haven't checked,
|
|
||||||
but I have a sneaking suspicion that base Ubuntu uses more RAM than that,
|
|
||||||
with all the services it kicks up.
|
|
||||||
|
|
||||||
|
|
||||||
Podman
|
|
||||||
------
|
|
||||||
|
|
||||||
At my previous job,
|
|
||||||
I played around with podman a little.
|
|
||||||
It is more or less a replacement for Docker,
|
|
||||||
although it doesn't have swarm mode.
|
|
||||||
|
|
||||||
I gave it a shot in this conversion,
|
|
||||||
after being irritated that Docker itself frequently used over 10% of the CPU,
|
|
||||||
and quite a lot of RAM.
|
|
||||||
|
|
||||||
It turned out that podman not only doesn't appear to show up in the CPU usage,
|
|
||||||
but it also takes about half the space on the RAM disk as Docker did.
|
|
||||||
Running podman as root just worked out of the box:
|
|
||||||
I had to create two files in `/etc` to map my uid and gid
|
|
||||||
to get it working for my user account,
|
|
||||||
but now that's working nicely too.
|
|
||||||
|
|
||||||
I'm not using podman pods, though.
|
|
||||||
I looked into this once,
|
|
||||||
and it seemed to require learning a new schema for all kinds of things,
|
|
||||||
and maintaining hundreds of lines of YAML.
|
|
||||||
I know runit and bourne shell pretty well,
|
|
||||||
and I know how to launch individual podman containers with a shared bridge network,
|
|
||||||
so I'm just doing that.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
A Beefier System
|
|
||||||
----------------
|
|
||||||
|
|
||||||
All of my services are running in containers.
|
|
||||||
At some point I realized:
|
|
||||||
why not put my login shell in a container, too?
|
|
||||||
So I did.
|
|
||||||
|
|
||||||
My work building that is in my
|
|
||||||
[toolbox repository](https://git.woozle.org/neale/toolbox),
|
|
||||||
but the summary is that I'm running a fat Alpine inside my lean host Alpine.
|
|
||||||
It still uses lbu and apk for preserving state,
|
|
||||||
but I can stretch out and install bash, vim, and even emacs.
|
|
||||||
I have a gigantic magnetic disk behind it,
|
|
||||||
I don't have to worry about storage space used by the OS in this setup.
|
|
||||||
|
|
||||||
Every time the container starts,
|
|
||||||
it reinstalls all the packages I have set up,
|
|
||||||
from the cached package repository I bind-mounted into the container from the btrfs array.
|
|
||||||
If I install new packages,
|
|
||||||
or update existing ones,
|
|
||||||
that updates the cache.
|
|
||||||
|
|
||||||
The tooling to do all this is minimal.
|
|
||||||
I encourage you to
|
|
||||||
[check out the repository](https://git.woozle.org/neale/toolbox)
|
|
||||||
if you're interested.
|
|
||||||
Most of the work is in the
|
|
||||||
[init script](https://git.woozle.org/neale/toolbox/src/branch/main/sbin/toolbox-init),
|
|
||||||
and most of the time getting *that* working correctly
|
|
||||||
was just me realizing that Alpine already had mechanisms for everything I wanted.
|
|
||||||
|
|
||||||
|
|
||||||
Runit
|
|
||||||
-----
|
|
||||||
|
|
||||||
When I managed my own (tiny) Linux distribution,
|
|
||||||
I became a fan of Dan Bernstein's "runit" init system.
|
|
||||||
Alpine was happy to let me set that up,
|
|
||||||
even providing a little `init.d` script to have their built-in openrc start runit.
|
|
||||||
|
|
||||||
Because runit uses files and filesystem pipes,
|
|
||||||
I can `sv restart /host/etc/services/foo` inside my "fat Alpine" container,
|
|
||||||
to restart the foo service *on the host OS*.
|
|
||||||
This lets me use my fat editor on service files,
|
|
||||||
and restart things without hopping onto the host OS.
|
|
||||||
|
|
||||||
|
|
||||||
Closing
|
|
||||||
-------
|
|
||||||
|
|
||||||
Moving from Ubuntu to Alpine gave me the following benefits:
|
|
||||||
|
|
||||||
* Boot time is down
|
|
||||||
* Memory use is down (I think)
|
|
||||||
* CPU use is down, and as a corrolary, so is energy use
|
|
||||||
* Absolute certainty that my system configuration is preserved in backup,
|
|
||||||
because every time I boot, I restore the system (into RAM) from that backup
|
|
||||||
* I get to keep all my creature comforts like bash, btop, vim, emacs, and the like
|
|
||||||
* If my root filesystem ever crashes again, I can just make a new Alpine SD card,
|
|
||||||
copy a backup tarball onto it, and I get my system back
|
|
||||||
|
|
||||||
Thanks to Nick Moffitt for blabbing about Alpine enough to get me interested,
|
|
||||||
and for providing some setup instructions (which I eventually completely undid)
|
|
||||||
to get me started quickly!
|
|
Loading…
Reference in New Issue