2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018

07/15/2014: Sharing Files Between Docker Images Using Volumes

Recently I wanted to provide the same configuration file to two different Docker containers. I choose to solve this using a Docker volume. The configuration file will be sourced from within each container and looks like this:
$ cat bridge-env.sh
export BRIDGENAME=brbob
export IMAGENAME=bob
export IPADDR=

Before any explanations, let's look at the files we'll be using:

./configuration/build_image.sh - wrapper for _docker build_.
./configuration/run_image.sh - wrapper for _docker run_.
./configuration/Dockerfile - control file for Docker image.
./configuration/files/bridge-env.sh - environment setting script.

All of the files are fairly small. Since our main topic today is Docker, let's look at the Docker configuration file first.

$ cat Dockerfile
FROM stackbrew/busybox:latest
MAINTAINER David Medinets <david.medinets@gmail.com>
RUN mkdir /configuration
VOLUME /configuration
ADD files /configuration

And you can build this image.

$ cat build_image.sh
sudo DOCKER_HOST=$DOCKER_HOST docker build --rm=true -t medined/shared-configuration .

I setup my docker to use a port instead of a UNIX socket. Therefore my DOCKERHOST is "tcp://". Since _sudo is being used, the environment variable needs to be set inside the sudo enviroment. If you want to use the default UNIX socker, leave DOCKER_HOST empty. The command will still work.

Then run it.

$ cat run_image.sh
sudo DOCKER_HOST=$DOCKER_HOST docker run --name shared-configuration -t medined/shared-configuration true

This command runs a docker container called sharedconfiguration. You'll notice that the _true command is run which exits immediately. Since this container will only hold files, it's ok there are no processes running in it. However, be very careful not to delete this container. Here is the output from docker ps showing the container.

$ docker ps -a
CONTAINER ID        IMAGE                               COMMAND             CREATED             STATUS                      PORTS               NAMES
d4a2aa46b5d9        medined/shared-configuration:latest   true                7 seconds ago       Exited (0) 7 seconds ago                       -shared-configuration

Now it's time to spin up two plain Ubuntu containers that can access the shared file.

$ sudo DOCKER_HOST=$DOCKER_HOST docker run --name A --volumes-from=shared-configuration -d -t ubuntu /bin/bash
$ sudo DOCKER_HOST=$DOCKER_HOST docker run --name B --volumes-from=shared-configuration -d -t ubuntu /bin/bash
sudo DOCKER_HOST=$DOCKER_HOST docker run --name B --volumes-from=shared-configuration -d -t ubuntu /bin/bash

How can we see the shared file? Let's turn to a very useful tool called nsenter (or namespace enter). The following command installs nsenter if isn't already installed.

hash nsenter 2>/dev/null \
  || { echo >&2 "Installing nsenter"; \
  docker run -v /usr/local/bin:/target jpetazzo/nsenter;  }

I use a little script file to make nsenter easier to use:

$ cat enter_image.sh


usage() {
  echo "Usage: $0 [image name]"
  exit 1

if [ -z $IMAGENAME ]
  echo "Error: missing image name parameter."

PID=$(sudo DOCKER_HOST=$DOCKER_HOST docker inspect --format {{.State.Pid}} $IMAGENAME)
sudo nsenter --target $PID --mount --uts --ipc --net --pid

This script is used by specifying the image name to use. For example,

$ ./enter_image.sh A
root@94638de8b615:/# cat /configuration/bridge-env.sh
export BRIDGENAME=brbob
export IMAGENAME=bob
export IPADDR=
root@94638de8b615:/# exit
$ ./enter_image.sh B
root@925365faded2:/# cat /configuration/bridge-env.sh
export BRIDGENAME=brbob
export IMAGENAME=bob
export IPADDR=
root@925365faded2:/# exit

We see the same information in both containers. Let's prove that the bridge-env.sh file is shared instead of being two copies.

$ ./enter_image.sh A
root@94638de8b615:/# echo "export NEW_VARIABLE=VALUE" >> /configuration/bridge-env.sh
root@94638de8b615:/# exit
$ ./enter_image.sh B
root@925365faded2:/# cat /configuration/bridge-env.sh
export BRIDGENAME=brbob
export IMAGENAME=bob
export IPADDR=

We changed the file in the first container and saw the changes in the second container. As an alternative to using nsenter, you can simply run a container to list the files.

$ docker run --volumes-from shared-configuration busybox ls -al /configuration

subscribe via RSS