Skip to content

Instantly share code, notes, and snippets.

@jpetazzo
Last active September 30, 2022 05:36
Show Gist options
  • Save jpetazzo/5668338 to your computer and use it in GitHub Desktop.
Save jpetazzo/5668338 to your computer and use it in GitHub Desktop.
Share a directory with a docker container

Rectifier

The diode bridge is the simplest rectifier I know.

Rectifier lets you share a directory with a docker container (just like $yourvm shared folders).

You don't have to install anything in your containers, and you only need to install diod in the host. diod is packaged on Ubuntu/Debian distros, and will automatically be apt-get install-ed if needed.

Since it uses diod to make a bridge, I called it rectifier. Yeah, that sucks, so if you have a better name, I'll steal it!

How to use it

Download rectifier.sh:

curl https://gist.github.com/jpetazzo/5668338/raw/rectifier.sh > rectifier.sh

Then:

bash rectifier.sh 042baf /mnt /home/joe

This will mount /home/joe (i.e. your home directory, if you happen to be joe) on /mnt inside the container 042baf.

When you don't want to share the directory anymore, Ctrl+C to terminate diod, then clean up the mount in the container by running:

bash rectifier.sh 042baf /mnt -

Known bugs

If the output format of docker inspect changes, the program will be confused.

All containers (and possibly other machines on your local network, depending on your firewalling rules) can access your shared folders.

If you Ctrl+C (to terminate the sharing), the shared folder will still be mounted in the container (but it will be unavailable), and you won't be able to umount it easily from the container (you have to use rectifier to umount).

It probably requires kernel 3.8 (for lxc-attach to work properly).

How it works

It uses v9fs, because:

  • it doesn't require any kind of package in the container (unlike FUSE et al.),
  • the server configuration is dead simple, doesn't require a portmapper, and won't fuck up with existing file sharing protocols.

It runs diod in TCP server mode, binding it to the docker gateway address, on a random TCP port, without authentication.

Then, it uses lxc-attach -e to execute a mount command in the context of the container without dropping privileges.

#!/bin/bash
set -e
[ "$3" ] || {
echo "Syntax: $0 <containerid> </path/in/container> </path/on/host>"
echo "Path in container (and on host, obviously) must exist."
echo "Specify '-' as host path to clean up an old sharing."
exit 1
}
which docker >/dev/null || {
echo "Could not find docker binary, aborting."
exit 1
}
SHORTID=$1
CPATH=$2
HPATH=$3
LONGID=$(docker inspect $SHORTID | grep -i '"id"' | cut -d\" -f4)
IPADDR=$(docker inspect $SHORTID | grep -i '"gateway"' | cut -d\" -f4)
PORT=$((50000+$RANDOM%10000))
[ "$HPATH" = "-" ] && {
sudo lxc-attach -e -n $LONGID -- umount $CPATH
exit 1
}
[ -x /usr/sbin/diod ] || sudo apt-get install diod
echo "Starting diod."
sudo diod --foreground --export $HPATH --listen $IPADDR:$PORT --no-auth &
echo "Mounting FS."
sudo lxc-attach -e -n $LONGID -- mount -t 9p -o port=$PORT,trans=tcp,version=9p2000.L,aname=$HPATH $IPADDR $CPATH
echo "Done. Press Ctrl+C to terminate sharing."
wait
@jpetazzo
Copy link
Author

Note for later: when running diod on a mac, I also had to add --allsquash and --squashuser nobody (use nobody or whatever suits you!)

@michaelneale
Copy link

@jpetazzo so on a mac - the "host" is still the docker host - ie the "boot2docker" vm or similar? so you run diod there? but also on the mac? or only on the mac?

Also - lxc-attach won't work unless docker is using lxc?

@michaelneale
Copy link

note for others: chaos/diod#5 is the "fork" of diod for os-x - and the changes: jpetazzo/diod@chaos:master...master

@vincentbernat
Copy link

This only works with LXC-enabled dockers, right? If you don't need OSX support, you can also just use bind mount. I am doing that (that's for zsh and for $HOME, but that's just to give the gist):

local homemnt=${${(f)"$(df --output=target $HOME)"}[-1]}
        local homedev=$(readlink -f ${${(f)"$(df --output=source $HOME)"}[-1]})
        sudo =nsenter -m -t $id -- /bin/sh -e <<EOF
if ! mountpoint $HOME > /dev/null 2>/dev/null; then
  tmp=\$(mktemp -d)
  mkdir -p ${HOME}
  [ -b /dev/home-directory ] || mknod /dev/home-directory b $(stat -c "0x%t 0x%T" ${homedev})
  mount /dev/home-directory \$tmp
  rm /dev/home-directory
  mount -n --bind \$tmp/${HOME#$homemnt} $HOME
  umount \$tmp
  rmdir \$tmp
fi

@michaelneale
Copy link

the lxc-attach I believe is just to do the mount - a nsenter based equivalent should also work.

@shoaibkamil
Copy link

This doesn't work for me on OS X btw; I pulled the "fork" from @chaos and then pulled from @jpetazzo's fork. diod compiles fine, but after mounting from within a linux VM I get errors even when trying to do common operations such as mv.

Has anyone gotten this to work well on OS X?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment