Wednesday, 14 October 2020

Tinkering with Docker and relative vs. absolute paths for volume mounting

 A colleague asked how he might use a relative path e.g. ~/foobar or ../foobar instead of an absolute path e.g. /home/Dave or /tmp/foobar when mapping a path on the host to a path inside a container, using Docker for Mac.

Well, I had a play ....

For reference, Docker uses a concept known as bind mounting as evidenced by docker run --help 

  -v, --volume list                    Bind mount a volume

to make a file-system on the host available inside a running container.

I used BusyBox ( busybox ) : -

docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
busybox             latest              6858809bf669        5 weeks ago         1.23MB

and tinkered with various options.

Scenario 1 - using a shortcut for /home/<user> specifically ~

echo "Hello World!" > ~/foo.txt

docker run --rm -it --volume ~:/tmp busybox:latest sh

and then validate from inside the container: -

cat /tmp/foo.txt

Hello World!

exit

so that works ....

Scenario 2 - using a shortcut / relative path such as ..

mkdir -p ~/foobar/snafu

echo "Hello World!" > ~/foobar/greeting.txt

docker run --rm -it --volume "..":/tmp busybox:latest sh

docker: Error response from daemon: create ..: ".." includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
See 'docker run --help'.

Erk, not so good .....

Whilst I can do this: -

docker run --rm -it --volume ~/foobar:/tmp busybox:latest sh

cat /tmp/greeting.txt 

Hello World!

that kinda defeats the object ....

Enter .... realpath

which realpath

/usr/local/bin/realpath

realpath --version

realpath (GNU coreutils) 8.32
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Padraig Brady.

realpath --help

Usage: realpath [OPTION]... FILE...
Print the resolved absolute file name;
all but the last component must exist

  -e, --canonicalize-existing  all components of the path must exist
  -m, --canonicalize-missing   no path components need exist or be a directory
  -L, --logical                resolve '..' components before symlinks
  -P, --physical               resolve symlinks as encountered (default)
  -q, --quiet                  suppress most error messages
      --relative-to=DIR        print the resolved path relative to DIR
      --relative-base=DIR      print absolute paths unless paths below DIR
  -s, --strip, --no-symlinks   don't expand symlinks
  -z, --zero                   end each output line with NUL, not newline

      --help     display this help and exit
      --version  output version information and exit

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Full documentation <https://www.gnu.org/software/coreutils/realpath>
or available locally via: info '(coreutils) realpath invocation'

I'd heard about realpath from the colleague who'd asked the question in the first place ... so I installed it ....

brew install realpath

and so back to Docker ....

docker run --rm -it --volume `realpath ..`:/tmp busybox:latest sh

cat /tmp/greeting.txt 

Hello World

which works a treat - the trick is to use the shell-within-a-shell trick of enclosing one command inside another, via the double backpack ( ` ) symbol.

So I'm asking realpath where am I ....

realpath ..

/Users/hayd/foobar

and then using the results of that as the from for the Docker bind mount.

Scenario 3 - absolute paths that are absolutely horrible

So even though this wasn't something for which my colleague asked, I wanted to see what happened with horrible paths that include space characters .....

Personally I *HATE* spaces in paths - Microsoft did it with Windows a few decades back, with C:\Program Files\ etc. and that used to play havoc with Java and class paths.

Here's one that IBM Notes uses, for dumps etc.

cd ~/Library/Application\ Support/IBM\ Notes\ Data/IBM_TECHNICAL_SUPPORT/

Within that path, there's a subdirectory: -

SmartUpgrade

This entire path expands out to: -

/Users/hayd/Library/Application Support/IBM Notes Data/IBM_TECHNICAL_SUPPORT/SmartUpgrade

so we test it thusly: -

cd "/Users/hayd/Library/Application Support/IBM Notes Data/IBM_TECHNICAL_SUPPORT/SmartUpgrade

echo "Hello World!" > ./greeting.txt

docker run --rm -it --volume "/Users/hayd/Library/Application Support/IBM Notes Data/IBM_TECHNICAL_SUPPORT/SmartUpgrade":/tmp busybox:latest  sh

cat /tmp/greeting.txt 

Hello World!

Interestingly, the realpath "hack" didn't work: -

docker run --rm -it --volume `realpath .`:/tmp busybox:latest sh

docker: invalid reference format: repository name must be lowercase.
See 'docker run --help'.

docker run --rm -it --volume "`realpath .`":/tmp busybox:latest sh

cat /tmp/greeting.txt

Hello World!

So now we are wrapping the output of `realpath .` in double-quotes ... otherwise, the output of realpath throws back space characters to the upper shell, which breaks docker run .....

What fun!

No comments:

Today I Learned - more about Git config

Whilst trying to create a container image from a project on GitHub, I hit an issue with the cloning process of the GH repository ... Specifi...