1. Index
  2. Debian
  3. Desktop
  4. Heimserver
  5. Webserver

Container mit Docker

Docker verwaltet leichte Container für Prozesse. Leicht bedeutet, der Container läuft ohne Hardware-Virtualisierung direkt auf dem Kernel des Hosts – aber streng isoliert mit eigene Dateisystemen, Benutzern und Netzwerken. Docker verwendet dazu Kontrollgruppen und Namensräume.

Docker installieren

Debian pflegt kein offizielles Docker-Paket. Daher nimmt man den Schlüssel und das Depot des Docker-Projekts in die Paketquellen auf und installiert den Daemon.

echo "deb https://download.docker.com/linux/debian bullseye stable" \
	>> /etc/apt/sources.list
curl https://download.docker.com/linux/debian/gpg | apt-key add
apt update
apt install docker-ce

Mitglieder der Gruppe docker dürfen Abbilder und Container verwalten.

adduser User docker

Abbild manuell erzeugen

Ein Abbild besteht aus einer Schablone für das Dateisystem beliebig vieler Container plus Metainformationen. Da man den Images aus dem offiziellen Depot nicht grundsätzlich vertrauen kann, ist es ratsam (und einfach), ein eigenes zu bauen.

debootstrap --variant=minbase stable /var/lib/machines/Name
cd /var/lib/machines/Name && tar cf - . | docker import - User/Distribution:Codename

Um aus diesem Basis-Abbild ein spezifisches Abbild abzuleiten, startet man einen Container mit einer interaktiven Shell.

docker run -i -t --name Name User/Distribution:Codename /bin/bash

Dort installieren und konfigurieren wir die gewünschten Pakete…

docker run -i -t --name Name User/Distribution:Codename /bin/bash
apt install Package
cat << . > /etc/motd

                  ##        .
            ## ## ##       ==
         ## ## ## ##      ===
     /""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
     \______ o          __/
       \    \        __/
        \____\______/
.
exit

…und erzeugt daraus schließlich ein neues Abbild.

docker commit Name User/Subimage

Abbild automatisch erzeugen

Ein Dockerfile dient als Anleitung für den Bau von Abbildern. Es liegt in einem eigenen Verzeichnis, dem Repository.

Instruktion Parameter Beispiel Beschreibung
FROM Image[:Tag=latest] phrank/debian:bullseye Basis für das zu erzeugende Image
LABEL Name=Value maintainer=phrank Metadaten für das Image
ARG Name homedir Nimmt Umgebungsvariable von außen entgegen
ENV Name=Value HOME=${homedir:/root} Setzt Umgebungsvariable für folgende Kommandos
USER User daemon Ändert Benutzerkennung für folgende Kommandos
SHELL Path /bin/zsh Ändert Shell für folgende Kommandos
WORKDIR Path /etc Ändert Arbeitsverzeichnis, auch für CMD und ENTRYPOINT
ADD Source Dest whale.txt /etc/motd Kopiert Dateien vom Repository in den Container
COPY Source Dest ~/.inputrc /root/.inputrc Kopiert Dateien vom Host in den Container
RUN Command apt install -y nginx Führt Kommando beim Erzeugen des Containers
VOLUME Path /srv Montiert externes Verzeichnis
EXPOSE Port 80 443 Liste von Ports für die Verknüpfung von Containern
CMD Command ["/bin/uname", "-a"] Default-Kommando beim Start des Containers
ENTRYPOINT Command ["/usr/bin/nginx"] Initialer Prozess, kann nicht von run überschrieben werden.
HEALTHCHECK CMD Command CMD test true || exit 1 Fürt Kommando alle 30 Sekunden aus
STOPSIGNAL Signal SIGKILL Sendet anderes Signal beim Stoppen des Containers
ONBUILD Instruction RUN rm -rf / Führt Anweisung als Basis beim Bau verwendet wird

Kommandos in exec-Notation benötigen keine Shell.

Beispiel: Webserver

~/repository/webserver/Dockerfile
FROM User/Distribution:Codename RUN apt install -y nginx CMD nginx EXPOSE 80

Für jedes Abbild ein Verzeichnis mit einem Dockerfile darin anlegen und dort ausführen:

docker build --tag webserver ~/repository/webserver
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step 0 : FROM       User/Distribution:Codename:custom
 ---> 8b4b40246122
…
docker run -d -p 8080:80 --name webby webserver

Container ausführen

Das Kommando run erzeugt aus einem Abbild einen neuen Container, indem es folgende Schritte ausführt:

  1. Lädt das Abbild lokal (oder aus dem offiziellen Depot) herunter.
  2. Überlagert das enthaltene Dateisystem mit einer schreibbaren Schicht.
  3. Erzeugt eine Netzwerk-Schnittstelle mit einer Adresse aus einem Pool.
  4. Verbindet Standardein- und -ausgabe mit dem Terminal (Option -i und -t).
  5. Führt in diesem Container einen Prozess (bash) aus.
docker run -i -t Image /bin/bash

Der Container existiert weiter, auch wenn sich das ausgeführte Programm beendet. Mit dem Kommando start wird er im Hintergrund gestartet. Mit attach kann man Standardein- und -ausgabe verbinden und mit stop den Container beenden.

Dienste dockerisieren

Aus verschiedenen Gründen kann es sinnvoll sein, Dienste in getrennten Containern laufen zu lassen. Zuerst muss auf dem Host-System IP-Forwarding aktivieren.

sysctl "net.ipv4.ip_forward=1"

Folgender Aufruf startet den Container als Daemon (-d) mit Portweiterleitung (-p).

docker run --name=Name -d -p HostPort:GuestPort Image Command

Und so wird ein laufender Container gestoppt:

docker stop Name

Beim Herunterfahren des Containers sendet Docker jedem Prozess ein Signal und tötet nach einer Schonfrist von 10 Sekunden alle noch laufenden Prozesse. Damit containerisierte Dienste einen Neustart des Rechners überleben, meldet man sie beim Init-System an.

/etc/systemd/system/Name.service
[Unit] Description=Text Author=DisplayName After=docker.service [Service] Restart=always ExecStart=/usr/bin/docker start -a Name ExecStop=/usr/bin/docker stop Name [Install] WantedBy=local.target

Schließlich starten wir den containerisierten Dienst.

systemctl enable --now Name.service

Schwarm aus mehreren Rechnern

Ein Schwarm fasst mehrere Rechner mit Docker Engine (Knoten) zu einem Cluster zusammen und verbindet die teilnehmenden Container zu einem virtuellen Netzwerk mit integriertem DHCP- und DNS-Server.

Referenz

Diese Auflistung soll nur einen Überblick über die verfügbaren Kommandos und Optionen vermitteln und erhebt keinen Anspruch auf Vollständigkeit. Als authoritative Quelle gelten nur die Manpages und die offizielle Dokumentation.

Kommando Option Parameter Beschreibung
Daemon
docker help Command Erklärt Optionen des Kommandos
docker version Zeigt Version der Komponenten
docker info Zeigt Übersicht der Objekte
docker stats -a|--all Beobachtet verwendete Ressourcen
docker events --since=Time Gibt Echtzeit-Ereignisse aus
--until=Time …in diesem Zeitraum
docker system df Berechnet verwendeten Plattenplatz
docker system prune Löscht nicht verwendete Objekte
Depot
docker login -e|--email=EmailAddress[Server] Meldet Benutzer beim Depot an
-u|--username=User …mit Name
-p|--password=Pass …und Passwort
docker logout [Server] Meldet Benutzer ab
docker search Keyword Sucht Image auf dem Docker Hub
docker pull Name[:Tag] Holt Image vom Depot
docker push Name[:Tag] Sendet Image zum Depot
Image
docker images [Name] Listet verfügbare Images auf
-a|--all …mit allen Zwischenschichten
-f|--filter=[…] …mit bestimmten Eigenschaften
-q|--quiet …aber nur die Nummer
docker build -t|--tag="Name:TagPath | UrlBaut Image nach Anleitung aus dem Dockerfile im Pfad
docker import Url Image[:Tag] Erzeugt Image aus einem Tar Archiv
docker export Container Schreibt Dateien des Containers in ein Tar Archiv
docker load -i|--input=File Liest Image aus Tar Archiv
docker save -o|--output=File Schreibt Image in Tar Archiv
docker tag Image[:Tag] [RegistryHost/][User/]Name[:Tag]
docker history Image Zeigt die Historie eines Images
docker image prune Image Löscht nicht verwendete Images
docker rmi Image Löscht ein Image
Container erzeugen
docker run Image [Command] Führt Kommando in neuem Container aus
docker create Image [Command] Erzeugt Container aus Image
docker start Container Startet einen gestoppten Container
-a|--attach Verbindet die Standardausgaben
-i|--interactive Verbindet die Standardeingabe
docker stop -t|--time=10 Stoppt einen laufenden Container (nach 10 Sekunden)
docker restart -t|--time=10 Startet einen laufenden Container neu
docker pause Container Pausiert alle Prozesse in einem Container
docker unpause Container Setzt pausierte Prozesse fort
docker wait Container Wartet, bis sich der Container beendet hat
docker kill -s|--signal="KILL" Container Sendet Signal an laufenden Container
docker update Container Ändert Konfiguration eines Containers
docker rename Container Name Benennt Container um
docker rm Container Löscht gestoppten Container
-f|--force Stoppt laufende Container vorher
-l|--link Löscht nur den Link
-v|--volumes Löscht auch Volumen
Container untersuchen
docker ps Listet laufende Container auf
-a|--all …alle (auch gestoppte) Container
-f|--filter …die auf das Muster passen
-l|--latest …nur den zuletzt erzeugten
-n|--last=N …die letzen paar
-q|--quiet …nur Container-Nummer ausgeben
-s|--size …mit Dateigrößen
docker inspect Container Zeigt Parameter eines Containers
docker logs -f|--follow Container Reicht die Standardausgabe durch
-t|--timestamps Zeigt Zeitstempel an
docker port Container [Port] Listet Port-Zuordnungen auf
docker top Container Listet die enthaltenen Prozesse auf
docker attach Container Verbindet Standardein- und ausgabe
docker exec Container CommandFührt Kommando im Container aus
-d|--detach …im Hintergrund
-e|--env=[] …mit Umgebungsvariablen
-i|--interactive …mit offener Standardeingabe
-t|--tty …mit Pseudo-Terminal
-u|--user=Uid[:Gid] …als Benutzer (in Gruppe)
--privileged …mit weitreichenden Privilegien
docker cp Container:Path PathKopiert Dateien vom Container zum Host
docker diff Container Gibt Änderungen im Dateisystem aus
docker commit -a|--author=Name Container [Image[:Tag]]Erzeugt neues Image mit diesen Änderungen
-m|--message=Text …mit Kommentar
Volumen
docker volume ls Volume Listet Volumen auf
docker volume create -d|--driver=Local Erzeugt neues Volumen
-o|--opt=[] …mit Optionen für den Treiber
-l|--label=Name …mit diesem Namen
docker volume inspect Volume Zeigt Parameter eines Volumens
docker volume prune Volume Löscht nicht verwendete Volumen
docker volume rm Volume Löscht ein Volumen
Schwarm
docker swarm init --advertise-addr=IpAddress Gründet einen Schwarm
docker swarm join --token=Token ManagerIp:2377 Fügt Arbeiter hinzu
docker swarm leave @todo
docker swarm unlock @todo
docker swarm update @todo
Knoten
docker node ls Listet Knoten im Schwarm auf
docker node ps [Node] Listet Prozesse im (aktuellen) Knoten auf
docker node inspect Node Gibt Parameter aus
docker node promote Node Befördert Knoten zum Manager
docker node demote Node Degradiert Knoten zum Arbeiter
docker node update Node Ändert Parameter
docker node rm Node Entfernt Knoten aus dem Schwarm
Dienst
docker service ls Listet alle Dienste auf
docker service ps Service Listet die Arbeiter eines Dienstes auf
docker service create --name=Service Image [Command] Erzeugt mehrere Container aus einem Image
--replicas=N …mit so vielen Arbeitern
docker service inspect Service Zeigt Parameter eines Dienstes
docker service update Tauscht das Image aller Arbeiter
docker service scale Service=N Ändert Anzahl der Arbeiter
docker service rm Entfernt alle Arbeiter des Dienstes
Option Argument Beschreibung
-a --attach STDIN Standardeigabe,
STDOUT Standardausgabe und
STDERR Fehlerausgabe aufzeichnen
-c --cpu-shares 0 Relatives Gewicht festlegen
--cap-add [CAP_…] Linux-Capabilities zuweisen
--cap-drop [CAP_…] Linux-Capabilities ablegen
-d --detach false Als Daemon laufen (nur run)
--device /dev/HostDevice:/dev/ContainerDevice Gerätedatei durchreichen
--dns IpAddress DNS-Server festlegen
--dns-search Domain Suchpräfix verwenden
-e --env [Name=Value …] Umgebungsvariable setzen
--env-file Path Umgebung aus Datei lesen
--entrypoint Command ENTRYPOINT überschreiben
--expose Port Port durchreichen
-h --hostname Host Name des Containers festlegen
-i --interactive false Standardeingabe offen halten
-l --label Name Container benennen
-m --memory N[bkmg] Speicherauslastung begrenzen
--name Name Alias für die Container-Nummer definieren
--net bridge Virtuelles Netzwerk bauen
container:Name:Id …Stack des Containers
host …Stack des Hosts (unsicher)
none …Keines
-p --publish [IpAddress:]HostPort:ContainerPortPorts durchreichen
-P --publish-all false Alle Ports durchreichen
--privileged false Privilegien erweitern
--restart no Kein Neustart nach Exit
on-failure Neustart bei Fehler
always …immer
unless-stopped …außer wenn gestoppt
--rm false Container beim Beenden löschen
-t --tty false Pseudo-Terminal verwenden
-u --user Uid[:Gid] Als Benutzer (in Gruppe) laufen
-v --volume [HostPath:ContainerPath …]Volumen montieren
-w --workdir Path Arbeitsverzeichnis wechseln

Literatur

  1. Debian Wiki: Docker
  2. Steve Kemp: A brief introduction to using docker
  3. Joey Hess: what does docker.io run -it debian sh run?
  4. Thorsten Leemhuis: Hafenarbeiter, c't 17/2014
  5. Bottomley, Emalyanov: Containers [PDF], Login 10/2014
  6. Neil Brown: Control groups series, LWN 7, 2014
  7. Michael Kerrisk: Namespaces in operation, LWN, 4/2013
  8. CoreOS: Quick Start