Inhaltsverzeichnis

Docker ist eine Open-Source-Plattform zur Containerisierung von Anwendungen. Es ermöglicht die Erstellung, Bereitstellung und Ausführung von Anwendungen in isolierten Containern, die unabhängig von der zugrunde liegenden Infrastruktur sind. Docker bietet eine standardisierte Methode zum Verpacken von Software und allen damit verbundenen Abhängigkeiten in ein einzelnes Paket, das als Docker-Image bezeichnet wird. Diese Images können dann auf jedem System ausgeführt werden, das Docker unterstützt.

Docker basiert auf der Linux-Containertechnologie (LXC) und nutzt die Funktionen des Linux-Kernels, um isolierte Umgebungen, sogenannte Container, zu erstellen. Jeder Container enthält eine eigenständige und isolierte Umgebung, in der eine Anwendung und ihre Abhängigkeiten ausgeführt werden können. Die Isolation sorgt dafür, dass eine Anwendung und ihre Abhängigkeiten unabhängig von anderen Containern und dem Hostsystem ausgeführt werden können, was zu einer besseren Portabilität und Skalierbarkeit führt.

Siehe auch Kubernetes.

Hauptkomponenten

Dockerfile

Ein Dockerfile ist eine Textdatei, die eine automatisierte Build-Anweisung für das Erstellen eines Docker-Images enthält. Dockerfiles werden verwendet, um Container-Images zu erstellen.

Ein Dockerfile besteht aus einer Reihe von Anweisungen, die Docker verwendet, um ein Docker-Image zu erstellen. Jede Anweisung in einem Dockerfile führt eine bestimmte Aktion aus, z. B. das Hinzufügen von Dateien, das Ausführen von Befehlen oder das Festlegen von Umgebungsvariablen. Dockerfiles verwenden eine einfache Syntax und können mit grundlegenden Texteditoren erstellt und bearbeitet werden.

Hier sind einige der gängigsten Anweisungen, die in einem Dockerfile verwendet werden:

# Verwenden des Python-Basisimages
FROM python:3.9

# Setzen des Arbeitsverzeichnisses innerhalb des Containers
WORKDIR /app

# Kopieren der Anforderungen (requirements.txt) in den Container
COPY requirements.txt .

# Installation der Abhängigkeiten
RUN pip install --no-cache-dir -r requirements.txt

# Kopieren des Anwendungsquellcodes in den Container
COPY . .

# Exponieren des Ports, auf dem die Anwendung lauscht
EXPOSE 8000

# Festlegen des Standardbefehls beim Starten des Containers
CMD ["python", "app.py"]

Den Container erstellen.

docker build -t <containername> .
docker run -dit -p 80:80 <containername>

Docker-Compose

Im Gegensatz zu einem einzelnen Dockerfile, das ein einzelnes Image definiert, ermöglicht Docker Compose die Definition und Konfiguration von Diensten, Netzwerken und Volumes für eine vollständige Anwendungsumgebung. Es verwendet eine einfache YAML-Datei, um die Konfiguration zu beschreiben.

version: '3'
services:
  webserver:
    image: httpd:latest
    networks:
      - my-network
    ports:
      - 80:80
    volumes:
      - ./html:/usr/local/apache2/htdocs/
    depends_on:
      - database
  database:
    image: mariadb:latest
    networks:
      - my-network
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=mydatabase
      - MYSQL_USER=myuser
      - MYSQL_PASSWORD=mypassword
    volumes:
      - db-data:/var/lib/mysql
volumes:
  db-data:
networks:
  my-network: 

Deployments

Um einen Load-Balanced Cluster mit mehreren Instanzen einer Anwendung zu erstellen, kannst du die Deploymentfunktion von Docker Compose verwenden. Somit laufen 3 Instanzen der Anwendung. Fällt eine aus, wird automatisch ein neuer Container gestartet.

version: '3'
services:
  app:
    image: myapp:latest
    ports:
      - 80:80
    deploy:
      mode: replicated
      replicas: 3
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: any

Deployment starten/stoppen

// Im Verzeichnis wo die docker-compose.yaml Datei liegt
sudo docker compose [-f <yml-filename>] up -d

sudo docker compose down <deployment-name>

Volumes

Docker Volumes werden verwendet, um Daten zwischen Containern und dem Host-Betriebssystem auszutauschen und um sicherzustellen, dass Daten auch dann erhalten bleiben, wenn Container neu erstellt oder aktualisiert werden. Es sind sozusagen virtuelle Festplatten für Container.

Ein Volume erstellen kann man mit

docker volume create myvolume

Mit dem Parameter –mount kann man ein Volume in einen Container mounten. Mit dem Parameter -v kann man einen Pfad am Host in einen Mountpoint am Container mounten.

docker run -dit --mount source=<docker-volume>,target=<container-mountpoint> ubuntu
docker run -dit -v <host-path>:<container-path> ubuntu

LVM

Vor der Installation bzw Inbbetriebnahme von Docker das LVM anlegen.

sudo mount /dev/docker_vg_lv0 /var/lib/docker

In der fstab

/dev/docker-vg/lv0 /var/lib/docker ext4 defaults 0 2

Netzwerke

Docker Networking unterstützt verschiedene Netzwerkmodelle, um den unterschiedlichen Anforderungen von Anwendungen gerecht zu werden.

NameBeschreibung
nonetodo
HostDas Host-Netzwerkmodell verwendet das Netzwerk des Docker-Hosts direkt für die Container. Container, die das Host-Netzwerk verwenden, haben Zugriff auf alle Netzwerkressourcen des Hosts, einschließlich der Netzwerkschnittstellen und Ports. Dieses Modell bietet eine maximale Leistung, kann aber die Isolation zwischen Containern beeinträchtigen.
BridgeEin Bridge-Netzwerk ist das Standardnetzwerkmodell von Docker. Es erstellt ein isoliertes Netzwerk für Container auf dem Docker-Host und ermöglicht die Kommunikation zwischen Containern über einen gemeinsamen Bridge-Dienst. Bridge-Netzwerke sind standardmäßig in Docker aktiviert und bieten eine einfache Möglichkeit, Container zu verbinden.
OverlayOverlay-Netzwerke werden verwendet, um Container über mehrere Docker-Hosts hinweg zu verbinden. Sie ermöglichen es Containern, über Host-Grenzen hinweg zu kommunizieren und eine skalierbare, verteilte Anwendung zu erstellen. Overlay-Netzwerke verwenden spezielle Protokolle wie VXLAN oder IPSec, um Container über das gesamte Cluster hinweg zu vernetzen.
MacVlanDas macvlan Netzwerkmodell ermöglicht es Containern, eine eigene MAC-Adresse zu haben und direkt mit dem physikalischen Netzwerk zu kommunizieren. Jeder Container erhält eine eindeutige MAC-Adresse, die von der des Hosts abweichen kann. Dies ermöglicht es Containern, direkt auf das physische Netzwerk zuzugreifen und mit anderen Geräten zu kommunizieren, als ob sie direkt an das physische Netzwerk angeschlossen wären.
IpVlanDas ipvlan Netzwerkmodell ist ähnlich wie das macvlan Modell, jedoch auf IP-Ebene. Es ermöglicht es Containern, eigene IP-Adressen zu haben und direkt mit dem physikalischen Netzwerk zu kommunizieren. Jeder Container erhält eine eindeutige IP-Adresse, die von der des Hosts abweichen kann.

Mit

docker network create -d <driver> <network-name>
docker network inspect <network-name>
docker network rm <network-name>

kann man ein neues erstellen. Ein Container Interface an ein Netzwerk binden kann man mit dem Parameter –network.

docker run -dit --name test --network mynetwork ubuntu

Ein Netzwerk von einem Container entfernen oder ändern kann man mit

docker network disconnect <network-name> <container-name>
docker network connect <network-name> <container-name>

Traefik

Traefik ist ein Reverse Proxy um Container über das Internet erreichbar zu machen.

Installation

Docker Installation.

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

Ubuntu

# update packages
sudo apt-get update

# add pgp key for signed docker repository
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# update again
sudo apt-get update

# install docker
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

WSL2

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

sudo usermod -aG docker $USER

# Install Docker Compose v2
sudo apt-get update && sudo apt-get install docker-compose-plugin

# Sanity check that both tools were installed successfully
docker --version
docker compose version

# Using Ubuntu 22.04 or Debian 10 / 11? You need to do 1 extra step for iptables
# compatibility, you'll want to choose option (1) from the prompt to use iptables-legacy.
sudo update-alternatives --config iptables

Docker Daemon

nano /etc/docker/daemon.json
{
  "bip": "172.17.1.1/24",
  "ipv6": false,
  "storage-driver": "devicemapper",
  "storage-opts": 
     [
       "dm.basesize = 41G",
       "dm.thinpooldev=/dev/mapper/docker--vg-thinpool",
       "dm.use_deferred_removal=true"
     ]
}

Usage

docker pull <image>
docker images
docker rmi -f <image-id>
docker image prune

docker inspect <container>
docker container diff <container> // see changes from base image

// see https://docs.docker.com/engine/reference/commandline/run/
docker run -dit --name <container-name> --hostname <hostname> -p <ext-port>:<int-port> --mount source=<vol>,target=<mountpoint>,readonly -v <volume>:<mountpoint> <image> <commands>
 --> -it - interactive, root terminal
 --> -p - port mapping ext:int
 --> -d - detach console
 --> --name - set container name
 --> --mount mount a docker-volume
 --> -v - mount a host folder <folder>:<mountpoint>
 --> --network - connect to a specific docker-network
 --> --cpus=0.1 - use 1 % of cpu
 --> -m 512m - use max 512 bytes of memory
 --> --cpu-shares=2000 - operations per cycle?
 --> -e VAR=1 - set environment variable

// change a running container using a snapshot
docker commit <container> <new-image-name>
docker run -dit <new-image-name> 

// start with same settings as setup
docker start <container>

// befehl auf laufendem host ausführen
docker exec <container> <commands>

docker attach <container>
sudo docker exec -it <container> /bin/bash
# ctrl + p - ctrl q ==> detach (nur mit -ti)?

docker start <container>
docker stop <container>
docker restart <container>

docker rename <oldname> <newname>

docker container ls
docker ps -a
docker rm <container>
docker container prune // remove all "status=exited" containers

// volumes
docker volume create --name testvol
docker volume inspect test-vol
docker volume rm test-vol
docker run -dit --mount source=test-vol,target=/mount/test,readonly <image>
docker run -dit -v test-vol:/mount/test <image>

// networking
docker network create -d bridge MyBridgedNetwork
docker network connect <options> <network> <container>
docker network inspect

docker network connect <network> <container>
docker network disconnect <network> <container>

Docker Swarm Cluster

Als erstes erstellt man mit dem Befehl

docker swarm init --advertise-addr <manager-ip>

ein Kontrollnode. Am Ende wird ein Token angezeigt, diesem gut merken! Möchte man weitere Nodes zu dem Cluster hinzufügen, führt man auf den jeweiligen Nodes den Befehl

docker swarm join --token <swarm-token> <manager-node-ip>

aus. Mit dem Befehl

docker node ls

werden alle Nodes eines Clusters angezeigt.