- understand the concept of bind-mounts
- learn which directories are bind-mounted into the container by default and how to prevent this behavior if necessary
- be able to bind mount other directories into the container via CLI options/arguments or environment variables
It's possible to read, create, and modify files on the host system from within the container. This is extremely useful. It means that you can containerize code to perform scientific modeling, analysis, etc., but the data can be read from the host system and the output can be saved to the host system at the end of a run.
Let's be more explicit. Consider this example. First we'll make a new place to play around.
$ mkdir -p ~/apptainer-class/bind-examples
$ cd ~/apptainer-class/bind-examples
If you completed the previous section on building containers, you should have a container called lolcow.sif
in the parent directory. (Otherwise you can use apptainer pull ../lolcow.sif oras://index.docker.io/godlovedc/lolcow:sif
to get the container.)
$ apptainer shell ../lolcow.sif
Apptainer> echo wutini > jawa.txt
Apptainer> cat jawa.txt
wutini
Apptainer> exit
$ ls -l
total 4
-rw-r--r--. 1 user user 7 Apr 19 09:31 jawa.txt
$ cat jawa.txt
wutini
Here we shelled into a container and created a file with some text in our current working directory. Even after we exited the container, the file still existed (and had proper ownership). How did this work?
There are several special directories that Apptainer bind mounts into your container by default. These include:
$HOME
/tmp
/var/tmp
/proc
/sys
/dev
Some of these directories are important from a systems perspective and help make the container work properly. Others (like $HOME
) allow you to read and write files on the host system from within the container. Remember that Apptainer's security model makes you the same user inside the container as you are on the host, so your permissions to and ownership are persevered and enforced properly as a side effect.
Sometimes having host directories bind mounted into the container is convenient, but other times it is unwanted. For instance, during the section on building we wanted to limit automatic bind-mounts to prevent us from accidentally reading or writing data in our $HOME
directory during the build. We did this by passing the --containall
flag. This flag ensures that the minimum bind-mounts just necessary to make the container function properly are used at runtime.
You can specify other directories to bind using the --bind
option or the environmental variable $APPTAINER_BINDPATH
Let's say we want to access a directory called /data
from within our container. For this example, we first need to create this new directory with some data on our host system. (This bit assumes you have root privileges.)
$ sudo mkdir /data
$ sudo chown $USER:$USER /data
$ echo 'I am your father' > /data/vader.txt
Now let's see how bind mounts work. First, let's list the contents of /data
within the container without bind mounting /data
on the host system to it.
$ apptainer exec ../lolcow.sif ls -l /data
/bin/ls: cannot access '/data': No such file or directory
Nothing there! Now let's repeat the same command but using the --bind
option to bind mount /data
into the container.
$ apptainer exec --bind /data ../lolcow.sif ls -l /data
total 4
-rw-rw-r-- 1 student student 17 Mar 2 00:51 vader.txt
Now a /data
directory is created in the container and it is bind mounted to the /data
directory on the host system.
You can bind mount a source directory of one name on the host system to a destination of another name using a source:destination
syntax, and you can bind mount multiple directories as a comma separated string. For instance:
$ apptainer shell --bind src1:dest1,src2:dest2,src3:dest3 some.sif
If no colon is present, Apptainer assumes the source and destination are identical. To do the same thing with an environment variable, you could do the following:
$ export APPTAINER_BINDPATH=src1:dest1,src2:dest2,src3:dest3
Let's set the environment variable to to bind mount our /data
directory and see how it works.
$ export APPTAINER_BINDPATH=/data
$ apptainer shell ../lolcow.sif
Apptainer> cat /data/vader.txt
I am your father
Apptainer> exit
exit
Don't forget to unset the environment variable when you are finished with the example!
$ unset APPTAINER_BINDPATH
Leaving that environment variable set or setting it automatically by putting it in your .bashrc
or something can lead to unexpected behavior and could result in data loss if you make a mistake!