Container

From docwiki
Jump to: navigation, search


Motivation

Container provide a light-weighted virtualization where the kernel of your system is used but the processes that have a different view onto the system. Instead of a Virtual Machine (VM) we only have a Virtual Environment (VE) Here you will learn the basic terminology of the container world and some examples.

Why Container?

In the beginning was the chroot command that allows a process to see only a part of the file-system but it was never meant as a secure confinement. FreeBSD developed something out of this with the name "jail" where you could really limit a process. Jails where limited to be only able to interact with processes inside its jail and also restricted with certain operations.

When Linux become popular hosting-providers wanted to offer cheap "root-servers" to customers without the overhead of full virtualization. This lead to the creation of "linux-VServers" but this was not part of the mainline kernel.

Today, Linux has a generalized framework for limiting what processes can see with the "cgroups" which is used for container-type virtualization.

Container and Dependency Hell

What was driving this was not so much a need for security or the desire to offer cheap root-servers but the ever more increasing dependency hell in languages as ruby, python, etc.. With the fast pace of development in this newer languages developers need to keep track about which version of the programming language and which modules they use. What worked in python2.4 did not work in python2.6, and then there are dependencies on many modules which are also available in newer and older versions and which are not always compatible. While languages like python and ruby already have some ways to deal with that in a way that they install a different set of modules for each project in a sub-directory, it can also be that case that some of the modules might have dependencies with special versions of system libraries. So the solutions, to put all of that into a container where one can make sure that there are no more outside dependencies makes sense.

This certainly has some advantages but also comes with some problems of its own: Now for security updates of modules you do not only have to take care of your system libraries but also a ton of code that is hidden away in containers and then there is a tendency to more or less ignore backwards compatibility of code as people can revert to containers. To manage the increased complexity then additional tools become necessary.

Overview of Container Technologies

On of the first projects that made use of the cgroups containers was the LXC (LinuX Containers) Project. LXCs are often kind of virtual machines which a more or less complete OS install but only sharing the kernel. They are usually meant as permanent machines that are started at boot and maintained with lxc- tools. LXC Container can also be maintained via the libvirt virsh tools. (Yet one should decide for one of the 2 as they are not fully interchangeable). The cgroups allows Virtual Environments (VE) to share some of the "namespace" (e.g. network).

Docker is the most known Container technology today. It started as extension of LXC but now is independent of it. It still makes use of the cgroups of course. The focus of docker is not to run a small OS in the VE (virtual environment) but just one application. What docker offers above that are tools to download container images from a git like repository and to build on existing containers.

Podman after the success of docker RedHat announced the podman project which aims to be a drop-in replacement for docker. It will be part of RedHat8. As of now (2020) it is not well integrated into debian or other distributions yet. Podman offers a few security enhancements over docker, e.g. the option to run containers without root and better integration into the systemd environment.

First Steps with LXC Containers using the libvirt virsh environment

If you have used virsh before then you know how to manage KVM VMs with it. If we want to use virsh for LXC we need to "connect" it to a different endpoint:

# list virtual machines:
virsh list

# list LXC VEs: 
virsh -c lxc:/// list 

If we set: export LIBVIRT_DEFAULT_URI=lxc:/// then virsh will assume the -c above, but in the examples here I will explicitly specify the -c in order to make clear that we are dealing with LXC and not with KVM.

virsh -c lxc:/// define myhello.xml
cat myhello.xml
<domain type='lxc'>
  <name>mylxc</name>
  <memory>102400</memory>
  <os>
    <type>exe</type>
    <init>/bin/bash</init>
  </os>
  <devices>
    <console type='pty'/>
  </devices>
</domain>
virsh -c lxc:/// list --all
virsh -c lxc:/// start mylxc
virsh -c lxc:/// console mylxc

If we look around in the console we find that our hostname is now "mylxc" and that "top" only shows us 2 processes: the bash and the top.

Also useful is the virt-sandbox tool: This would create a sandbox on the fly and execute /bin/hostname in it:

virt-sandbox -c lxc:/// /bin/hostname 

There is also a tool to create a container from an OCI (Open Container Image) which is also used by docker, podman, etc..


Different View on the Filesystem

If we include the following in the XML definition of our LXC VE then we will get a different filesystem:

<filesystem type='mount'>
  <source dir='/space/mylxc/root'/>
  <target dir='/'/>
</filesystem>
<filesystem type='mount'>
  <source dir='/space/mylxc/var'/>
  <target dir='/var'/>
</filesystem>

In order to be able to run anything we either need static binaries there that do not need any library or we need to setup an envinronment that has all the necessary stuff in there.

Docker, Podman

The following examples are for docker, yet podman should be mostly compatible:

The docker-CE (comunity edition) is free. The EE needs a commercial license.

To test your docker isntallation you could e.g. use:

docker run --rm -it  --name mydocker alpine:latest /bin/sh

rm would remove an older image and -it attaches stdin and terminal.

It downloads and installs "alpine" which is a small 6MB, very limited linux enviroment and runs ist

docker ps
# would list the currently running docker versions. e.g:
CONTAINER ID  IMAGE           COMMAND      CREATED             STATUS              PORTS               NAMES
e8b274b83b99  alpine:latest   "/bin/sh"    10 seconds ago      Up 7 seconds                            mydocker

If we want to list what images we have downloaded we could use:

docker images
# download another image: e.g
docker pull busybox
docker images

And then run it with:

docker run -it --name mybbox busybox

Busybox is a small binary that contains a simple shell and a few simply tools all in one binary and it is often used for tiny installations (e.g. in an applicance).

We can also pass arguments to the container which will then given to the shell or command that runs in the container. If we do not specify a name we will get a random name. (the name of the container is not the hostname) e.g:

docker run  busybox hostname 
docker run  busybox echo "hello world"
<pre>

Once a container exits it still exists: E.g. with
<pre>
# list all containers (even the one that exited)
docker ps -a

You can start them again, attach to them or remove them with rm.

To restart and attach use:

docker  start bf47e934ff16 -a

To remove all remains of containers that are no longer running you could use:

docker container prune

You can create your own containers with a "dockerfile" that contains info on where it builds on and extra files that need to be copied into it. You can then share this if you have an account on the docker hub or you can use alternative hubs e.g. gitlab.

Building A Container with Podman

FROM debian:12
WORKDIR /app
RUN apt-get -y update ; apt-get -y upgrade ; apt-get -y install python3 python3-flask
COPY . .
ENV FLASK_APP lvapp.py
EXPOSE 8000
CMD [ "flask", "run", "--host=0.0.0.0","--port=8000" ]

Building an image from this: In the UPPER directory

podman build test1 -t lvapp:latest
podman run -d -p 8000:8000  lvapp

Exercises

  • Setup LXC (e.g. inside a VM) and build a simple environment.
  • setup docker or podman and run some command inside a virtual environment.

Links