Arch Linux as a Docker Host: Optimal Configuration Guide
Arch Linux and Docker are a natural pairing for administrators who want the latest features, minimal overhead, and full control over their infrastructure. Arch's rolling release model means you always run the most recent stable Docker engine without waiting for distribution backports or PPA updates. Combined with Arch's minimal base installation, you get a Docker host with nothing unnecessary running alongside your containers.
This guide covers everything needed to configure Arch Linux as an optimal Docker host, from storage driver selection and filesystem configuration to kernel parameter tuning and maintaining stability on a rolling release.
Installing Docker on Arch Linux
# Install Docker and Docker Compose from official repositories
pacman -S docker docker-compose docker-buildx
# Enable and start the Docker daemon
systemctl enable docker
systemctl start docker
# Verify installation
docker version
docker compose version
docker run hello-world
# Add your user to the docker group (avoid running docker as root)
usermod -aG docker $USER
# Log out and back in for group membership to take effect
docker group grants them effectively root-level access to the system through Docker. Only add trusted users. For production environments, consider using rootless Docker or restricting access through usulnet's RBAC system.
Storage Driver Selection
The storage driver determines how Docker stores image layers and container writable layers. The choice depends on your filesystem:
| Storage Driver | Filesystem | Performance | Recommended For |
|---|---|---|---|
overlay2 |
ext4, XFS | Excellent | Most deployments (default) |
btrfs |
Btrfs | Good | When you want snapshots and compression |
zfs |
ZFS | Good | Enterprise with ZFS infrastructure |
# Check current storage driver
docker info | grep "Storage Driver"
# Configure in /etc/docker/daemon.json
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.size=20G"
]
}
Btrfs as Docker Storage: The Arch Advantage
Btrfs is a first-class citizen on Arch Linux and offers unique advantages for Docker hosts. When your /var/lib/docker is on a Btrfs filesystem, Docker can use the native Btrfs storage driver, which creates lightweight copy-on-write snapshots for image layers and containers:
# Set up Btrfs for Docker
# If / is already Btrfs, create a dedicated subvolume:
btrfs subvolume create /var/lib/docker
# Or use a separate Btrfs partition
mkfs.btrfs -L docker-data /dev/sdb1
mount -o compress=zstd,noatime /dev/sdb1 /var/lib/docker
# Add to fstab
echo 'UUID=xxx /var/lib/docker btrfs defaults,compress=zstd,noatime 0 2' >> /etc/fstab
# Configure Docker for Btrfs
cat > /etc/docker/daemon.json << 'EOF'
{
"storage-driver": "btrfs"
}
EOF
systemctl restart docker
Btrfs Benefits for Docker
- Transparent compression: Zstd compression reduces disk usage for image layers by 30-50% with negligible CPU overhead
- Instant snapshots: Container creation is a lightweight COW snapshot operation
- Filesystem-level deduplication: Common data across images shares physical blocks
- Online defragmentation: No downtime needed for maintenance
- Snapshot-based backups: Create consistent point-in-time backups of all Docker data
# Snapshot Docker data before updates
btrfs subvolume snapshot -r /var/lib/docker \
/snapshots/docker-pre-update-$(date +%Y%m%d)
# Check compression ratio
btrfs filesystem usage /var/lib/docker
compsize /var/lib/docker # Requires compsize package
# Schedule automatic Docker data snapshots
cat > /etc/systemd/system/docker-snapshot.service << 'EOF'
[Unit]
Description=Snapshot Docker Data
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/btrfs subvolume snapshot -r /var/lib/docker /snapshots/docker-$(date +%%Y%%m%%d-%%H%%M%%S)
ExecStartPost=/bin/bash -c 'ls -dt /snapshots/docker-* | tail -n +8 | xargs -r btrfs subvolume delete'
EOF
cat > /etc/systemd/system/docker-snapshot.timer << 'EOF'
[Unit]
Description=Daily Docker Data Snapshot
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl enable docker-snapshot.timer
Docker Daemon Configuration
A complete /etc/docker/daemon.json for an Arch Linux production Docker host:
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-address-pools": [
{"base": "172.17.0.0/16", "size": 24},
{"base": "172.18.0.0/16", "size": 24}
],
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Soft": 65535,
"Hard": 65535
}
},
"metrics-addr": "127.0.0.1:9323",
"experimental": false
}
Key Settings Explained
| Setting | Purpose |
|---|---|
live-restore |
Keep containers running during Docker daemon restarts |
userland-proxy: false |
Use iptables/nftables instead of userland proxy (better performance) |
no-new-privileges |
Prevent processes from gaining privileges via setuid |
log-opts |
Prevent container logs from filling the disk |
metrics-addr |
Expose Prometheus metrics endpoint |
Systemd Integration
Override Docker's systemd unit for Arch-specific optimizations:
# Create override
mkdir -p /etc/systemd/system/docker.service.d/
cat > /etc/systemd/system/docker.service.d/override.conf << 'EOF'
[Service]
# Increase file descriptor limits
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
# Ensure clean startup
ExecStartPre=-/usr/bin/docker system prune -f --filter "until=24h"
# Restart policy
Restart=always
RestartSec=5s
EOF
systemctl daemon-reload
systemctl restart docker
Kernel Parameters for Docker
Create /etc/sysctl.d/99-docker.conf:
# Required for Docker networking
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
# Increase connection tracking for many containers
net.netfilter.nf_conntrack_max = 1048576
# Increase file descriptors
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 1024
# Network performance
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65536
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
# Memory
vm.swappiness = 10
vm.overcommit_memory = 1
vm.max_map_count = 262144
# Load the bridge module first (needed for bridge-nf-call)
modprobe br_netfilter
echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf
# Apply sysctl changes
sysctl --system
Security Modules
# Arch uses AppArmor (can be enabled) or SELinux (via AUR)
# For Docker, AppArmor is simpler:
# Install AppArmor
pacman -S apparmor
# Enable at boot (add to kernel command line)
# In /boot/loader/entries/arch.conf:
# options ... apparmor=1 security=apparmor
# Enable the service
systemctl enable apparmor
systemctl start apparmor
# Docker automatically uses AppArmor profiles when available
docker info | grep "Security Options"
# Security Options: apparmor, seccomp
AUR Docker Tools
# Useful AUR tools for Docker administration
yay -S lazydocker # Terminal UI for Docker
yay -S dive # Analyze Docker image layers
yay -S ctop # Top-like interface for containers
yay -S docker-credential-pass # Credential helper using pass
# Dive: analyze image size
dive myimage:latest
# ctop: real-time container metrics
ctop
# lazydocker: full TUI management
lazydocker
Managing Rolling Updates with Docker
The biggest concern with Arch as a Docker host is the rolling release model. Here is a safe update strategy:
#!/bin/bash
# /usr/local/bin/safe-docker-update.sh
set -euo pipefail
LOG="/var/log/docker-update.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG"
}
# Check if Docker packages are being updated
DOCKER_UPDATES=$(pacman -Qu 2>/dev/null | grep -E "^(docker|containerd|runc) " || true)
if [ -z "$DOCKER_UPDATES" ]; then
log "No Docker-related updates available."
exit 0
fi
log "Docker updates available:"
echo "$DOCKER_UPDATES" | tee -a "$LOG"
# Snapshot Docker data before update
if command -v btrfs &> /dev/null && btrfs subvolume show /var/lib/docker &> /dev/null; then
log "Creating Btrfs snapshot..."
btrfs subvolume snapshot -r /var/lib/docker \
/snapshots/docker-pre-update-$(date +%Y%m%d-%H%M%S)
fi
# Check for running containers
RUNNING=$(docker ps -q | wc -l)
log "Running containers: $RUNNING"
if [ "$RUNNING" -gt 0 ]; then
log "Containers are running. Docker's live-restore will keep them up."
fi
# Apply updates
log "Applying Docker updates..."
pacman -S --noconfirm docker docker-compose containerd 2>&1 | tee -a "$LOG"
# Restart Docker daemon
log "Restarting Docker daemon..."
systemctl restart docker
# Verify all containers are running
sleep 5
RUNNING_AFTER=$(docker ps -q | wc -l)
log "Containers running after update: $RUNNING_AFTER"
if [ "$RUNNING_AFTER" -lt "$RUNNING" ]; then
log "WARNING: Some containers did not survive the update!"
docker ps -a --filter "status=exited" | tee -a "$LOG"
fi
log "Docker update completed."
"live-restore": true in your Docker daemon configuration, containers continue running even when the Docker daemon is restarted for updates. This dramatically reduces downtime during rolling updates on Arch.
Docker Host Monitoring on Arch
# Install monitoring stack
pacman -S prometheus-node-exporter
# Enable the exporter
systemctl enable prometheus-node-exporter
systemctl start prometheus-node-exporter
# Docker metrics are available at the metrics-addr configured earlier
curl -s http://localhost:9323/metrics | head
# Monitor Docker disk usage
docker system df
docker system df -v # Verbose output
# Clean up periodically
cat > /etc/systemd/system/docker-cleanup.service << 'EOF'
[Unit]
Description=Docker System Cleanup
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/docker system prune -af --filter "until=168h"
ExecStart=/usr/bin/docker volume prune -f
EOF
cat > /etc/systemd/system/docker-cleanup.timer << 'EOF'
[Unit]
Description=Weekly Docker Cleanup
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl enable docker-cleanup.timer
Using usulnet on Arch Linux
usulnet is built with Go and ships as a single binary, making it an ideal Docker management platform for Arch Linux. It runs natively without any external runtime dependencies and works with whatever Docker version Arch provides in its repositories:
# Deploy usulnet via Docker Compose
mkdir -p /opt/usulnet && cd /opt/usulnet
# Create docker-compose.yml with usulnet configuration
# See https://usulnet.com for the latest deployment guide
docker compose up -d
# usulnet provides:
# - Web-based container management
# - Security scanning with Trivy
# - Multi-node Docker management
# - RBAC access control
# - Backup automation
# - Real-time monitoring
The combination of Arch Linux's rolling release model and usulnet's container management gives you a modern, minimal Docker infrastructure where both the host OS and the management platform stay current without the major-version upgrade cycles that plague traditional distributions.
Bottom line: Arch Linux as a Docker host requires more hands-on maintenance than Ubuntu or Debian, but rewards you with a minimal, current system running the latest Docker features. The key is automation: automated updates with safeguards, automated snapshots before changes, and automated monitoring to catch issues early.