[Docker Series Part 3] Ubuntu vs. Alpine - How to Pick a Base Image

한국어 버전

Part 2 explained how Dockerfiles connect images and containers. Now we use that idea to answer a practical question: which base image should you build on? For many high-school learners practicing Docker, the two names that appear most often are ubuntu and alpine. This post compares them so you can make a first choice confidently and know when to switch.

How this post flows

  1. What a base image changes in practice
  2. Terms you need before comparing Ubuntu and Alpine
  3. Why Ubuntu is usually the easier starting point
  4. Why Alpine is useful when image size matters
  5. A checklist you can reuse on real projects
  6. How this choice connects to multi-stage builds

Reading card

  • Estimated time: 15 minutes
  • Prereqs: Dockerfile basics and some experience installing software from a terminal
  • After reading: you can explain when Ubuntu is the safer default and when Alpine is worth testing.

Terms introduced here

  1. Base image: The starting filesystem and default toolset named in FROM.
  2. Package manager: A tool that installs software inside the image or container. Ubuntu uses apt; Alpine uses apk.
  3. glibc vs. musl: Two different C standard libraries. Ubuntu images usually use glibc, while Alpine uses musl, so some prebuilt binaries work on Ubuntu but need extra work on Alpine.
  4. Static binary: A compiled program that already includes the libraries it needs, so it can run on a very small image.

What a base image changes

Base images go beyond "which Linux is this?" They change the commands you type, the packages you can install, and the compatibility problems you may run into.

For beginners, these are the highest-impact differences:

  • Package manager: Ubuntu means apt; Alpine means apk.
  • Default shell and utilities: Ubuntu usually feels closer to mainstream Linux tutorials, while Alpine starts with BusyBox tools and sh.
  • Runtime library: Ubuntu and most mainstream Linux distributions use glibc, while Alpine uses musl.
  • Image size trade-off: Alpine images are much smaller, while Ubuntu images are larger but often easier for first labs and debugging.

If you have never used apt or apk, think of them as Linux versions of tools like npm install or pip install. They fetch software from the image's package repositories, install it, and track dependencies.

The glibc versus musl point sounds abstract at first, so use this shortcut:

  • Ubuntu is the "most tutorials just work" option.
  • Alpine is the "small and fast, but some packages need extra care" option.

What does that extra care look like? You might install a prebuilt tool and see an error such as not found or a message that mentions glibc. In that case, the issue is often not your command but the binary's expectation about the underlying Linux library.

When that happens, switching the project to Ubuntu is a reasonable move, especially while you are still learning Docker. If your goal is understanding images and containers instead of squeezing every megabyte out of a runtime image, Ubuntu usually keeps the first experiments smoother.

Reasons to choose Ubuntu

Students often start with Ubuntu for three practical reasons:

  1. Matches most teaching material: Linux guides frequently target Ubuntu LTS releases.
  2. Rich package catalog: apt install build-essential quickly unlocks compilers and system headers.
  3. Comfortable debugging environment: bash, common GNU utilities, and widely documented package names make trial and error less frustrating.

Compose example for an Ubuntu lab container:

services:
  ubuntu-lab:
    image: ubuntu:24.04
    command: ["bash", "-lc", "sleep infinity"]
    stdin_open: true
    tty: true

Ubuntu mini lab

  1. Launch the container.
docker run -it --name ubuntu-lab --rm ubuntu:24.04 bash
  1. Update packages and install common tools.
apt update && apt install -y git curl
  1. Inspect running processes.
ps aux | head -5

These commands give you a Linux playground with apt, bash, and familiar utilities. If you are learning command-line workflows for the first time, Ubuntu usually feels closer to the tutorials you find online.

Reasons to choose Alpine

Alpine serves a different goal set:

  1. Smaller images: alpine:3.20 stays in the tens-of-megabytes range, which speeds up downloads and lowers bandwidth use.
  2. Fast startup: Fewer default packages mean containers boot almost instantly.
  3. Minimal runtime surface: There is less tooling in the image, which is useful when you want a lean deployment target.

Keep a few points in mind:

  • The default shell is sh; scripts written for bash may need edits or an extra package install.
  • Package names differ. For example, use apk add curl instead of apt install curl.
  • Some prebuilt binaries expect glibc, so Alpine may need compatibility packages or a different base image.

Alpine mini lab

  1. Launch the container.
docker run -it --name alpine-lab --rm alpine:3.20 sh
  1. Install a couple of tools.
apk add --no-cache curl bash
  1. Confirm which Linux distribution is running.
cat /etc/os-release

These steps show what a "lightweight Linux" experience feels like. In production Dockerfiles, apk add --no-cache is a common way to avoid leaving package-index cache files behind. In a learning lab, the main point is simply to notice that Alpine uses a different package command and starts with fewer tools installed.

If you want a quick compatibility check before choosing Alpine, ask: "Do my dependencies already work on Alpine, or will they need recompilation or extra system packages?" If you do not know the answer yet, Ubuntu is the safer learning default.

Scenario-driven checklist

Question Recommend Ubuntu Recommend Alpine
Practicing Linux fundamentals?
Need images under 100 MB?
Need prebuilt packages that assume glibc?
Shipping a single static binary you built yourself?
Need many debugging tools?

Compose example running both images

services:
  ubuntu-lab:
    image: ubuntu:24.04
    command: ["bash", "-lc", "sleep infinity"]
    tty: true

  alpine-lab:
    image: alpine:3.20
    command: ["sh", "-lc", "sleep infinity"]
    tty: true

Start them with docker compose up -d, then attach with docker compose exec ubuntu-lab bash and docker compose exec alpine-lab sh. You will immediately notice different shell names, different package commands, and different expectations about what tools already exist inside the container.

When in doubt, fall back on these simple rules:

  1. If the goal is learning Linux commands and package installs, start with Ubuntu.
  2. If you must slim down deployment images, evaluate Alpine first.
  3. If Alpine throws compatibility errors, switching to Ubuntu is a normal decision, not a failure.

Next up: multi-stage builds

Once you settle on a base image, the next challenge is separating the build environment from the runtime environment inside one Dockerfile. That is also where this choice becomes strategic: many teams build with a fuller image and run with a slimmer one. Part 4 introduces multi-stage builds with a Node example, shows how to copy artifacts between stages, and explains how to keep runtime images lean without making the build process painful.

💬 댓글

이 글에 대한 의견을 남겨주세요