Introduction to Containers
Introduction to Containers
Source: http://bit.ly/2IVk6e5
Source: https://red.ht/2IUxJdr
Source: http://bit.ly/2IVk6e5
Source: http://goo.gl/4jh8cX
ubuntu@VM1:~$ time docker run ubuntu echo "hello from the container"
hello from the container
real 0m1.362s
user 0m0.036s
sys 0m0.050s
→ The total time it takes on this system (not really a powerful one) to start a
container, execute a command inside it and exit from the container is a bit
more than a second. How long would it take if we used a full VM instead?
Corso CNAF 09-12/12/2019 18
How to extend a docker container (1)
• Suppose you need to execute a command or app inside a container, but it is
not installed in the image you pulled from Docker Hub. For example, you
would like to use the ping command but by default it’s not available:
• ubuntu@VM1:~$ docker run ubuntu ping www.google.com
docker: Error response from daemon: OCI runtime create failed:
container_linux.go:345: starting container process caused "exec: \"ping\":
executable file not found in $PATH": unknown.
• Who can explain this? The ping command was successfully installed!
Corso CNAF 09-12/12/2019 19
How to extend a docker container (2)
• Whenever you issue a docker run <image> command, a new container is
started, based on the original container image.
• Check it yourself with the docker ps -a command.
• If you modify a container and then want to reuse it (which is often the
case!), you need to save the container, creating a new image.
• So, install what you need to install (e.g. the iputils-ping package, using
the same command as before) , and then issue a commit command like
docker commit xxxx ubuntu_with_ping
• This locally commits a container, creating an image with the name
ubuntu_with_ping (or any other name you like). Take xxxx from the
container ID shown by the docker ps –a output.
• Do it now.
• Reclaim disk space with docker system prune, then check again:
• ubuntu@VM1:~$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 97.22MB 97.22MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
• You can now type docker run –d –p 8080:80 web_server any time
you want to instantiate a new web server.
• What happens if you type docker run –d –p 8081:80 web_server ?
• Now exit from the container. Run it again with the same command as above
(docker run -i -t ubuntu /bin/bash).
• Is the file still there? (it should not!)
• It is not there, because every time you write docker run you start a new Ubuntu container.
Corso CNAF 09-12/12/2019 33
Connect a container to a host file
system
• So, what if we want to retain data within a container?
• We can map a directory that is available on the host (the system where we run the
docker command, e.g. your VM), to a directory that is available on the container.
This is done with the docker flag -v, like this:
docker run -v /host/directory:/container/directory <other docker arguments>
• For example:
• Create a “scratch” directory with mkdir -p $HOME/containers/scratch and change to that
directory (cd $HOME/containers/scratch).
• Create a dummy 10MB file there with head -c 10M < /dev/urandom > dummy_file
• Map the scratch directory to the directory /cointainer_data on the container:
docker run -v $HOME/containers/scratch/:/container_data -i -t ubuntu /bin/bash
• Now, when you are within the container, if you write ls /container_data you
should see the dummy file. Do it now.
• Verify also that you can write to that directory from the container, and that you can
find the written data when you are on the VM. What about permissions?
Corso CNAF 09-12/12/2019 34
Connect a container to a Docker
volume (1)
• In the previous slide, we mapped a directory that was
available on the host to a directory on the container. This
is called a bind mount.
• But what if we want to copy or move our docker
container to a different host, with a different directory
structure? Or perhaps with a different operating system?
Remember that Docker promises to be system-
independent.
• We can (and should generally prefer to) use Docker
volumes. We’ll see later what
a tmpfs mount is.
• Docker volumes are persistent but are not tied to the
specific filesystem of the host and are completely
managed by Docker itself.
Corso CNAF 09-12/12/2019 35
Connect a container to a Docker
volume (2)
• You can create a new Docker volume with the command
docker volume create some-volume
• Try these self-explanatory commands:
docker volume ls
docker volume inspect some-volume
docker volume rm some-volume
• You can also start a container with a volume which does not exist yet
with the -v flag. It will be automatically created:
docker run -i -t --name myname -v some-volume2:/app ubuntu /bin/bash
• Notice that we also introduced here the flag --name to give an explicit name
(here: myname) to a container.
• In this case, check the container with the command docker inspect myname
and look for the Mounts section. Try it now: what do you see?
App-specific App-specific
public network private network
(frontend) (backend)
Database for
WordPress WordPress
Web server
Internet
VM
docker-compose logs -f
This will continuously follow the logs generated by your containers. Very
useful to verify possible issues.
• Adding restart: always for any or all the services in your docker-
compose.yml file will make them restart automatically when your host
system boots, or when the Docker daemon restarts.
• Note: it will not automatically restart your containers if you manually kill them.
• If you need to wait until a certain container is really “ready” (whatever this
means for your application), you must use something more specific than
depends_on, e.g. https://github.com/vishnubob/wait-for-it or
https://github.com/Eficode/wait-for. Be warned that in some cases this is not
enough. For more info: https://docs.docker.com/compose/startup-order/
Corso CNAF 09-12/12/2019 52
Limitations of Docker Compose
• As we have seen, Docker Compose is very handy to create
combinations of containers running on the same machine (in our
case, your VM).
• It is best suitable if you don’t need automatic scaling of resources or
multi-server environments.
• For complex set ups, other tools such as Docker Swarm or Kubernetes
are more appropriate. We’ll cover them in one of the next lectures.
Commands:
search <repo/image:tag> :Search dockerhub for container images
pull <repo/image:tag> :Pull container image from dockerhub
images :List container images
create <repo/image:tag> :Create container from a pulled image
ps :List created containers
rm <container> :Delete container
run <container> :Execute container
[…]
Corso CNAF 09-12/12/2019 63
docker vs. udocker: comparison
docker udocker
• # docker search ubuntu • $ udocker search ubuntu
• # docker pull ubuntu • $ udocker pull ubuntu
• # docker run --name=my_ub • $ udocker create –-name=my_ub
ubuntu echo 'Hello from a ubuntu
container'
• $ udocker run my_ub echo 'Hello
• # docker rm mycontainer from a container'
• $ udocker rm my_ub
Tip: if you have installed udocker in directory /mydir, put the following line at the end of the file .bashrc:
alias udocker= '/mydir/udocker'
You can then call udocker directly, without specifying any path before it.
Corso CNAF 09-12/12/2019 64
udocker and root emulation
Root emulation
r = requests.get('http://quotes.rest/qod.json')
j = r.json()
author = j['contents']['quotes'][0]['author'].encode("utf-8")
quote = j['contents'][' quotes'][0]['quote'].encode("utf-8")
• Do it now.
• We have then verified that through udocker we are able to pull and
run standard containers. This would have worked even if we did not
have root privileges nor Docker installed.
Corso CNAF 09-12/12/2019 74
Optional Hands-on: containers in batch jobs
• Since udocker basically only requires Python, it is possible to submit
jobs to a batch system that runs containers, even if Docker is not
installed on the execution nodes of the batch system.
• It should work like this:
• Write a job script that, when executed on a node of the batch system cluster,
fetches udocker from its public repository.
• The job script should then run udocker on some container, writing the output
somewhere.
• An assignment could therefore be to encapsulate one of your
applications in a container and submit one or more jobs making use
of udocker using the HTCondor cluster that you will create during
this course.
Corso CNAF 09-12/12/2019 75
Summary
• We covered basic concepts about Containers, comparing them to Virtual Machines.
• We saw how to execute a container, list docker images and extend them to create new containers.
• We then learned how to push containers to repositories on Docker Hub and simplified the building
of containers via Dockerfiles.
• We created a container serving web pages and then connected containers to external file systems,
to volumes and to tmpfs mounts. We also learned how to export and import containers.
• We studied how to combine multiple containers in an application stack with docker-compose.
• We then discussed some Docker limitations, in particular regarding security, introduced udocker
and installed it on our VM.
• We then created a container running a Python program retrieving the Quote of the Day via a REST
call, pushed it to our individual public repository on Docker Hub and used udocker to run it on our
VM.
• Finally, we offered as optional assignment the task to use udocker to run batch jobs on an
HTCondor cluster.