Server OS Choice: Ubuntu vs. Alpine
For VMs, Ubuntu has been our first choice for years. Alpine dominates in containers. The decision is less ideological and more practical.
Ubuntu: The Workhorse
Ubuntu Server LTS brings glibc, systemd, broad hardware support, and a predictable support cycle of 5+5 years. Nearly every software has an Ubuntu package or a tested installation path.
In VMs, this is our standard — Proxmox host, then Ubuntu VM, then Docker on top. The overhead of a few hundred MB of image size plays no role in VMs. What matters is: operation is predictable, security updates arrive via unattended-upgrades, and anyone on the team can jump in without onboarding in an emergency.
Alpine: The Container Queen
Alpine is tiny — ~5 MB base image. It uses musl instead of glibc and busybox instead of GNU Coreutils. This reduces the attack surface and image size, but it means: many binaries expect glibc and won’t run without adjustment.
In the container registry, Alpine therefore dominates rightly. For microservices that only need their own binary and minimal dependencies, there is nothing slimmer.
The musl Difference
musl is correct, but DNS resolution behaves differently than under glibc. Some software (e.g., older Node.js versions, some Python wheels with C extensions) causes trouble. This is no reason against Alpine, but you need to know it before spending three hours debugging.
Direct Comparison
| Criterion | Ubuntu LTS | Alpine |
|---|---|---|
| libc | glibc | musl |
| Base Image | several hundred MB | ~5 MB |
| Tooling | GNU Coreutils, systemd | busybox |
| Compatibility | very broad | occasional adjustment needed |
| Support | 5+5 years LTS | rolling, lean |
| Ideal for | VMs & Host Systems | Containers / Microservices |
The Third Option: distroless & Wolfi
Between "fat but compatible" and "tiny but musl," a third class has established itself: distroless images (only the application plus runtime, no shell, no package manager) and Wolfi/Chainguard images — minimal, but glibc-based and focused on as few CVEs as possible. Where small attack surface and glibc compatibility matter, they are often the better answer than Alpine.
Our Rule of Thumb
Ubuntu LTS for VMs and host systems. Alpine for containers, where it fits. If a container image on Alpine doesn’t run cleanly, we switch to debian:slim or a Wolfi image — still small enough, but glibc-compatible.
Conclusion
Alpine is no replacement for Ubuntu, but the right kernel for container workloads. Ubuntu is the right kernel for anything meant to run longer than a day and be maintained by people.
Should we move everything to Alpine for smaller images?+
No. The article draws a clear line: Ubuntu LTS for VMs and host systems, Alpine only for containers where it fits. In VMs the overhead of a few hundred MB is irrelevant — predictable operation and the ability for anyone on the team to step in without onboarding matter more. If a container image doesn't run cleanly on Alpine, we switch to debian:slim or a Wolfi image.
What pitfalls does musl bring compared to glibc?+
musl is correct, but DNS resolution behaves differently than under glibc. Some software causes trouble — older Node.js versions or Python wheels with C extensions that expect glibc and won't run without adjustment. This is no reason against Alpine, but you should know it before spending three hours debugging.
Is there a middle ground between heavy Ubuntu and musl-Alpine?+
Yes. Distroless images contain only the application plus runtime — no shell, no package manager. Wolfi/Chainguard images are also minimal, but glibc-based and designed for as few CVEs as possible. Where a small attack surface and glibc compatibility both matter, they are often the better answer than Alpine.