This page describes a very simple project with a ''Dockerfile'' and a ''Makefile'' as required for all projects and theses supervised in our group. The basic idea is really easy: if you were afraid of Docker before, you won't be anymore after reading this page. <> = Example Project = Let's consider a tiny example project, which consists of two files. The first file is a ''Makefile'' with the following contents (the first character in the second line must be TAB, this is standard Makefile syntax). {{{ help: @echo "Help yourself before you help others :-)" }}} The second file is a simple bash startup script, traditionally called ''bashrc'' (the ''rc'' stands for ''run commands)'' with the following contents. This is used to turn bash completion on (a must-have feature) and to print a welcome message when the container has started: {{{ if [ -f /etc/bash_completion ]; then source /etc/bash_completion; fi echo echo "Welcome to this Docker container, type \"make help\" to get some help" echo }}} = Dockerfile = In the same folder as your Makefile, create a file ''Dockerfile'' with the following contents: {{{ FROM ubuntu:16.04 LABEL maintainer="Firstname Lastname " RUN apt-get update && apt-get install -y make vim && rm -rf /var/lib/apt/lists/* COPY Makefile Makefile COPY bashrc bashrc CMD ["/bin/bash", "--rcfile", "bashrc"] # docker build -t docker-example . # docker run -it docker-example }}} The first line (FROM ...) says that we want to build an image based on Ubuntu 16.04. The second line (LABEL ...) sets the ''Author'' field of the image, you should of course use your own name and email address here. The third line (RUN ...) installs make and vim in the image (it's a naked Ubuntu 16.04, with almost nothing pre-installed); the ''rm -rf'' clears the apt cache, which helps to keep the image size small. The fourth line (COPY ...) copies the Makefile to the image (you can also copy whole directories here). The fifth line (CMD) specifies the command to be run when you run the container (in this case, we will be in an interactive bash shell, which executes the commands in the ''bashrc'' file at the beginning). The last two lines are comments and their purpose is purely for documentation. They should always be there, however, so that it's clear with which command-line arguments the image should be built and the container should be run. In particular, in most cases the ''docker run'' will mount at least one outside directory via the -v option and it should be clear which one it is. You find more tips in this list of [[https://docs.docker.com/develop/develop-images/dockerfile_best-practices|Dockerfile best practices]]. = Building the image and running it in a container = Now we can build the image (conceptually, a whole Ubuntu 16.04 with our Makefile from above in it, in reality, Docker will reuse as much as possible from the machine on which you are building the image) and run it inside a container: {{{ docker build -t docker-example . docker run -it docker-example }}} The -t option in the first line specifies a name and the . says that docker should look for everything in the current directory. The -it option in the second line says that we want to run in interactive mode. After the commands above, you should see a prompt of the following kind {{{ root@4b3dbcdd8fff:/# }}} The ''root'' says that you are the root user (but only inside of this container). The part after the @ is the name of the container. You can now do 'ls -l' and you will see the typical directory structure of Ubuntu, as well your ''Makefile''. You can edit it with ''vim'' if you like. Or you can just run ''make''. Note that we explicitly specified in the Dockerfile to install ''vim'' and ''make'', otherwise the two commands would not be available (but we could install them ourselves in the container with ''apt-get install ...'', but we would have to do that every time we run the container). = Testing the Dockerfile on our machines = On our machines you cannot run ''sudo docker'', because of security reasons. Instead, on ''tapoa'' and ''metropolis'', we have made available ''wharfer'', which can be used just like ''docker'', but without the security risks. So on those machines, you can run (with the same effect as described above): {{{ wharfer build -t docker-example . wharfer run -it docker-example }}} = Useful docker commands = {{{ docker ps | grep qlever # show all containers with a matching name docker images | grep qlever # show all images with a matching name docker stats # show the resource consumptions of the running containers docker exec -it bash # run bash in running container (useful for debugging) }}}