How to Build Custom Container Images with Moby on Linux 2025
How to Build Custom Container Images with Moby on Linux 2025
The Moby Project provides the foundational components to build containerized systems without relying on the Docker daemon. If you're working on a project that needs fine-grained control over container image building or want to understand how Docker's container engine works under the hood, Moby offers modular, swappable components that let you assemble a custom container pipeline.
This guide walks you through building container images using Moby's toolkit on Linux, focusing on practical steps for developers who want to move beyond the standard Docker daemon.
Understanding Moby's Architecture
Moby is not a replacement for Docker itself—it's the upstream open-source project that Docker is built from. The key difference is philosophy: Moby provides "batteries included but swappable" components. You get container build tools, registries, runtimes, and orchestration pieces that you can mix and match.
The main components you'll interact with for image building are:
- BuildKit: A modern build system for container images (more efficient than legacy builders)
- containerd: A lightweight container runtime specification-compliant implementation
- runc: A low-level container runtime that manages the actual container processes
Prerequisites
Before starting, ensure you have:
- A Linux system (Ubuntu 20.04 LTS or later recommended)
- Root or sudo access
- Basic understanding of Docker/container concepts
- Go 1.20 or later (if compiling from source)
gitinstalled
Step 1: Install containerd and runc
The foundation of Moby is containerd, the container runtime. Install it on your Linux system:
# Download the latest containerd release
wget https://github.com/containerd/containerd/releases/download/v1.7.18/containerd-1.7.18-linux-amd64.tar.gz
# Extract to /usr/local
sudo tar -C /usr/local -xzf containerd-1.7.18-linux-amd64.tar.gz
# Create systemd service
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
# Start containerd
sudo systemctl start containerd
sudo systemctl enable containerd
Verify installation:
containerd --version
# Output: containerd github.com/containerd/containerd v1.7.18 ...
Next, install runc (the OCI runtime):
wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
runc --version
Step 2: Set Up BuildKit
BuildKit is Moby's modern build system. It's more efficient and feature-rich than the legacy builder:
# Download BuildKit
wget https://github.com/moby/buildkit/releases/download/v0.12.5/buildkit-v0.12.5.linux-amd64.tar.gz
# Extract
sudo tar -C /usr/local -xzf buildkit-v0.12.5.linux-amd64.tar.gz
# Verify
buildkitd --version
Start the BuildKit daemon:
# Run as background service
sudo buildkitd &
# Or use systemd (create /etc/systemd/system/buildkit.service)
[Unit]
Description=BuildKit
After=network.target
[Service]
Type=notify
ExecStart=/usr/local/bin/buildkitd
Restart=always
[Install]
WantedBy=multi-user.target
Step 3: Create a Simple Dockerfile
Create a test Dockerfile to build:
# Dockerfile
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
curl \
git \
build-essential
WORKDIR /app
COPY . .
RUN echo "Built with Moby BuildKit"
CMD ["/bin/bash"]
Step 4: Build the Image with BuildKit
Use buildctl (the BuildKit CLI) to build:
# Build image and load into containerd
buildctl build \
--frontend=dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=localhost/my-app:latest,push=false
For a more practical workflow, you can also use containerd directly with BuildKit:
buildctl build \
--frontend=dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=oci,dest=/tmp/image.tar
Then import into containerd:
ctr image import /tmp/image.tar
Step 5: Run the Container
Once built, run it with containerd's ctr command:
# List images
ctr image ls
# Run container
ctr run --rm localhost/my-app:latest my-container /bin/bash
Or use nerdctl (a Docker-like CLI for containerd):
# Install nerdctl
wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz
sudo tar -C /usr/local -xzf nerdctl-1.7.6-linux-amd64.tar.gz
# Use familiar Docker-like commands
nerdctl run --rm localhost/my-app:latest /bin/bash
Moby vs Standard Docker: Key Differences
| Aspect | Moby | Docker Desktop | |--------|------|----------------| | Target Audience | Developers, integrators, hackers | End users, enterprises | | Support | Community, best-effort | Commercial support available | | Modularity | Swappable components | Integrated stack | | Learning Curve | Steeper (manual setup) | Gentle (pre-configured) | | Customization | High (build your own stack) | Limited (Docker's way) | | Use Case | Custom container systems, edge computing | Development, testing, deployment |
Common Pitfalls and Solutions
Issue: BuildKit daemon won't start
Ensure containerd is running first, and check logs:
sudo journalctl -u buildkit -n 50
Issue: Permission denied errors
Add your user to the containerd group:
sudo usermod -aG containerd $USER
newgrp containerd
Issue: Image not appearing in ctr image ls
Verify the image was actually imported:
ctr image list --quiet
Why Choose Moby?
Moby excels when you need:
- Custom container runtimes for embedded systems or Kubernetes nodes
- Lightweight setups without full Docker Desktop overhead
- Understanding of container fundamentals by working with modular pieces
- Integration into larger systems like CI/CD pipelines or edge devices
The Moby Project's philosophy aligns with developers who want to understand how containers work and build systems tailored to their specific requirements, rather than accepting Docker's opinionated stack as-is.
Next Steps
Now that you have a working Moby build pipeline, explore:
- BuildKit advanced features: Caching strategies, multi-stage builds
- Kubernetes integration: Running containerd as the runtime for K8s
- Registry setup: Hosting your own image registry with Moby components
- Custom runtimes: Experimenting with alternative OCI runtimes like crun or kata
The Moby Project's modular architecture means each component can be swapped and upgraded independently, giving you flexibility that Docker Desktop's monolithic approach doesn't offer.
Recommended Tools
- DockerDevelop faster. Run anywhere.
- DigitalOceanCloud hosting built for developers — $200 free credit for new users