[Docker](https://www.docker.com/) and [Singularity](http://singularity.lbl.gov/) are software container systems that allow you to write applications that can be deployed on any compute environment. This article explains our base lab docker image and how you can use it to run your programs/scripts.

Build Status: [![CircleCI](https://circleci.com/gh/DosenbachGreene/dglabdocker.svg?style=svg)](https://circleci.com/gh/DosenbachGreene/dglabdocker)

[TOC]

## Docker

### Installation
#### Linux
See the [install docker](https://docs.docker.com/engine/installation/) guide. You want to install the Community Edition.

#### Mac
Docker is availiable through [Docker for Mac](https://docs.docker.com/docker-for-mac/install/). Simply [download](https://download.docker.com/mac/stable/Docker.dmg) and drop the app into your applications folder.

#### Windows
Haven't done testing with Windows, but it could work in theory...

### Pulling the Image
Our [lab docker image](https://hub.docker.com/r/vanandrew/dglabimg/) is hosted on [docker hub](https://hub.docker.com) and the [Dockerfile](https://github.com/DosenbachGreene/dglabdocker) is hosted on our lab [GitHub](https://github.com/DosenbachGreene). You should create an account if you aim to make derivatives of this image.

To pull the image into your local docker repository, you use the `docker pull` command:

```
docker pull vanandrew/dglabimg
```

This will pull the latest image. You can also pull specific versions of the image:

```
docker pull vanandrew/dglabimg:v1.00
```

As of v1.00 of the lab docker image, these are the following programs availiable:

- 4dfp tools
- fsl 5.0.10
- caret 5.6.1
- connectome workbench 1.2.3
- python 2/3 (w/ nibabel,numpy)

These programs are also runnable on the image through outside mounts

- MATLAB
- freesurfer

If you think a particular program should be in the image that is not already in here, you can [send me a request](mailto:vanandrew@wustl.edu).

### Using the image

Running the image can be done with `docker run` with the `-it` and `--rm` options (See the [docker run documentation](https://docs.docker.com/engine/reference/commandline/run/) for the full details). The `-i` flag keeps a STDIN pipe open to your container instance and allows you to submit commands to it. Similarly, the `-t` flag opens a pseudo-tty terminal interface. The `--rm` flag cleans up your container after you exit.

```
docker run --it --rm vanandrew/dglabimg
```

This will spawn a software container running the image that will be cleaned up automatically once you exit.

```
root@079c8713aca6:/# 
```

If you see this prompt in your terminal, congratulations! You're officially running a self-contained Ubuntu system on your machine. You can do whatever you want to the image (try `rm -rf /`, if you're brave enough :^) ), and it will not affect your host system at all.

### Mounting paths from the host to the container

Having an isolated system is nice, but what's the use if you can't access data located on the host?

You can accomplish this through Docker's volume mounting feature. It will allow you to map a host directory to a directory on docker. This is done through the `-v [host directory]:[container directory]` option:

```
docker run -it --rm -v $(pwd -P)/Downloads:/mnt/downloads -v $(pwd -P)/Documents:/mnt/documents vanandrew/dglabimg

# or to go onto multiple lines use \
docker run -it --rm \
    -v $(pwd)/Downloads:/mnt/downloads \
    -v $(pwd)/Documents:/mnt/documents \
    vanandrew/dglabimg
```

This mounts my `/User/vanandrew/Downloads` directory to `/mnt/downloads` and `/User/vanandrew/Documents` directory to `/mnt/documents`. It should be noted that the `-v` option only accepts absolute paths, so don't use `./` or `~` when constructing your path. 

* Note: For Mac users, Docker has to be given explicit permission to directories it's allowed to mount. You can add these by clicking on the docker icon in your status bar, Preferences-->File Sharing and adding the directories containing paths you intend to mount. Changing paths requires docker to restart after applying changes.

### X11 Forwarding
By default, docker does not forward the x display of the host to allow for graphics rendering. To use graphical applications, you can grab a copy of my `docker_x11` script to setup x11 forwarding for your system. Simply clone the dglabdocker repo, and add the directory to your PATH variable:

```
git clone https://github.com/DosenbachGreene/dglabdocker.git
# You can add this to your .bashrc
export PATH=${PATH}:$(pwd)/dglabdocker
```

The docker_x11 script will automatically setup your environment for X11 forwarding. (On Mac, carefully read the instructions to enable indirect GLX). The script essentially runs the equivalent of `docker run -it --rm`, so to run an image, the full command would be:

```
docker_x11 vanandrew/dglabimg:v1.00
```

And mounting directories is simply:

```
docker_x11 -v mount/me:/I/am/Mounted vanandrew/dglabimg:v1.00
```

### Using MATLAB
To use MATLAB in our docker image, you must mount a Linux MATLAB install to /opt/MATLAB. From there, you can simply type `matlab` to start MATLAB.

```
docker run -it --rm -v /path/to/MATLAB/:/opt/MATLAB vanandrew/dglabimg:v1.00

OR

docker_x11 -v /path/to/MATLAB/:/opt/MATLAB vanandrew/dglabimg:v1.00
```

I have uploaded a [MATLAB 2017b install](https://wustl.box.com/shared/static/kq5a5nd094ztymz78iregcawnjpops5n.zip) on Box for use with our Docker image, but due to licensing issues, you must on our university network to use it.

You can use the `-nojvm` option when you start MATLAB, if you don't need X11 and graphics (Though if you run matlab without forwarding X11, you will get the same effect).

### Using Freesurfer
TO-DO

### Extending the image (Dockerfiles) 
You can extend the base lab image by creating a derivative image using our lab image as a base. This is done through a Dockerfile. An example like this:

```
FROM vanandrew/dglabimg:v1.00
MAINTAINER Andrew Van <vanandrew@wustl.edu>

RUN apt-get install -y zsh
```

This simple example shows me creating a derivative image from the base lab image, then installing zsh.

In order to turn this Dockerfile into an actual image, I use the `docker build` command:

```
docker build . -t vanandrew/simpletest
```

Where `.` is the path to the **directory**, not file, of where the Dockerfile is located. The `-t` option specifies the tag option, where I can give the image a specific name. Here, I also namespace it by my docker hub username. This allows me to easily push the image to my dockerhub, where I can share it with others!

Pushing an image to dockerhub is accomplished with the `docker push` command:

```
docker push vanandrew/simpletest
```

### Other Notes and Guidelines

- When you write a script, you want to always write your files to a mounted directory (even temp files). This is due to the fact that conversion of a Docker image to a Singularity makes certain directories read-only, which can cause errors in your script later on when you move your application to other systems.

## Singularity

### Usage
TO-DO