How do I transfer Docker containers and named volumes between MX Linux hosts or drives


Gemini

To transfer Docker containers and named volumes between MX Linux hosts or external drives, the most effective approach is to separate the data (named volumes) from the container image/state (or Compose files).

Attempting to copy live directories directly out of /var/lib/docker/ can cause permission issues and corruption if the Docker daemon is running. Instead, export the named volumes into standard compressed tarballs and export custom images using standard Docker mechanisms.

1

Export Named Volumes

Data Preservation

Stop the target container to prevent database writes or file corruption during extraction.

Run a temporary, lightweight Alpine container that mounts your volume as read-only and packages its contents into a compressed tarball in your current working directory:

# Stop the container using the volume
docker stop <container_name>

# Export volume data to a .tar.gz archive
docker run --rm \
  -v <volume_name>:/source:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/<volume_name>.tar.gz -C /source .

Verification: Verify the archive was created and contains your data by listing its contents without extracting:

tar -tzf <volume_name>.tar.gz | head -n 10

2

Export Custom Images (Optional)

Image Portability

If you built custom images locally or modified container filesystems that aren't hosted on a public/private registry, export the image directly to a file:

docker save -o <image_name>.tar <image_name>:<tag>

(Note: If you use standard docker-compose.yml files pointing to public images on Docker Hub/GHCR, you can skip this step and let docker compose pull handle image fetching on the target machine.)

3

Transfer Archives to Target MX Linux Machine or Drive

File Movement

Copy the .tar.gz volume archives, image .tar files, and any docker-compose.yml configurations to your target host using rsync, scp, or a formatted USB drive/external mount:

# Example using rsync over SSH:
rsync -avP <volume_name>.tar.gz user@target-host:/home/user/docker-backups/

4

Restore Named Volumes on Target Host

Data Restoration

On the destination MX Linux system, create the target volume and use another temporary container to unpack the archive into it:

# 1. Create the named volume
docker volume create <volume_name>

# 2. Extract contents into the volume
docker run --rm \
  -v <volume_name>:/target \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/<volume_name>.tar.gz -C /target

Verification: Confirm the contents were extracted properly into the volume space:

docker run --rm -v <volume_name>:/target alpine ls -la /target

5

Load Images and Spin Up Containers

Execution

If you transferred custom .tar images, import them back into the local Docker daemon:

docker load -i <image_name>.tar

Finally, start your containers pointing to the restored volume name (using your docker run command or docker compose up -d).

MX Linux Permission & Path Notes

  • Ensure your user is part of the docker group on both MX Linux systems (sudo usermod -aG docker $USER) so you don't need sudo for standard Docker operations.
  • If restoring database containers (PostgreSQL, MariaDB, SQLite), always ensure the container is fully stopped prior to step 1. Alternatively, use database-native dumps (e.g., pg_dump or mysqldump) for maximum transactional consistency.

You

How can I stream a Docker image directly from one machine to another over SSH without saving a tar file locally first?


Gemini

You can pipe the standard output of docker save directly into docker load over SSH. This streams the image layer by layer across the network without writing a temporary .tar archive to disk on either the source or host machine.

Run this command from your local machine (or source host):

docker save <image_name>:<tag> | ssh user@target-host docker load

How it works:

  1. docker save <image_name>:<tag> writes the uncompressed tar stream of the image directly to standard output (stdout).
  2. The pipe (|) routes stdout through the encrypted SSH channel.
  3. ssh user@target-host docker load receives the stream via standard input (stdin) on the target machine and loads the image directly into its local Docker storage engine.

Tips for Faster Transfers

If you are transferring over a LAN or WAN with limited bandwidth, compress the stream on the fly using gzip or zstd before sending it over SSH:

  • Using gzip (standard across all systems):
    docker save <image_name>:<tag> | gzip | ssh user@target-host "gunzip | docker load"
    
  • Using zstd (faster compression/decompression if installed on both hosts):
    docker save <image_name>:<tag> | zstd | ssh user@target-host "zstd -d | docker load"
    
  • Verification: Once completed, check that the image is present on the target host by running:
    ssh user@target-host docker images
    

You

Move /var/lib/docker


Gemini

Moving /var/lib/docker to a new drive or partition requires stopping the Docker daemon, copying the existing data while preserving absolute permissions and extended attributes, and updating Docker's configuration to point to the new directory.

1

Stop Docker Engine & Create Target Directory

Prerequisite

Stop all running containers and the Docker daemon to avoid file lockups or corruption during copy:

sudo systemctl stop docker.socket
sudo systemctl stop docker

Verify Docker is completely inactive:

sudo systemctl status docker

Create the target directory on your destination drive (replace /mnt/data with your mount point):

sudo mkdir -p /mnt/data/docker

2

Copy /var/lib/docker using rsync

Data Integrity

Copy all content from /var/lib/docker to the new location. Use rsync with -aHAX flags to preserve permissions, ownership, hard links, and extended attributes:

sudo rsync -aHAXv /var/lib/docker/ /mnt/data/docker/

Verification: Confirm that the target directory contains the Docker layout:

sudo ls -la /mnt/data/docker

3

Update daemon.json Data Root

Configuration

Inform the Docker daemon about the new storage location by editing /etc/docker/daemon.json (create the file if it doesn't exist):

sudo nano /etc/docker/daemon.json

Add or update the data-root key:

{
  "data-root": "/mnt/data/docker"
}

4

Start Docker and Confirm Directory Path

Restart & Validation

Start the Docker service again:

sudo systemctl start docker

Verification: Query Docker runtime system info to confirm it points to the new path:

docker info | grep "Docker Root Dir"

Expected output: Docker Root Dir: /mnt/data/docker

5

Backup or Delete Original Storage

Cleanup

Once you have verified that your containers, images, and volumes work properly from the new location, rename or remove the old directory to free up disk space on your root drive:

# Rename old directory as safety backup:
sudo mv /var/lib/docker /var/lib/docker.bak

# Or remove it completely once verified:
# sudo rm -rf /var/lib/docker.bak

Mount Point & Storage Caveats

  • Filesystem Compatibility: Ensure the target filesystem supports Docker storage drivers (e.g., ext4, btrfs, or xfs). Avoid using NTFS or FAT drives, as missing Linux permissions/symlink support will break container runtimes.
  • Auto-mount Requirement: If the target directory resides on an external drive or secondary partition, ensure it is configured in /etc/fstab to mount automatically at boot before the docker.service starts.

What would you like to explore next?