07 — Containers and VMs¶
Containers and VMs solve two problems for a C engineer: reproducible builds (“works on my machine” is a career-limiting phrase) and cross-platform testing (does your code work on musl? on ARM? on an older glibc?). You don’t need Kubernetes; you need three tools: a Docker runtime, QEMU, and a lightweight Linux VM.
Docker on macOS — OrbStack (recommended)¶
OrbStack is a native macOS Docker runtime + Linux VM manager built on Apple’s virtualization framework. Fast startup (~2s), tiny footprint, and it also runs Linux VMs alongside containers.
Install: brew install --cask orbstack. Free tier is enough for personal use; Pro is $8/month.
Two commands you’ll use daily:
# Run any Docker command; it just works with the docker CLI
docker run --rm -it -v $(pwd):/work -w /work ubuntu:26.04 bash
# Spin up a full Linux VM (persistent, not a container)
orb create ubuntu:26.04 dev
orb -m dev
The orb -m dev command drops you into a real Ubuntu shell that shares your home directory. Perfect for “run perf on this program right now.”
Docker on macOS — Colima (pure-OSS alternative)¶
Colima is the open-source, CLI-only alternative. Slower startup (~10s), 1-way file sharing, but zero closed-source dependencies.
Install: brew install colima docker. Then colima start.
Use Colima if: you object to closed-source tools or your employer’s security policy blocks OrbStack.
Use OrbStack if: you want the fastest daily-driver experience.
Docker on Linux¶
On Ubuntu 26.04, install Docker Engine directly: https://docs.docker.com/engine/install/ubuntu/. Native performance, no VM overhead.
Reproducible C builds via Docker¶
A Dockerfile for a reproducible dev environment:
FROM ubuntu:26.04
RUN apt-get update && apt-get install -y \
build-essential gcc-15 clang-20 lldb gdb \
make cmake ninja-build meson pkg-config \
valgrind mold ccache \
git ripgrep fd-find bat fzf tmux \
libssl-dev libcurl4-openssl-dev zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /work
Build once (docker build -t c-dev .), then docker run --rm -it -v $(pwd):/work c-dev bash. Every teammate gets the same compiler versions.
The “run it in Alpine” trick — test against musl¶
Most Linux systems use glibc. Alpine Linux uses musl libc. Musl is stricter about pointer alignment, more careful about errno, and often exposes bugs glibc’s forgiveness hides. Serious C code should be tested against both.
docker run --rm -it -v $(pwd):/work -w /work alpine:3.20 sh
# Inside:
apk add build-base gcc make
gcc -std=c17 -Wall -Wextra -O2 foo.c -o foo
./foo
If your code compiles cleanly on both glibc and musl, and passes ASan on both, you have caught 90% of libc-portability bugs.
QEMU — cross-arch testing¶
QEMU emulates architectures. You write C on your Apple Silicon Mac and want to test on x86_64, RISC-V, or ARMv7? QEMU handles it.
Two modes:
User-mode QEMU (run a binary from another arch):
# On Apple Silicon Mac, run an x86_64 Linux binary
docker run --rm -it --platform linux/amd64 -v $(pwd):/work ubuntu:26.04 bash
# Docker Desktop / OrbStack handle QEMU under the hood
System-mode QEMU (full VM of another arch):
qemu-system-riscv64 -M virt -kernel bbl -append "..." # boot a RISC-V kernel
For a C learner in 2026, the --platform linux/amd64 container trick is the 90% use case. Full QEMU is a M12+ topic when you want to boot your own kernel.
Lightweight Linux VMs on Mac¶
If you want a persistent Ubuntu VM (not a per-run container):
Tool |
Pros |
Cons |
|---|---|---|
OrbStack VM |
2s boot, native macOS integration, shared home dir |
Requires OrbStack |
Lima ( |
Free, scriptable, YAML-configurable |
Slower than OrbStack |
Multipass ( |
Canonical’s tool, Ubuntu-focused, easy “launch a VM” workflow |
Slower cold boot |
UTM.app |
Full GUI VM manager, supports x86 emulation on Apple Silicon |
Overkill for headless dev |
Full VMware Fusion / Parallels |
Feature-rich |
Paid |
Recommendation: OrbStack’s built-in VMs if you’re already using OrbStack for Docker. Otherwise, Lima.
What you don’t need¶
Kubernetes — nope, not for C dev.
Docker Swarm — no.
Podman — fine, but Docker CLI is what every project’s README assumes; stick with the tribe.
Vagrant — solves a 2015 problem; OrbStack/Lima/Multipass are the 2026 answers.
What most people get wrong about containers for C¶
They think containers are for shipping production, not for development. Flip it: containers are your dev environment’s escape hatch. When something is behaving differently between your Mac and Linux CI, spin an Ubuntu container in 2 seconds and reproduce it. You will use this pattern hundreds of times.
Return to README.md · Next: 08_ai_assist_for_c.md