Skip to main content

Installing Docker on Ubuntu 24.04 with Dedicated ZFS Mirror Pool

ubuntu docker zfs

Set up Docker with a dedicated encrypted ZFS mirror pool for optimal isolation, performance, and data integrity.

Prerequisites

System requirements and assumptions for this guide.

  • Ubuntu 24.04 LTS with ZFS support
  • Root access or sudo privileges
  • Two identical disks for the mirror (e.g., /dev/sdb and /dev/sdc)
  • ZFS encryption key directory set up at /etc/zfs/keys/

This guide creates a dedicated encrypted ZFS mirror pool named zcontainer specifically for Docker containers and images, providing complete isolation from the system pool.

Install Docker Engine

Follow the official Docker installation guide for Ubuntu to install Docker Engine using the apt repository method.

After installation, add your user to the docker group:

sudo usermod -aG docker $USER

Log out and back in for group membership to take effect.

Create Dedicated ZFS Pool for Docker

Create a dedicated encrypted ZFS mirror pool optimized for Docker workloads.

This guide uses the same encryption key as your root pool (/etc/zfs/keys/zroot.key) for consistency and simplified key management.

Identify Container Disks

Identify the two disks you’ll use for the mirror using persistent disk-by-id paths:

# List available disks with their by-id paths
ls -lh /dev/disk/by-id/ | grep -v part

# Set your disk paths (replace with your actual disk IDs)
export CONTAINER_DISK1=/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_XXXXXXXXXXXXX
export CONTAINER_DISK2=/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_YYYYYYYYYYYYY

Warning: The disks will be completely wiped. Verify you’re using the correct disks before proceeding.

Stop Docker Service

If Docker is already installed, stop it before creating the pool:

sudo systemctl stop docker
sudo systemctl stop containerd

Create ZFS Mirror Pool

Create the encrypted mirror pool with optimized settings:

sudo zpool create -f \
  -m none \
  -O acltype=posixacl \
  -o ashift=12 \
  -O atime=off \
  -o autotrim=on \
  -o cachefile=none \
  -O canmount=off \
  -O compression=zstd \
  -O dnodesize=auto \
  -O encryption=aes-256-gcm \
  -O keyformat=passphrase \
  -O keylocation=file:///etc/zfs/keys/zroot.key \
  -O normalization=formD \
  -O relatime=off \
  -O xattr=sa \
  zcontainer mirror ${CONTAINER_DISK1} ${CONTAINER_DISK2}

Create Docker Dataset

Create the dataset that Docker will use:

sudo zfs create \
  -o mountpoint=/var/lib/docker \
  -o recordsize=128K \
  zcontainer/DOCKER

Verify Pool Creation

# Check pool status
sudo zpool status zcontainer

# Check pool properties
sudo zpool get all zcontainer

# Check dataset properties
sudo zfs get all zcontainer/DOCKER

# Verify mountpoint
mount | grep docker

Expected output for mountpoint: zcontainer/DOCKER on /var/lib/docker type zfs (rw,...)

Configure Docker Daemon

Configure Docker daemon with ZFS storage driver and logging.

Create Docker Daemon Configuration

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
  "storage-driver": "zfs",
  "storage-opts": [
    "zfs.fsname=zcontainer/DOCKER"
  ],
  "log-driver": "journald",
  "log-opts": {
    "tag": "{{.Name}}"
  }
}
EOF

Configuration breakdown:

Storage Driver:

  • storage-driver: zfs - Use native ZFS storage driver instead of overlay2
  • zfs.fsname=zcontainer/DOCKER - ZFS dataset for container storage

Logging:

  • log-driver: journald - Send container logs to systemd journal
  • tag: {{.Name}} - Tag journal entries with container name for easy filtering

Benefits of this configuration:

  • Dedicated pool isolates Docker from system storage
  • Native ZFS snapshots for containers and images
  • Full encryption at rest (AES-256-GCM)
  • Transparent compression (ZSTD) reduces storage usage
  • Mirror redundancy protects against disk failure
  • No overlay filesystem overhead
  • Copy-on-write efficiency for container layers
  • Easy backup via ZFS send/receive

Start Docker Service

sudo systemctl daemon-reload
sudo systemctl enable --now docker
sudo systemctl enable --now containerd

Verify Installation

Validate Docker installation and ZFS integration.

Check Docker Service Status

sudo systemctl status docker

Should show: Active: active (running)

Verify ZFS Storage Driver

docker info | grep -A 10 "Storage Driver"

Expected output:

 Storage Driver: zfs
  ZFS Dataset: zcontainer/DOCKER
  Parent Dataset: zcontainer/DOCKER
  ZFS Filesystem: zcontainer/DOCKER