<- previous - home - next ->

Downloading and Interacting with Containers

This section will be useful for container consumers. (i.e. those who really just want to use containers somebody else built.) The next chapter will explore topics more geared toward container producers (i.e. those who want/need to build containers from scratch).

You can find pre-built containers in lots of places. Singularity can convert and run containers in many different formats, including those built by Docker.

In this class, we’ll be using containers from:

There are lots of other places to find pre-build containers too. Here are some of the more popular ones:

Downloading containers

In the last section, we validated our Singularity installation by “running” a container from the Container Library. Let’s download that container using the pull command.

$ cd ~

$ singularity pull library://godlovedc/funny/lolcow

You’ll see a warning about running singularity verify to make sure that the container is trusted. We’ll talk more about that later.

For now, notice that you have a new file in your current working directory called lolcow_latest.sif

$ ls lolcow_latest.sif

This is your container. Or more precisely, it is a Singularity Image Format (SIF) file containing an image of a root level filesystem. This image is mounted to your host filesystem (in a new “mount namespace”) and then entered when you run a Singularity command.

Note that you can download the Docker version of this same container from Docker Hub with the following command:

$ singularity pull docker://godlovedc/lolcow

Doing so may produce an error if the container already exists.

Entering containers with shell

Now let’s enter our new container and look around. We can do so with the shell command.

$ singularity shell lolcow_latest.sif

Depending on the environment of your host system you may see your shell prompt change. Let’s look at what OS is running inside the container.

$ cat /etc/os-release
VERSION="16.04.5 LTS (Xenial Xerus)"
PRETTY_NAME="Ubuntu 16.04.5 LTS"

No matter what OS is running on your host, your container is running Ubuntu 16.04 (Xenial Xerus)!


In general, the Singularity action commands (like shell, run, and exec) are expected to work with URIs like library:// and docker:// the same as they would work with a local image.

Let’s try a few more commands:

Singularity> whoami

Singularity> hostname

This is one of the core features of Singularity that makes it so attractive from a security and usability standpoint. The user remains the same inside and outside of the container.

Regardless of whether or not the program cowsay is installed on your host system, you have access to it now because it is installed inside of the container:

Singularity> which cowsay

Singularity> cowsay moo
< moo >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

We’ll be getting a lot of mileage out of this silly little program as we explore Linux containers.

This is the command that is executed when the container actually “runs”:

Singularity> fortune | cowsay | lolcat
/ A horse! A horse! My kingdom for a \
| horse!                             |
|                                    |
\ -- Wm. Shakespeare, "Richard III"  /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

More on “running” the container in a minute. For now, don’t forget to exit the container when you are finished playing!

Singularity> exit

Executing containerized commands with exec

Using the exec command, we can run commands within the container from the host system.

$ singularity exec lolcow_latest.sif cowsay 'How did you get out of the container?'
< How did you get out of the container? >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

In this example, singularity entered the container, ran the cowsay command with supplied arguments, displayed the standard output on our host system terminal, and then exited.

“Running” a container with (and without) run

As mentioned several times you can “run” a container like so:

$ singularity run lolcow_latest.sif
/ Q: How many Bell Labs Vice Presidents   \
| does it take to change a light bulb? A: |
| That's proprietary information. Answer  |
| available from AT&T on payment of       |
\ license fee (binary only).              /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

So what actually happens when you run a container? There is a special file within the container called a runscript that is executed when a container is run. You can see this (and other meta-data about the container) using the inspect command.

$ singularity inspect --runscript lolcow_latest.sif

    fortune | cowsay | lolcat

In this case the runscript consists of three simple commands with the output of each command piped to the subsequent command.

Because Singularity containers have pre-defined actions that they must carry out when run, they are actually executable. Note the default permissions when you download or build a container:

$ ls -l lolcow_latest.sif
-rwxr-xr-x 1 student student 93574075 Feb 28 23:02 lolcow_latest.sif

This allows you to run execute a container like so:

$ ./lolcow_latest.sif
/ It is by the fortune of God that, in   \
| this country, we have three benefits:  |
| freedom of speech, freedom of thought, |
| and the wisdom never to use either.    |
|                                        |
\ -- Mark Twain                          /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

As we shall see later, this nifty trick can makes it easy to forget your applications are containerized and just run them like any old program.

Pipes and redirection

Singularity does not try to isolate your container completely from the host system. This allows you to do some interesting things. For instance, you can use pipes and redirection to blur the lines between the container and the host system.

$ singularity exec lolcow_latest.sif cowsay moo > cowsaid

$ cat cowsaid
< moo >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

We created a file called cowsaid in the current working directory with the output of a command that was executed within the container. >shock and awe

We can also pipe things into the container (and that is very tricky).

$ cat cowsaid | singularity exec lolcow_latest.sif cowsay -n
/  _____                       \
| < moo >                      |
|  -----                       |
|         \   ^__^             |
|          \  (oo)\_______     |
|             (__)\       )\/\ |
|                 ||----w |    |
\                 ||     ||    /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

We’ve created a meta-cow (a cow that talks about cows). ;-P

So pipes and redirects work as expected between a container and the host system. If, however, you need to pipe the output of one command in your container to another command in your container, things are slightly more complicated. Pipes and redirects are shell constructs, so if you don’t want your host shell to interpret them, you have to hide them from it.

$ singularity exec lolcow_latest.sif sh -c "fortune | cowsay | lolcat"

The above invokes a new shell, but inside the container, and tells it to run the single command line fortune | cowsay | lolcat.

That covers the basics on how to download and use pre-built containers! In the next section we’ll start learning how to build your own containers.

<- previous - home - next ->