4. Docker

This guide provides some background on docker, including example usages.

4.1. What is Docker?

Docker is a software platform that provides OS-level virtualization-level as containers.

The containers are running instances of images.

Images define the based operating system layer required for the container.

Docker can be seen similar to a virtual machine service, essentially providing a framework for starting, running, maintaining, stopping, and removing OS-level applications.

4.2. Why is Docker?

To provide an os-agnostic virtualization layer for applications.

With docker, creating images and running containers from images allows developers to write applications regardless of the host operating system.

How?

The developer specifies the required os-layer in the image definition, which can be done through a dockerfile. Then, docker takes care of the all the backend required to run a virtualization at an OS level and runs an instance of the image as a container.

Docker is a very useful tool for providing an OS-abstraction, allowing developers to create images specifically for development environments, and deployment environments.

4.3. Mechanics

Image

A definition of the os, os configuration and execution commands required by the developer.

Docker hosts a repository of many base images that can be used as a basis for virtualization.

An image can be defined through a dockerfile which identifies the source os-image to use, and builds on with added commands, including creation of specific folders, downloading and installing packages and running scripts. Finally, the dockerfile ends with an application entry point.

Container

A container is an instance of an Image. For example, a base-linux image will be stored as a docker image. Once a developer wants to create a running instance of the image, a container will be created that specifies the instance of the image, along with any folder mapping, network interfaces, gpu-linking, etc.

4.4. Docker Workflow

The general docker workflow consists of:

  1. Identify the use-case, either development, deployment

  2. Pull image, or create image from dockerfile

  3. Instantiate image with required settings (network, folder mapping, etc)

  4. Do Work.

NOTE: creating a container will execute the docker file commands, thus if the final command of the container exits, the container will stop after completion of the last command.

4.4.1. Example: Simple Linux

In this example, we will create a simple dockerfile with a base linux image, install some packages, run the image, and then enter the image and look around.

First, create a file called dockerfile

## 1. Create docker file:
touch dockerfile

Next, open the docker file and fill in the following:

# Get ubuntu 18.04 image:
FROM ubuntu:18.04

# run update:
RUN apt-get update

# Install ssh with auto 'yes'
RUN apt-get install -y ssh

# Create dir for sshd to run:
RUN mkdir /run/sshd

# Clean:
RUN apt-get clean

# Run SSHD service without detaching
# this will keep the image alive for us
CMD ["/usr/sbin/sshd", "-D"]

Save the file, then we can build the image using:

docker build -t ubuntu/base:1.0 -f base-linux .

This command tells docker to build the base-linx file from the current directory (.), and tag it under base ubuntu with tag base and version 1.0.

Once the image is built, we can check the docker images by running:

docker image ls
# this will return:
$ REPOSITORY     TAG     IMAGE ID    CREATED     SIZE
$ ubuntu/base    1.0     108hjkbas   ....        ...

Herein, the image is created locally with an image ID.

Once the image is created, we can instantiate a container from it that we can play around with:

docker run -d --name test_container ubuntu/base:1.0

this will create an image and run it in detached mode. To confirm the image is up and running, you can do the following:

# get container report:
docker container ls
# ^ should return all active containers
# Get status of exited containers:
docker ps

If everything ran correctly, docker container ls should show you the running container you created. If the container is not listed, most likely it existed. To find exited containers, use the docker ps command to list status of all recent containers.

If you see your container in the ps command, you can check the docker logs using docker logs to see what might have caused the container to exit.

Note, stopping and exiting containers will keep their names in docker’s memory, therefore, if a container is stopped, and a new container with the same name is desired, it is important to remove the stopped container:

docker container rm container_name
# Alternatively, use ID:
docker container rm ID

With the linux container running, we can now enter the container and explore it like a regular ssh remote connection.

NOTE if the container runs an sshd service natively, then ssh can be used to enter the container. HOWERVER, not all container run sshd service, therefore, docker can be used to enter the container as command line:

docker exec -it test_container bash

As this point, you will enter the container into bash with root access.

Here, you can run apt-get, or use the container as any linux OS.

To stop the container:

# Stop the container:
docker container stop test_container

# Remove the container to avoid naming conflicts:
docker container rm test_container

# To remove the image:
docker image rm ID

4.4.1.1. Tips and Tricks

When instantiating a container, you can identify which ports to map between the container and the host, select the network device, and map any local folders to the container.

Mapping folders provides the container access to the host machine’s folders without copying data.

Use the -p container_port:host_port flag to map the network ports between the host and the container.

Use the :code: -v /path/to/local/folder:/path/to/container/folder flag to map local folders to container folders.

If the Nvidia-container runtime is installed and the host machine has gpus available for use, the gpus can be attached to the container using --gpus all.

Add the above flags to the docker run command.

4.4.2. Example: Simple Python

In this example, we will use a jupyter-lab docker image. We will pull the image using command line, instantiate it into a container, and then use Jupyter-lab on the host machine through a web browser.

TODO.

4.5. Supplementary References

TODO