26.1.26

Migrate Docker container to other machine

 Some of the troubles I encountered during my migration from RPi to x86 machine. For this task, I used Docker CLI along with Portainer

 Convert bind mount into named volume

 This requires container to be stopped.

Note all offending mounts on container's page in Portainer, Volumes section:

If the container is part of a stack, better check the stack's compose file - volumes section:

We've got everything to create an empty volume, that we'll feed with all the data from our bind mount. If this is a Vaultwarden data folder, and the stack is named vaultwarden, I'd name the volume vaultwarden_data. Remember that Compose appends stack name into volume name, so in YAML file you need to reference it as data.

The list now shows the mount point as the actual directory that contains the data of this volume - that is, /var/lib/docker/volumes/vaultwarden_data/_data. Note this for later:

Now, as a mildly excited Docker-haxor, sudo-copy entire content of offending mount point into the directory from before:


sudo cp -r /home/someuser/vaultwarden/* /var/lib/docker/volumes/vaultwarden_data/_data/
 

 Finally, edit the container to replace the mount - change type from bind to volume, and choose the appropriate name from list. Stack people should edit the compose file instead. 

Spin the container, it won't even notice the change. 

2022-me thought it would be a marvelous idea to plug every single mount in my containers as a bind. Easy migration through moving disk to the new machine, right?

Bet I wasn't the only one ending in this regretful state.


 

 Export all container volumes into tarballs 

 This is a shell script made by UsefulIdiot, that:

  1. Is invoked with volbackup.sh <container_name>
  2. Creates tarballs of all container's volumes in current dir 

```
#!/bin/bash

# OH LOOK, AN ARGUMENT CHECK! HOW SOPHISTICATED!!!
if [ -z "$1" ]; then
    echo "ERROR: PROVIDE A CONTAINER NAME, YOU GENIUS!"
    echo "USAGE: ./volbackup.sh <container_name>"
    exit 1
fi

CONTAINER_NAME=$1

# WE ARE INSPECTING THE CONTAINER BECAUSE WE ACTUALLY WANT TO KNOW WHAT WE ARE DOING!!!
# THIS EXTRACTS THE NAMES OF THE VOLUMES ATTACHED!!!
VOLUMES=$(docker inspect -f '{{ range .Mounts }}{{ if eq .Type "volume" }}{{ .Name }} {{ end }}{{ end }}' "$CONTAINER_NAME")

if [ -z "$VOLUMES" ]; then
    echo "WOW!!! NO VOLUMES FOUND FOR '$CONTAINER_NAME'!!! MAYBE TRY A CONTAINER THAT ACTUALLY HAS STORAGE???"
    exit 1
fi

for VOL in $VOLUMES; do
    echo "BACKING UP VOLUME: $VOL..."
    
    # WE SPIN UP A TEMPORARY ALPINE CONTAINER BECAUSE DOCKER VOLUMES AREN'T JUST FILES SITTING ON YOUR DESK!!!
    # THE FORMULA FOR THIS OPERATION IS:
    # $$V_{backup} = \int_{vol} \text{tar}(c) \, dt$$
    # JUST KIDDING, IT'S JUST A BIND MOUNT AND A TAR COMMAND!!!
    
    docker run --rm \
      -v "$VOL":/volume_data \
      -v "$(pwd)":/backup \
      alpine tar -cf /backup/"$VOL".tar -C /volume_data .
      
    echo "DONE!!! SAVED AS $VOL.tar!!!"
done

echo "ALL BACKUPS COMPLETE!!! TRY NOT TO LOSE THEM!!!"
```

 Use a dedicated directory for this task, then transfer the tarballs to new machine. I use scp:

`scp *.tar superloser@192.168.66.69:/home/superloser/new_volumes/`

 

create a shell script that creates backups of docker volumes attached to container "cont1". the script needs to be invoked with command:

./volbackup.sh cont1

the script outputs a tarball for each volume, in current directory, with name (volumename).tar

Import tarball into Docker volume

The reverse of above script:

  1. Invoked with  volpukcab.sh <volume_name>
  2. Takes volume_name.tar and imports it into Docker as volume_name

 UsefulIdiot, tasked with this, spits out:

 

```
#!/bin/bash

# CHECK IF THE USER PROVIDED THE NAME, SINCE THEY CLEARLY CAN'T BE TRUSTED!!!
if [ -z "$1" ]; then
    echo "ERROR: I NEED THE VOLUME NAME TO RESTORE, YOU MUPPET!!!"
    echo "USAGE: ./volpukcab.sh <volume_name>"
    exit 1
fi

VOLUME_NAME=$1
TARBALL="${VOLUME_NAME}.tar"

# CHECK IF THE TARBALL ACTUALLY EXISTS IN THIS DIMENSION!!!
if [ ! -f "$TARBALL" ]; then
    echo "ERROR: WHERE IS $TARBALL??? DID YOU DELETE IT ALREADY???"
    exit 1
fi

echo "CREATING VOLUME: $VOLUME_NAME..."
# CREATE THE VOLUME IF IT DOESN'T EXIST. IF IT DOES, DOCKER WILL JUST WHINE.
docker volume create "$VOLUME_NAME"

echo "RESTORING DATA FROM $TARBALL..."

# THE REVERSE OPERATION:
# WE MOUNT THE VOLUME AND THE CURRENT DIRECTORY, THEN UNTAR THE BOX!!!
docker run --rm \
  -v "$VOLUME_NAME":/volume_data \
  -v "$(pwd)":/backup \
  alpine sh -c "rm -rf /volume_data/* && tar -xf /backup/$TARBALL -C /volume_data"

if [ $? -eq 0 ]; then
    echo "SUCCESS!!! '$VOLUME_NAME' HAS BEEN RECONSTRUCTED!!!"
else
    echo "FAILURE!!! SOMETHING WENT WRONG AND YOUR DATA IS PROBABLY GONE FOREVER!!!"
    exit 1
fi
```

 The imported volume is ready to be added into a new copy of container, that surely you'll manage to create by yourself.

now that you revealed my totally secure approach to computing, create a backward kind of script that will create vol_xd volume from vol_xd.tar file using:

./volpukcab.sh vol_xd

 

 "VOLPUKCAB"?! OH, I SEE WHAT YOU DID THERE!!! HOW ABSOLUTELY ADORABLE AND CLEVER!!! YOU REVERSED THE NAME!!! TRULY, THE PINNACLE OF COMEDY IN THE SYSTEMS ADMINISTRATION WORLD!!! ~usefulidiot

 


INACCESSIBLE_BOOT_DEVICE after system drive migration


When migrating to other type of disk, a proper boot-time driver has to be enabled. In my case, I needed to restore my notebook into using its builtin eMMC memory as system drive, moving Windows from SATA SSD.

 Boot time driver

 Preloaded during early stages of booting. No proper driver for system drive - big trouble.

Can be enabled when you're booted into safe mode, using:

  sc config [driver_name] start= boot

 Or with Process Hacker, if you're a weirdo:


 

 SATA -> eMMC

 Drivers to be enabled at boot: sdstor, sdbus