An introduction to Docker and its role in sustainable research

Andre Weiner, Mathematical Modeling and Analysis (Chair of Prof. D. Bothe), TU Darmstadt
Get in touch: weiner@mma.tu-darmstadt.de
Slides available at: andreweiner.github.io/reveal.js/mma_docker_intro.html

mma_logo
spp1740_logo

Some warm-up questions

answer by a show of hands

What is Docker?

Who is using Docker images?

Who has created Docker images?

What is Git and Github/Bitbucket?

Who is working with Git and Github/Bitbucket?

Binary code?

Shared object libraries (.so)?

Outline

  1. Introduction to Docker
  2. Using a Docker image
  3. Containerizing an applicaton
  4. Containerizing OpenFOAM
  5. Containerizing a single application more effectively
  6. Containerizing a Jupyter notebook
  7. Distributing images

It's a training ...

Feel free to ask questions at any time!

Introduction to Docker®

Just enough to get you started

What is Docker?

Docker is a tool to create an isolated environment inside your OS. The environment is called container.

What is Docker?

Docker is a tool for OS-level virtualization. OS-level virtualization allows the existence of multiple isolated user-space instances, so-called containers.

VM versus Docker

vm
docker

Image source

Why call it container?

docker_logo

What is a container?

“A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.”
Source

What is a container image?

“A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.”
Source

Image versus Container

CD
PC
PC
PC

Image source CD, Image source PC

Containers in research

Docker minimizes local dependencies!

  • reproducible results (long term)
  • easy sharing of software
  • quick and risk free testing
  • automated testing and deployment
  • Cloud computing

Compatibility

  • Linux kernel 3.10+ (30th June 2013)
  • Docker engine
    • Initial release: 0.1.0 (23rd March 2013)
    • Compatibility break: 1.10 (4th Febuary 2016)
    • Current release: 19.03.01 (25th July 2019)

Docker group

The docker engine requires root previliges, so you can

  1. run every command with sudo, or
  2. create a docker group

    sudo groupadd docker

    sudo usermod -aG docker $USER

Using a Docker image

Download the installOpenFOAM and startOpenFOAM scripts (ESI version)


~$ chmod +x installOpenFOAM
~$ ./installOpenFOAM
~$ chmod +x startOpenFOAM
~$ ./startOpenFOAM
# in the container command line prompt
~$ mkdir -p $FOAM_RUN
~$ run
~$ cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity .
~$ cd cavity
~$ blockMesh
~$ icoFoam
						

Observations

  • Command line promt?
  • bash-4.2$
  • HOST?
  • echo $HOSTNAME
  • Username?
  • whoami
  • Directory?
  • pwd
  • Where is the data?

installOpenFOAM


username="$USER"
user="$(id -u)"
home="${1:-$HOME}"

imageName="openfoamplus/of_v1906_centos73"
containerName="of_v1906"

docker run  -it -d --name ${containerName} --user=${user}  \
  -e USER=${username}                                      \
  --workdir="${home}"                                      \
  --volume="${home}:${home}"                               \
  --volume="/etc/group:/etc/group:ro"                      \
  --volume="/etc/passwd:/etc/passwd:ro"                    \
  --volume="/etc/shadow:/etc/shadow:ro"                    \
  --volume="/etc/sudoers.d:/etc/sudoers.d:ro"              \
  -v=/tmp/.X11-unix:/tmp/.X11-unix ${imageName}            \
  /bin/bash --rcfile /opt/OpenFOAM/setImage_v1906.sh
						

docker run (container creation)


docker run [options] IMAGE_NAME [command] [arguments]
						

Show images


docker image ls
...
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
openfoamplus/of_v1906_centos73   latest              6e63df7efb1e        5 weeks ago         2.23GB
							

Show running containers


docker container ls
...
CONTAINER ID  IMAGE                           COMMAND                 CREATED      STATUS      PORTS  NAMES
9176100c3273  openfoamplus/of_v1906_centos73  "/bin/bash --rcfile …"  5 weeks ago  Up 5 weeks         of_v1906

							

Show all containers


docker container stop 9176100c3273
docker container ls -a
...
CONTAINER ID  IMAGE                           COMMAND                 CREATED      STATUS                      PORTS  NAMES
9176100c3273  openfoamplus/of_v1906_centos73  "/bin/bash --rcfile …"  5 weeks ago  Exited (137) 6 seconds ago         of_v1906
							

Removing images and containers

  • Remove images
  • docker image rm IMAGE_IDs
  • Remove all unsed images
  • docker image prune
  • Remove containers
  • docker container rm CONTAINER_IDs
  • Remove all stopped containers
  • docker container prune

startOpenFOAM


xhost +local:of_v1906
docker start of_v1906
docker exec -it of_v1906 /bin/bash -rcfile /opt/OpenFOAM/setImage_v1906.sh
						

docker start (start a stopped container)


docker start CONTAINER_NAME # or CONTAINER_ID
						

docker exec (run a command in a running container)


docker exec [options] CONTAINER_NAME COMMAND [arguments]
						

Learn more

Containerizing an application

Scenario

  • You develop a new app based on a specific framework (e. g. OpenFOAM, Jupyter, ...)
  • You do not modify the framework itself
  • There is already a Docker image for the version of the framework you are working with
  • You want to share/save framework and app together (complete build environment)

Repo: of_app_isolation


git clone https://github.com/AndreWeiner/of_app_isolation.git
cd of_app_isolation
ls
...
Dockerfile
Dockerfile.single
README.md
						

git clone https://github.com/AndreWeiner/dummyFoam
git --git-dir dummyFoam/.git log -1
...
commit f2fbf951ca312e98b3e9c13def8ec122089d67e4
Author: Andre Weiner <weiner@mma.tu-darmstadt.de>
Date:   Fri Jun 28 12:57:23 2019 +0200

    Update to OpenFOAM-v1906.
						

git --git-dir dummyFoam/.git log -1 --format=%h
...
f2fbf95
						

Dockerfile.single


FROM openfoamplus/of_v1906_centos73
# copy app source code to base image
COPY dummyFoam /opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam
# change working directory
WORKDIR /opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam
# source environment variables, compile, and create execution script
RUN source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
    wmake && \
    mkdir /case && \
    echo "source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc &> \
    /dev/null; dummyFoam -case /case" > /runDummyFoam.sh
						
Best pratices for writing Dockerfiles

Building the image


# -t TAG
# -f DOCKERFILE
#  . current path
docker build -t andreweiner/dummy_foam:$(git --git-dir dummyFoam/.git log -1 --format=%h) -f Dockerfile.single .
...
docker image ls
REPOSITORY              TAG      IMAGE ID      CREATED         SIZE
andreweiner/dummy_foam  f2fbf95  50a4ab4d3441  13 seconds ago  2.23GB
						

docker build


docker build [options] PATH
# tag syntax
-t repository/app_name:version
# multiple tags are possible
-t repo/my_app:v1.0 -t repo/my_app:latest
						

Using the app


# go to some valid OpenFOAM case
cd ${HOME}/OpenFOAM/${USER}-v1906/run/cavity
docker container run -it -v"$PWD:/case" andreweiner/dummy_foam:f2fbf95 /bin/bash /runDummyFoam.sh
...
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time


ExecutionTime = 0 s  ClockTime = 0 s

End
						

Containerizing OpenFOAM

Scenario

  • You wrote an app or a library from scratch
  • You modified an app or a library substantially
  • You want to share/save framework and app together (complete build environment)

steps to go

  1. build a build system like the one you work with
  2. add the sources and build them

repository: of_pytorch_docker


git clone https://github.com/AndreWeiner/of_pytorch_docker.git
						

Download the OpenFOAM-v1906 sources: link

Dockerfile


FROM ubuntu:18.04
# install dependencies to compile OpenFOAM
RUN apt-get update && apt-get install -y build-essential flex bison cmake zlib1g-dev \
  libboost-system-dev libboost-thread-dev libopenmpi-dev openmpi-bin gnuplot \
  libreadline-dev libncurses-dev libxt-dev wget unzip vim
# copy OpenFOAM sources to the image
COPY OpenFOAM-v1906.tgz /opt/
# extract sources and prepare compilation
RUN mkdir /opt/OpenFOAM && \
  tar -xzf /opt/OpenFOAM-v1906.tgz -C /opt/OpenFOAM && \
  rm /opt/*.tgz
# set default shell to bash to source OpenFOAM specific environment variables
SHELL ["/bin/bash", "-c"]
# change installation directory to /opt/OpenFOAM and add default compilation flag -D_GLIBCXX_USE_CXX11_ABI=0
WORKDIR /opt/OpenFOAM/OpenFOAM-v1906
RUN sed -i '/projectDir=\"\$HOME\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"/c\projectDir=\"\/opt\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"' /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
  sed -i '/CC          = g++ -std=c++11/c\CC          = g++ -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0' /opt/OpenFOAM/OpenFOAM-v1906/wmake/rules/General/Gcc/c++ && \
  source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && ./Allwmake -j 8
# get libtorch and set enironment variable with installation folder
WORKDIR /opt
RUN wget --no-check-certificate https://download.pytorch.org/libtorch/cpu/libtorch-shared-with-deps-latest.zip && \
    unzip libtorch-shared-with-deps-latest.zip && \
    rm libtorch*.zip
ENV TORCH_LIBRARIES /opt/libtorch
						

FROM ubuntu:18.04
# install dependencies to compile OpenFOAM
RUN apt-get update && apt-get install -y build-essential flex bison cmake zlib1g-dev \
  libboost-system-dev libboost-thread-dev libopenmpi-dev openmpi-bin gnuplot \
  libreadline-dev libncurses-dev libxt-dev wget unzip vim
# copy OpenFOAM sources to the image
COPY OpenFOAM-v1906.tgz /opt/
# extract sources and prepare compilation
RUN mkdir /opt/OpenFOAM && \
  tar -xzf /opt/OpenFOAM-v1906.tgz -C /opt/OpenFOAM && \
  rm /opt/*.tgz
# set default shell to bash to source OpenFOAM specific environment variables
SHELL ["/bin/bash", "-c"]
# change installation directory to /opt/OpenFOAM and add default compilation flag -D_GLIBCXX_USE_CXX11_ABI=0
WORKDIR /opt/OpenFOAM/OpenFOAM-v1906
RUN sed -i '/projectDir=\"\$HOME\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"/c\projectDir=\"\/opt\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"' /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
  sed -i '/CC          = g++ -std=c++11/c\CC          = g++ -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0' /opt/OpenFOAM/OpenFOAM-v1906/wmake/rules/General/Gcc/c++ && \
  source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && ./Allwmake -j 8
# get libtorch and set enironment variable with installation folder
WORKDIR /opt
RUN wget --no-check-certificate https://download.pytorch.org/libtorch/cpu/libtorch-shared-with-deps-latest.zip && \
    unzip libtorch-shared-with-deps-latest.zip && \
    rm libtorch*.zip
ENV TORCH_LIBRARIES /opt/libtorch
						

FROM ubuntu:18.04
# install dependencies to compile OpenFOAM
RUN apt-get update && apt-get install -y build-essential flex bison cmake zlib1g-dev \
  libboost-system-dev libboost-thread-dev libopenmpi-dev openmpi-bin gnuplot \
  libreadline-dev libncurses-dev libxt-dev wget unzip vim
# copy OpenFOAM sources to the image
COPY OpenFOAM-v1906.tgz /opt/
# extract sources and prepare compilation
RUN mkdir /opt/OpenFOAM && \
  tar -xzf /opt/OpenFOAM-v1906.tgz -C /opt/OpenFOAM && \
  rm /opt/*.tgz
# set default shell to bash to source OpenFOAM specific environment variables
SHELL ["/bin/bash", "-c"]
# change installation directory to /opt/OpenFOAM and add default compilation flag -D_GLIBCXX_USE_CXX11_ABI=0
WORKDIR /opt/OpenFOAM/OpenFOAM-v1906
RUN sed -i '/projectDir=\"\$HOME\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"/c\projectDir=\"\/opt\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"' /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
  sed -i '/CC          = g++ -std=c++11/c\CC          = g++ -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0' /opt/OpenFOAM/OpenFOAM-v1906/wmake/rules/General/Gcc/c++ && \
  source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && ./Allwmake -j 8
# get libtorch and set enironment variable with installation folder
WORKDIR /opt
RUN wget --no-check-certificate https://download.pytorch.org/libtorch/cpu/libtorch-shared-with-deps-latest.zip && \
    unzip libtorch-shared-with-deps-latest.zip && \
    rm libtorch*.zip
ENV TORCH_LIBRARIES /opt/libtorch
						

Building the image

Don't build it now! It takes ~50min...


# docker build -t your_dockerhub/of_pytorch:your_tag .
# be expressive ...
docker build -t andreweiner/of_pytorch:of1906-py1.1-cpu
						

Containerizing a single application more effectively

dummyFoam dependencies


docker container run -it andreweiner/dummy_foam:f2fbf95 /bin/bash
...
source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc
ldd $(which dummyFoam)
...
libfiniteVolume.so => /opt/OpenFOAM/OpenFOAM-v1906/platforms/linux64GccDPInt32Opt/lib/libfiniteVolume.so (0x00007fbce0318000)
libmeshTools.so => /opt/OpenFOAM/OpenFOAM-v1906/platforms/linux64GccDPInt32Opt/lib/libmeshTools.so (0x00007fbcdfada000)
libOpenFOAM.so => /opt/OpenFOAM/OpenFOAM-v1906/platforms/linux64GccDPInt32Opt/lib/libOpenFOAM.so (0x00007fbcdef0d000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fbcded09000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fbcdea00000)
libm.so.6 => /lib64/libm.so.6 (0x00007fbcde6fe000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fbcde4e8000)
libc.so.6 => /lib64/libc.so.6 (0x00007fbcde125000)
...
exit
						

Multistage builds

Repository: of_app_isolation

  1. Build the app as done before
  2. Create a new, clean image
  3. Copy only executable and dependencies

The final image will be significantly smaller!

Dockerfile: stage I


FROM openfoamplus/of_v1906_centos73 AS builder
COPY dummyFoam /opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam
WORKDIR /opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam
RUN source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
    wmake && \
    ldd $(which dummyFoam) | cut -d" " -f3 | xargs tar --dereference -cf libs.tar && \
    tar --dereference -rvf libs.tar /lib64/ld-linux-x86-64.so.2 && \
    tar -cf etc.tar /opt/OpenFOAM/OpenFOAM-v1906/etc
						

Dockerfile: stage II


FROM alpine:latest
RUN apk add --no-cache bash tar
COPY --from=builder /opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam/libs.tar \
										/root/OpenFOAM/-v1906/platforms/linux64GccDPInt32Opt/bin/dummyFoam \
										/opt/OpenFOAM/OpenFOAM-v1906/applications/solvers/dummyFoam/etc.tar \
										/
RUN tar -xf libs.tar && \
		tar -xf etc.tar && \
		rm *.tar && \
		sed -i '/projectDir=\"\$HOME\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"/c\projectDir=\"\/opt\/OpenFOAM\/OpenFOAM-\$WM_PROJECT_VERSION\"' /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc && \
		mkdir case && \
		echo "source /opt/OpenFOAM/OpenFOAM-v1906/etc/bashrc &> /dev/null; /dummyFoam -case /case" > runDummyFoam.sh
ENV LD_LIBRARY_PATH=/opt/OpenFOAM/OpenFOAM-v1906/platforms/linux64GccDPInt32Opt/lib:\
lib:lib64:/opt/OpenFOAM/ThirdParty-v1906/platforms/linux64Gcc/openmpi-1.10.4/lib64/lib:\
/opt/OpenFOAM/OpenFOAM-v1906/platforms/linux64GccDPInt32Opt/lib/openmpi-1.10.4:\
/opt/OpenFOAM/ThirdParty-v1906/platforms/linux64Gcc/openmpi-1.10.4/lib64
						

Building the image


# -t TAG
# -f DOCKERFILE
#  . current path
docker build -t andreweiner/dummy_foam_iso:$(git --git-dir dummyFoam/.git log -1 --format=%h) .
...
docker image ls
REPOSITORY                  TAG      IMAGE ID      CREATED         SIZE
andreweiner/dummy_foam_iso  f2fbf95  018fbad986dd  5 weeks ago     161MB
						

The previous image was ~2.3GB

Using the app


# go to some valid OpenFOAM case
cd ${HOME}/OpenFOAM/${USER}-v1906/run/cavity
docker container run -it -v"$PWD:/case" andreweiner/dummy_foam_iso:f2fbf95 /bin/bash /runDummyFoam.sh
...
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time


ExecutionTime = 0 s  ClockTime = 0 s

End
						

Containerizing Jupyter notebooks

Distributing an image

Sharing images

  1. public registry (Dockerhub)
  2. private registry
  3. tar ball

Dockerhub

To use Dockerhub, you need an account (free).


docker login --username=yourhubusername --email=name@host.com
docker push andreweiner/of_pytorch:of1906-py1.1-cpu
...
docker pull andreweiner/of_pytorch:of1906-py1.1-cpu
						
Check out the of_pytorch example!

tar archive


docker history andreweiner/dummy_foam:f2fbf95
...
IMAGE         CREATED       CREATED BY                                     SIZE    COMMENT
50a4ab4d3441  17 hours ago  /bin/sh -c source /opt/OpenFOAM/OpenFOAM-v19…  72.5kB
1d1a83fdb3da  17 hours ago  /bin/sh -c #(nop) WORKDIR /opt/OpenFOAM/Open…  0B
7cb119e51ba1  17 hours ago  /bin/sh -c #(nop) COPY dir:db92694508b316ccc…  73.1kB
6e63df7efb1e  5 weeks ago                                                  2.23GB  Imported from -
						

docker save -o dummy_foam-f2fbf95.tar andreweiner/dummy_foam:f2fbf95
docker image rm andreweiner/dummy_foam:f2fbf95
docker image ls
...
docker load -i dummy_foam-f2fbf95.tar
docker image ls
...
						

Conclusion

  • Docker minimizes dependencies
  • Docker images are easy to share
  • Docker containers are always ready to use
  • Running a container with the same options will always give 100% identical results

More pros and cons you can think of?

THE END

Thank you! Let me know what you think!

Get in touch: weiner@mma.tu-darmstadt.de

Time for discussion ...