Docker Seminare

[Wer sofort mit den Docker Seminarunterlagen loslegen will: Einführung]

Container (Bild Unsplash: timelab-pro-sWOvgOOFk1g-unsplash.jpg)

Container (Bild Unsplash: timelab-pro-sWOvgOOFk1g-unsplash.jpg)

Virtualisierungen und Container nehmen in den IT-Infrastrukturen eine immer größere Bedeutung ein.

Manche sprechen bei Containern von der nächsten Evolutionsstufe der Virtualisierung. Diese Seminare widmen sich der Praxis von Containern mit Docker - bzw. den Container-Alternativen - und wird auch die technischen, theoretischen und sicherheitsrelevanten Themen für Applikationscontainer nicht vernachlässigen.

Sie werden die Administration von Docker (bzw. Containern) erlernen und den unterschiedlichen Einsatz von Docker für Projektumgebungen kennen lernen. Und natürlich werden auch die netzwerk- und sicherheitsspezifischen Aspekte nicht zu kurz kommen.

Virtualisierungstechnik ist ein Dauerbrenner in der IT.

Die Techniken bieten eine große Bandbreite: von kleinen technischen Umgebungen im Rahmen von SW-Development bis zu den großen Cloud-Lösungen wie Microsoft Azure oder den Amazon Web Services (AWS).

Die Umsetzungen basieren dabei auf Virtuellen Maschinen (VMs) und/oder den sogenannten Containern. Die Techniken drängen aktuell auch in die Private IT:

  • VMs und Container auf dem NAS

  • SW-Entwicklungsumgebung per Container auf dem Raspberry Pi

  • Web-Oberflächen für das Smart-Home

Die Liste ließe sich beliebig verlängern.

In unserem praxisorientiertem Seminar wollen wir uns mit Installationen und Einrichtungen der Virtualisierungstechniken und Container-Managements einen intensiven Einblick in diese Techniken verschaffen.

Ihr Trainer Joe Brandes

Für einen schnelleren Überblick - in den HTML-Dokumenenten - folgt hier das Stichwortverzeichns und die Dokumentstruktur:


Stichwortverzeichnis


Willkommen zu Docker

Manche meiner RST-Unterlagen sind im Laufe der Jahre zu kleinen Büchern gewachsen. Das möchte ich mit dieser Unterlage nicht (er)schaffen. Und die Autoren haben mir/uns die Arbeit „Buch“ ja auch schon abgenommen!

Diese Unterlage sollte eher als „Cheat Sheet“ / „Roter Faden“ verstanden und genutzt werden!

Und jetzt viel Spaß mit Docker…

Erste Aufrufe mit Docker Containern

Erste Aufrufe mit Docker Containern

Docker Umgebungen

Docker Software gibt es für nahezu alle Betriebssysteme. Und in unseren Seminaren wollen wir die OS-Implementierungen versuchen in Gänze zu erfassen.

Operating Systems für Hosts und Container

Operating Systems für Hosts und Container (Bild Unsplash: claudio-schwarz-z508Zk08HNU-unsplash.jpg)

Besonderen Wert sollte man beim Einstieg in die Materie auf die genutzten Docker (bzw. Container) Bereitstellungen legen.

  • Hosts: beliebige OS wie Windows, MacOS und Linux

  • Container OS: Linux Container vs. Windows Container

Die natürliche Umgebung für Container-Techniken ist Linux. Das liegt nahe, da in fast allen Fällen auch Linux Container zum Einsatz kommen.

Hinweis

Im 1400 Seiten zweiten Container-Werk von O. Liebel sind Windows Container komplett herausgefallen und der Nano-Server findet ebenfalls nicht statt!

Wir werden uns also im Weiteren auf Linux Container konzentrieren und uns jeweils für ein Operating System nach Wahl für die Umsetzung als Container Host (oder auch Container Serverumgebung) entscheiden.

Schauen wir uns also die üblichen Verdächtigen für einen Einsatz als Docker Hosts an.

Windows

Für den Einstieg - und zur Erinnerung - ist es wieder wichtig zu unterscheiden:

  • OS für Container: (gewünscht) Linux Container

  • Host für Container-Technik: Windows 10 (oder 11)

Wir wollen also Windows als Host-System für unsere Linux Container-Umsetzungen nutzen.

Wo bekommen wir unter Windows eine Linux Maschine (einen Linux Kernel) her, den wir für die Linux Container nutzen können?

  • Linux VM mit Hyper-V (Hyper-V benötigt min. Windows Pro/Enterprise)

  • Docker Toolbox (Legacy oder ggf. in Kombination mit VirtualBox betrachten)

  • Docker Desktop für Windows mit Linux Moby VM bereitgestellt mit Hyper-V

  • Docker Desktop für Windows mit WSL2

Install Docker Desktop on Windows

Install Docker Desktop on Windows

Wir starten mit der aktuell attraktivsten Docker-Kombi zur Umsetzung mit Windows.

Docker Desktop für Windows mit WSL2

Die Dockerversionen liegen für alle OS als Docker Desktop für Mac/Linux/Win vor. Das ermöglicht auf allen OS dieselben Arbeits- und Deployumgebungen. Allerdings setzt man unter Linux/MacOS im Grunde immer auf die nativen Installationen.

Hinweis

Bitte dann später Anleitungen für unterschiedliche Projekte wie Portainer beachten, die auf diese unterschiedlichen Umgebungen hinweisen!

Installarchiv für die Docker für Windows (Hyper-V) Technik am Besten über Umweg docs.docker.com

Docker Desktop für Windows mit MobyVM

Wir bnenötigen Windows 10 Pro oder Enterprise für Hyper-V mit MobyLinuxVM!

Die Nutzung des Docker Desktop unterscheidet sich nicht grundsätzlich von der WSL2-Technikkombination. Die Umsetzung ist allerdings nicht so effizient und schlank.

Hinweis

Bei dieser Technikumsetzung könnte man auch zwischen den Linux und Windows Containern switchen!

Linux VMs mit Hyper-V

Man kann sich einfach eine Linux-Distro nach Wahl im Hyper-V installieren und dann mit der gewünschten Container Technik experimentieren.

Da Container keine wirkliche Virtualisierung benötigen ist Docker in einer VM also überhaupt kein Problem! Und Hyper-V würde über das Feature ExposedVirtualization ja sogar ein sogenanntes Nested (sprich: verschachteltes) Virtualisieren erlauben!

Docker Toolbox (DEPRECATED)

Das sollte die letzte Bastion für eine Umsetzung darstellen, da wir die Techniken sehr aufwändig und ineffizient kombinieren und bereitstellen. Und es gibt ja auch in der Kombination Windows (auch Home) mit WSL2 keinen Grund mehr gegen Docker Desktop für Windows!

Gefahr

Legacy Tech: Docker Toolbox - officially deprecated since late 2020: Docker Archive Link Toolbox .

Wir würden hier eine vorhandene VirtualBox Installation mit der Docker Toolbox kombinieren.

Linux

Verschiedene Installationen in meinen Seminaren zeigen die native Kombination aus Linux Container Host und Linux Containern.

Statt einem Docker Desktop für Linux können wir die Installation der Docker Engine nutzen.

Install Docker Engine on Linux

Install Docker Engine on Linux

Hier folgen ein paar Anmerkungen zu Linux-Distros.

Aber generell eignen sich alle Linux-Distros für eiese Umsetzungen. Sehr häufig wird in diesen Zusammenhängen natürlich auch der Ubuntu Server genannt, der auf Grund seines LTS Charakters diverse Vorzüge verspricht.

Hinweis

Bitte überprüfen, ob der Docker Daemon läuft und enabled ist für Standard-Target/Runlevel!

Alle Aufrufe (hier folgend) und dann auch für docker müssen mit root-Rechten durchgeführt werden.

systemctl status docker.service
systemctl start docker.service           # oder gleich
systemctl enable docker.service --now    # enable und start
docker version

Im letzten Aufruf müssen Client und Server aufgelistet sein.

Im Seminar wird auch der Standarduser für docker berechtigt werden, um die tägliche Seminar- und Schulungsarbeit zu erleichtern.

Hierfür muss manchmal die Gruppe docker neu erstellt werden

groupadd docker    # falls noch nicht vorhanden und nicht mit dockerroot (CentOS) verwechseln
usermod -aG docker standarduser

Bitte bei der obigen Syntax unbedingt auf die korrekte Schreibweise der Gruppenzuordnung (Parameter a mit Groß G) achten!

Gefahr

Docker mit Standarduser kann ein großes Sicherheitsrisiko darstellen! Darstellungen hierzu folgen!

macOS

Pers. Anm.: noch mehr außer Konkurrenz als Docker für Windows ;-)

Die Installationsdatei (DMG) für Docker Desktop für Mac (MacOS) finden Sie unter folgender Adresse: Docker für Mac

Die Installer sind auch für die neueren Apple Silicon M1/M2 Prozessoren verfügbar.

Container Fachbegriffe

Das folgende Image ist eine einfache Übersicht über beteiligte Techniken und Fachbegriffe. Man lehnt sich an einem (s.a. Netzwerke) üblichen Layer System an.

Virtuelle Layers

Virtuelle Layers (Bild: Liebel - Skalierbare Container-Infrastrukturen für Ihr Unternehmen)

Basis-Begriffe:

  • Images - unveränderlich / ro

  • Container - basieren auf Images, nutzen ein Overlay-Dateisystem

    Container basiert auf Image; Container-Instanz ist R/W (Read/Write) Layer

    maximale Anzahl Layer: 128 (bei overlay2, devicemapper; s.u.)

    Container-Hosts: physikalische/reale oder virtuelle Maschine

  • Volumes - möglichst vom Container getrennte Verzeichnisse im Docker-Host-System

Vertiefung:

  • Services - Dienst/Aufgabe

    Um diese Services kümmert sich Docker selbst! Sogar auf welchem Docker-Host!

  • Stacks - Administration von Service-Gruppen

  • Cluster - Vorraussetzung für Services und Stacks;

    Docker Nomenklatur: Swarm; s.a. Python-Skriptool docker-compose

  • Kubernetes - Google Open Source für Container-Verwaltungen;

    Läuft Docker Swarm den Rang ab und auch Fa. Docker Hat mittlerweile auf K8s umgeschwenkt!

  • Continouus Delivery / Continous Integration (CD/CI)

    Versuch der Eklärung: (semi-)automatisierte Verfahren (CI) von kleinteiligen Releases mit ebenfalls möglichst automatischen Deployment-Test (CD)

    siehe: Liebel Kap. 2.3ff

Container Technik

Weitere Fachbgegriffe und kurze Erläuterungen:

docker Client-Server-Modell (Anm.: bei Windows/MacOS Umsetzungen wird das komplizierter!)

Die Umsetzung mit Linux: docker CLI mit dockerd (Docker Daemon/Engine)

Docker-Client und Server kommunizieren über eine HTTP-RESTful API.

Anm.: für eine sichere Kommunikation siehe Docker Security HTTPS

Einfacher Test der HTTP-Verbindung:

curl -s --unix-socket /var/run/docker.sock http://localhost/images/json

Das erzeugt einen etwas unleserlichen (serialisierten) Infostrom, der sich mit dem Tool jq besser analysieren und lesen lässt:

curl -s --unix-socket /var/run/docker.sock http://localhost/images/json | jq

Tipp

Paket jq nachinstallieren! Anm.: für CentOS benötigt man EPEL-Repo!

Bei diesen Ausgaben bitte auch gleich auf die Syntax der JSON-Strukturen achten:

  • Klammerungen

  • Aufzählungen mit Kommata

  • Keine Kommentare!

Registry

Technisch: Image-Datenbank mit Service zum pullen und pushen von Images

Im Produktionsbetrieb müsssen aus Sicherheitaspekten vertrauenswürdige und daher firmeninterne Registries genutzt werden.

Docker Registry: https://index.docker.io/v1/

Registry finden/analysieren: docker info | grep -i registry

Alternative Registries:

Anm.: Werden im Seminar - bis auf Weiteres - keine Rolle spielen (siehe auch nötige Accounts, ggfs. Kosten, …)

Repository

Logische Unterteilung einer Registry; Fundus mit mehreren Images (siehe Tags); siehe ubuntu:* (beliebige Ubuntu-Varianten)

keine init/systemd Techniken

Was passiert bei mehr als einem Dienst pro Container?

Virtuelle VMs vs. Container

die Container als „Leichtgewichte“ und ohne Prozesse-Lasten; und Nutzung von VMs für Docker-Hosts!

Virtuelle Maschinen und Container

Virtuelle Maschinen und Container (Bild: Liebel - Skalierbare Container-Infrastrukturen für Ihr Unternehmen)

Container Lösungen (Wikipedia Containervirtualisierung )

  • Klassiker:

    FreeBSD Jails (ca. 2000), Solaris Zones (ca. 2005), OpenVZ (ca. 2005; siehe Virtuozzo von Parallels)

  • LXD für LXC (ca. 2008; Linux Containers oder Lightweight Linux Container) - Ausgangsbasis für Docker

  • rkt (sprich: Rocket) - von CoreOS (bzw. Produkt Container Linux)

  • VMware Photon

  • Docker

    März 2013 Fa. dotCloud - dann Oktober 2013 umbenannt in Docker Inc. mit Sitz in Berlin

    Neue Componenten (ab Version >= 1.11): containerd, runc,

    aus „Docker Daemon“ wurde Docker Engine;

    ab Version 1.12 mit eingebauter Swarm Technik: Swarm Mode

    Schwerpunkt auf Applikationsvirtualisierung und nicht auf abgespeckte VMs

Tipp

Darstellung runc als eigenständiges Container-Tool bei Liebel (S. 85ff.)

Container Formate

  • Docker, CoreOS/rkt, LXD/LXC, Photon, …

  • OCF (Open Container Format) der OCI (Open Container Initiative - www.opencontainers.org

Namespaces

Ressourcen von Kernel lassen sich isolieren - Prozesse erhalten quasi eigene Umgebung

Tipp

Übung mit uname -r und grep -i pretty_name /etc/os-release Aufrufen in Host und Containern!

Docker Windows Images

Bitte hierzu die folgenden Technikhinweise beachten:

  • Windows Server Core

  • Nano Server

  • IIS

  • ASP.NET

Anm.: Nano Server nur für Windows Server Instanzen verfügbar!

Container Sicherheit

Faktoren für die Sicherheit der Container-Techniken:

  • Herkunft der genutzten Images

  • Wegen der Kernel-syscall Techniken (siehe namespaces) problematisch!

Tipp

Bitte seccomp >= Version 2.2.1

Anm./Empfehlung zu Thema namespaces:

# cat /boot/config-$(uname -r) | grep CONFIG_SECCOMP=
CONFIG_SECCOMP=y
# rpm -qa | grep seccomp
libseccomp2-2.3.2-lp150.1.9.x86_64
joeb@opensuse:~/rst/docker>

Links:

Empfehlungen:

  • Implementierungen mittels cgroups (Control Groups für Nutzung von Limits)

  • Applikationen in Container möglichst nicht mit root

  • Fähigkeiten der Images einschränken

  • User-Namespace aktiv

  • seccomp/SELinux/Apparmor

  • keine SUID im Container

  • aktuelle Kernel

  • Container-Host härten, aktualisieren, patchen

  • Container-Host Zugriffe einschränken

  • Netzwerk sichern / konfigurieren

Hinweis

Also: SELinux und auch Firewalltechnken (Netfilter/iptables, firewalld, …) bedenken.

Zu diesen vertiefenden Themen in Produktionsumgebungen an dieser Stelle keine weiteren Ausführungen.

Faktoren für Security

Ganz wichtige aber eben auch ganz dicke Bretter…

  • AppArmor (Application Armor)

  • SELinux (Security Enhanced Linux) - wollen wir für Test auf permissive

    Status ermitteln mit: sestatus oder ls -Z (bei CentOS; bei Debian, openSUSE sollte SELinux deaktiv sein)

    (Auszug/Zeile:) Current Mode: enforcing

    Ausschalten mit setenforce 0

    Dauerhafte Konfiguration in /etc/sysconfig/selinux

  • Netfilter/iptables (bzw. Dienste firewalld, ufw)

    Anm.: auch immer mal verantwortlich bei vermeintlichen Docker Technik Problemen!

Sicherheitstechnik

Container sind zwar durch Namespaces isoliert. Doch das ist bei Weitem nicht derselbe Schutz, wie es bei echten Virtualisierungen erreicht werden kann.

Technische Ansätze zur Isolierung zum Host:

  • Namespaces (siehe UIDs, GIDs, PIDs pro Container)

  • Mount-Namespaces auf Kernelebene (sicherer als chroot)

  • eigener Netzwerkstack

Gefahr

Docker Prozess verlangen nach root

Siehe Rechte für

ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0  7. Jan 12:35 /var/run/docker.sock

Aus Vereinfachungs- und Seminargründen entscheiden wir uns dennoch für

usermod -aG docker joeb

Ansätze zur Verbesserung der Sicherheit:

Vertrauenswürdige Images

Wir nutzen bisher einfach öffentliche Images aus möglichst offiziellen Quellen.

Wie sieht es aber mit echt vertrauenswürdigen Images aus?

Eigenes Basis-Image

Wir erstellen/installieren ein Template-System und erstellen hieraus einen Tarball.

Dieses lässt sich dann auf dem Docker-Host wieder Importieren.

Image-Erzeugung per Skript

Beispiel: YUM-Based mit Skript online

Images from Scratch

Siehe Docker Registry: Offizielles Image Scratch

SUSE/SLES sle2docker

Auf Ruby basierendes spezielles Tool mit speziellen Registries für Suse-Plattformen.

Erste Beispiele

Wir wollen ein Gefühl für die Docker-Technik bekommen - „Learning by Doing

Hello World mit PHP

Hello World mit PHP

Fertige „Hello World“ Beispiele (inkl. Dockerfile Nutzungen) nach „Öggl/Kofler“ (siehe Literatur) mit Umsetzungen mit:

  • apache2/php

  • node.js

  • python

Tipp

Anm.: möglichst erst später im Seminar - wir wollen uns herantasten

Hier beispielhaftes Dockerfile für das Hello-World apache2/php Image:

Dockerfile für apache2/php Lösung
1FROM php:7-apache
2ENV TZ="Europe/Amsterdam"
3COPY index.php /var/www/html

Mehr dazu aber - wie bereits gesagt - dann später! Hier sollen jetzt einsetzbare erste Beispiele folgen.

Beispiel Hello World!

Kein Seminar oder Scripting ohne ein „Hello World!“ Beispiel!

Erste Aufrufe also:

1docker run hello-World
2docker ps -a
3docker images

Basis-Images Docker Hub

Beispielhafte Suche nach offiziellen Basis-Images: Docker Hub - Offizielle Basis Images

z.B. Ubuntu https://hub.docker.com/_/ubuntu

also:

docker run -it ubuntu

Bestehende Container nutzen:

docker start -i <name>  (oder die ID)

Anm.: bei Namen funzt Completion

Besser beim Erstellen der Container auf Namen achten: (hier für Container und Docker-„Maschine“)

docker run -it --name meinubuntu -h meinubuntuhostname ubuntu

Gleichzeitiges Ausführen von Kommando in laufendem Container:

docker exec -it meinubuntu /usr/bin/top

Beispiel MariaDB

Das Image stellt mit dem MariaDB-Service einen Background Prozesse zur Verfügung! Anm./Erinnerung: Container ohne Prozess(e) wird gleich wieder beendet! (siehe: hello-world)

docker run -d --name mariadb-test1 -e MYSQL_ROOT_PASSWORD=geheim mariadb

Stoppen eines Containers:

docker stop mariadb-test1

Containerinfos auslesen:

docker inspect maria-db-test1

Beachten: MariaDB Datenbank Verzeichnis /var/lib/mysql liegt im Docker-Container!

docker inspect maria-db-test1 | less

und die Zeilen mit Mounts analysieren.

Die Datenbank (wenn diese läuft) mit MySQL/MariDB-Client checken:

docker exec -it mariadb-test1 mysql -u root -p

Den Container analysieren:

docker exec -it mariadb-test1 /bin/bash
# Aufrufe:
cat /etc/os-release
ps ax
mysqld --version
exit

Das Logging übernimmt Docker für den Hintergrund-Daemon Mysqld:

docker logs mariadb-test1

Jetzt erweitern wir das Beispiel mit eigenem Volume im Userdir Home:

mkdir /home/joeb/varlibmysql     # manuelles mkdir (ggf.) nicht nötig!
docker run -d --name mariadb-test2 \
    -e MYSQL_ROOT_PASSWORD=geheim \
    -v /home/joeb/varlibmysql/:/var/lib/mysql  mariadb

So jetzt haben wir einen neuen Container mariadb-test2 mit den DB-Dateien im Homedir eines Users.

Hinweis

Diese Umleitung für Volumes kann bei Nicht-Linuxen problematisch sein!

Jetzt noch ein Container - hier mit Portumleitungen:

docker run -d --name mariadb-test3 \
    -v /home/joeb/varlibmysql/:/var/lib/mysql \
    -p 13306:3306 mariadb

Und jetzt klappt der Zugriff auch direkt über den Docker-Host:

mysql -u root -p --port 13306 --protocol=tcp

Beispiel Networking

Mit Ports kann man also (in)direkt auf die Dockerdienste / Dockerprozesse zurgreifen. Besser ist es allerdings mit eigenen Dockernetzwerk die nötigen Container zu verbinden.

Anm.: bitte (immer) vorher alle beteiligten „MariaDB-Container“ stoppen.

Neues Netzwerk erstellen und und neuen MariaDB-Container mit PhpMyAdmin nutzen:

docker network create test-net
docker run -d --name mariadb-test4 \
    -v /home/joeb/varlibmysql/:/var/lib/mysql \
    --network test-net mariadb
docker run -d --name pma -p 8080:80 \
    -e PMA_HOST=mariadb-test4 \
    --network test-net phpmyadmin/phpmyadmin

Anm.: beim letzten Aufruf ist der volle Name für das PhpMyAdmin-Image zu beachten.

Siehe: PhpMyAdmin Image auf Docker Hub

Docker-Netzwerke erledigen selbstständig die Namensauflösungen! Aber: es werden die mit der Option -- name erstellten Bezeichner verwendet.

Beispiele WordPress

Vor der Bereitstellung von WordPress benötigen wir eine MySQL/MariaDB-Docker-Instanz und ein passendes Dockernetzwerk.

Infos zum Wordpress Image siehe: Wordpress Image auf Docker Hub

Auf dem Docker Hub Portal zu Wordpress finden sich auch die Erläuterungen für die speziellen WordPress Umgebungsvariablen (siehe Parameter -e).

Hier die vollständigen Konfigurationen…

Lokale Verzeichnisse für DB und WordPress-Website: (Anm.: ich habe gerne ein Hauptverzeichnis für die Docker-Dirs, die Unterverzeichnisse würde Docker heute auch selber anlegen!)

mkdir -p /home/joeb/docker/varlibmysql
mkdir /home/joeb/docker/wp-html

Test-Netzwerk:

docker network create test-net
docker network list

DB MariaDB bereitstellen: (bei Tests auf Name –name achten - Nummerierungen)

docker run -d --name mariadb-test5 \
    -e MYSQL_ROOT_PASSWORD=geheim --network test-net \
    -v /home/joeb/docker/varlibmysql/:/var/lib/mysql  mariadb

Und jetzt noch WordPress:

docker run -d --name wp-test1 --network test-net \
    -v /home/joeb/docker/wp-html:/var/www/html -p 8081:80 \
    -e WORDPRESS_DB_PASSWORD=geheim \
    -e WORDPRESS_DB_HOST=mariadb-test5 wordpress

Und natürlich lässt sich auch der PhpMyadmin Zugriff bereitstellen:

docker run -d --name pma -p 8080:80 \
    --network test-net -e PMA_HOST=mariadb-test5 phpmyadmin/phpmyadmin

Hinweis

Bitte immer auf die Ports achten!

Soweit ein kleiner Überblick mit praktischen Beispielen.

Administration 101

Die komplette Administration ergibt sich erst durch längere Praxis und Erfahrungen mit den mannigfachen Docker-Aufrufen und Tools.

Docker Techniküberblick bei Microsoft Dot.Net Learn Portal

Docker Techniküberblick bei Microsoft Dot.Net Learn Portal

Hier eine erste kleine Übersicht und Einstiege in verschiede Aspekte der Container.

Images, Container

Liste der heruntergeladenen bzw. selbst erstellten Images:

docker images
docker container

Container analysieren:

docker ps                # laufende Container (old)
docker container ls      # laufende Container (new)
docker ps -a             # alle Container
docker container ls -a
docker ps -a s           # alle Container mit Größenangaben

Beachten bei den Größenangaben: virtuell - mehrere Container können gleiche Images nutzen.

Gefahr

Die Löschkommandos gerne ohne Rückfragen! Wie bei Linux-Konsolen eben üblich!

Container löschen:

docker rm <id>          # (old)
docker container rm     # (new)
docker rm <name>

Die IDs der Container kann mit Parameter -q erhalten und so ergeben sich praktische Aufrufe zum Löschen von Containern:

docker ps -a -q
docker ps -a -q -f ancestor=hello-world              # alle Container von Image hello-world
docker rm $(docker ps -a -q -f ancestor=hello-world) # löschen
docker rm $(docker ps -aq)                           # alle Container löschen!!!

Images löschen:

docker rmi hello-world

Container Volumes

Die Volumes werden beim Löschen von Containern nicht mitgelöscht, was ja auch ganz im Sinne der technischen Nutzung ist (siehe Aktualisierung von Containern).

Verzeichnis für Volumes (bei Linux): /var/lib/docker/volumes

Zu beachten in aktuellen Beispielen entweder keine Volumens genutzt (siehe docker inspect) oder die Volumes anders gemountet!

…tbc…

Overlay-Dateisysteme

Die Struktur aus (von unten nach oben):

  • Read-only Schichten

    • bootfs mit Kernel und cgroups

    • Basis Image (z.B. Alpine)

    • Application Image (z.B. Webserver Apache oder Nginx)

    • weitere Application-Layers

  • Read-Write Container Schicht (quasi on top)

    Jetzt wird aus einem Image ein Container!

Copy-On-Write (COW)

Zugriff durch die Schichten und in oberster Schicht (rw-Container) Kopie anlegen, für Daten aus den unteren ro-Schichten.

Ermitteln des Storage-Overlay-Systems:

docker info | grep Storage

Durch die Schichten

Übersicht Overlay-Systeme:

  • vfs (nur für Testing/Debugging)

  • aufs (ältester Docker Storage Driver; Advanced Multi-layered Unification Filesystem)

    Anm.: nur noch selten vertreten; siehe: Knoppix

  • overlay2 (die modernisierte overlay Variante und Docker-Standard)

    Anm.: Kernel >= 4.0 nötig!

  • btrfs (siehe openSUSE/SLES)

    Achtung (siehe Suse Installationen): Literatur empfiehlt noch keinen produktiven Einsatz!

  • zfs

    performant, hoher RAM-Verbrauch, Lizenzfragen; hinterfragen: Ubuntu nutzt zfs

  • devicemapper

    in allen Distros verfügbar; muss mit direct-lvm eingebunden werden (nicht: loop-lvm)

Hier mal eine Grafik zur OverlayFS(2) Technik:

Overlay(2)FS

OverlayFS(2)-Modell (Bild: Liebel - Skalierbare Container-Infrastrukturen für Ihr Unternehmen)

Siehe hierzu auch Ordnerstrukturen: /var/lib/docker/overlay...

Netzwerke

Spater hierzu mehr - hier: 101

Netzwerke auflisten:

docker network ls             # auflisten
docker network inspect bridge # analysieren

… tbc …

Konfiguration Daemon

Verschiedene Möglichkeiten für die Docker Daemon Konfiguration:

  • Beim Starten über die Kommandozeile - siehe dockerd --help

  • Docker config: /etc/sysconfig/docker (z.B. DOCKER_OPTS="")

  • Systemweite config: /etc/docker/daemon.json

  • Benutzer config: ~/.docker/config.json

Tipp

Möglichst nicht mischen/kombinieren!

Dockerfile

Docker Referenz zu Dockerfile

Docker Referenz zu Dockerfile

Bis jetzt haben wir fertige Images (siehe hub.docker.com) genutzt und mit diesen Images die Container erstellt.

Die meisten Images waren auch ordentliche Vorlagen, aber z.B. in Ubuntu würde man vielleicht gerne das Paket iproute2 nachinstallieren, … usw.

Also wollen wir jetzt unsere eigenen Images erstellen und bedienen uns eines Dockerfile, das alle nötigen Anweisungen enthält!

Hinweis

Später: mit docker-compose werden mehrere Container kombiniert eingerichtet!

Kurzanleitung

  • Ordner für Image erstellen

  • ggf. Dateien im Ordner bereitstellen (z.B. Skripte, Webdateien/Ordner)

  • Datei Dockerfile im Ordner erzeugen und Inhalt/Konfiguration für Image festlegen

  • mit docker build ein neues Image lokal erzeugen

  • mit docker push (ggf.) im Docker-Hub veröffentlichen (wörtlich zu nehmen: public)

Alternative Veröffentlichungstechniken für eigene Images:

  • GitHub für Dockerfile bzw. Ordner/Dateien für automatisierte Builds

  • Private Image Repository auf Docker Hub ($)

  • Eigenes Docker Repository

Links:

Syntax Dockerfile

Schlüsselwörte für ein Dockerfile als Tabelle:

Schlüsselwort

Bedeutung

ADD

kopiert Dateien in das Dateisystem des Images

CMD

führt Kommando beim Start des Containers aus

COPY

kopiert Dateien aus Projekverzeichnis in das Image

ENTRYPOINT

führt Kommando beim Start des Containers aus

ENV

setzt eine Umgebungsvariable

EXPOSE

gibt die aktiven Ports an

FROM

gibt das Basis-Image an

LABEL

legt Zeichenkette fest

RUN

führt das Kommando aus

USER

Account für RUN, CMD und ENTRYPOINT

VOLUME

gibt Volume-Dirs an

WORKDIR

Arbeitsverzeichnis für RUN, CMD und ENTRYPOINT

Erläuterungen:

Kurze Analyse / Erläuterungen:

ADD v. COPY - scheinen ja dasselbe zu tun, aber ADD kann…

  • … auch mit URL umgehen

  • … auch (wie COPY) Verzeichnisinhalte komplett kopieren

  • … mit TAR-Archiven arbeiten/entpacken (gzip, bzip2, xz)

Beide können mit –chown=user:group Parameter umgehen.

In Kürze: COPY nur für einfaches Kopieren einer lokalen Datei.

CMD v. ENTRYPOINT - Startkommandos für Container

Wenn man Container mit mit docker run Komandos anfügt, dann …

  • … wird bei CMD das angefügte Kommando anstelle von CMD ausgeführt

  • … wird bei ENTRYPOINT das Kommando hinzugefügt

Image erstellen

Vorgehen für Beispiel 2 (s. folgendes Beispiel Einfacher Webserver)

mkdir -p /home/joeb/projektverzeichnis/samplesite
cd /home/joeb/Projekverzeichnis
touch samplesite/index.html samplesite/style.css   # HTML/CSS-Site nach usto
touch Dockerfile                                   # siehe Dockerfile eispiel
docker build -t joebrandes/testwebserver .         # Image erzeugen / taggen
docker run -d -p 80:80 -p 443:443 -h webtest \     # Container erzeugen
    --name testwebserver joebrandes/testwebserver

Die normale (und https-gesicherte) Seite sollte sich jetzt im Browser öffnen lassen!

Beispiele

Ein paar Beispiele aus Öggl/Kofler…

Beispiel 1

Beispielhaftes erstes Dockerfile:

Dockerfile nach Öggl/Kofler (S. 63)
1# Datei Dockerfile
2FROM ubuntu:18.04
3LABEL maintainer "kontakt@kofler.info"
4RUN apt -get update && \
5    apt-get install -y joe && \
6    apt-get clean && \
7    rm -rf /var/lib/apt/lists/*
8CMD ["/bin/bash"]

Im Seminar analysieren - Wert legen auf Zusammenfassung für RUN mit && Konstruktion!

Beispiel 2

Beispiel für einfachen Webserver:

Gefahr

Für aktuellere Docker und Ubuntu Kombi fehlerhafte Umsetzung!

Dockerfile für Webserver nach Öggl/Kofler (ALTE AUFLAGE!)
 1# Datei Dockerfile
 2FROM ubuntu:18.04
 3
 4LABEL maintainer "kontakt@kofler.info"
 5LABEL description "Test"
 6
 7# Apache installieren, und unnötige Dateien aus dem Paket - Cache
 8# gleich wieder entfernen
 9RUN apt-get update && \
10    apt-get install -y apache2 && \
11    apt-get -y clean && \
12    rm -rf /var/cache/apt /var/lib/apt/lists/*
13
14# HTTPS -Unterstützung aktivieren
15RUN a2ensite default-ssl && a2enmod ssl
16
17ENV APACHE_RUN_USER=www-data \
18    APACHE_RUN_GROUP=www-data \
19    APACHE_LOG_DIR=/var/log/apache2
20
21EXPOSE 80 443
22
23# gesamten Inhalt des Projektverzeichnisses
24# samplesite nach /var/www/html kopieren
25COPY samplesite/ /var/www/html
26
27CMD ["/usr/sbin/apache2ctl" , "-D" , "FOREGROUND"]

Aktualisiertes Beispiel:

Dockerfile für Webserver nach Öggl/Kofler (AKTUELLE Auflage!)
 1# Datei Dockerfile
 2FROM ubuntu:20.04
 3
 4LABEL maintainer "name@somehost.com"
 5LABEL description "Test"
 6
 7# Umgebungsvariablen und Zeitzone einstellen
 8# (erspart interaktive Rückfragen)
 9ENV TZ="Europe/Berlin" \
10    APACHE_RUN_USER=www-data \
11    APACHE_RUN_GROUP=www-data \
12    APACHE_LOG_DIR=/var/log/apache2
13
14# Apache installieren, unnötige Dateien aus dem Paket-Cache
15# gleich wieder entfernen, HTTPS aktivieren
16RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
17    echo $TZ > /etc/timezone && \
18    apt-get update && \
19    apt-get install -y apache2 && \
20    apt-get -y clean && \
21    rm -r /var/cache/apt /var/lib/apt/lists/* && \
22    a2ensite default-ssl && \
23    a2enmod ssl
24
25EXPOSE 80 443
26
27# gesamten Inhalt des Projektverzeichnisses
28# samplesite nach /var/www/html kopieren
29COPY samplesite/ /var/www/html
30
31CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Beispiel 3

Alpine Linux mit Apache2

Hier sind wir durch Recherchen zu Alpine Linux und diversen Dockerfile Analysen herausgefordert worden (Anm.: Apache als Prozess am Laufen halten im Container!)

Dockerfile für Alpine Linux mit Apache2
 1FROM alpine
 2
 3LABEL maintainer "dummy@aol.com"
 4LABEL description "Test Alpine und Apache"
 5
 6
 7RUN apk update && apk upgrade && \
 8    apk add apache2 libxml2-dev apache2-utils && \
 9    rm -rf /var/cache/apk/*
10
11# war zwischendurch nötig: 
12# RUN mkdir /run/apache2
13
14ENV APACHE_RUN_USER=apache \
15    APACHE_RUN_GROUP=www-data 
16
17EXPOSE 80 443
18
19COPY samplesite/ /var/www/localhost/htdocs
20
21CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

Beispiel 4

Als ausführlicheres Dockerfile-Beispiel liefern Öggl/Kofler für „Pandoc“:

Dockerfile pandoc Installationen nach Öggl/Kofler (S. 73ff.)
 1# Datei Dockerfile
 2FROM haskell
 3
 4# Pakete installieren
 5RUN apt-get update -y && \
 6    apt-get install -y -o Acquire::Retries=10 \
 7                     --no-install-recommends \
 8      texlive-latex-recommended \
 9      texlive-latex-extra \
10      texlive-fonts-recommended \
11      texlive-lang-german \
12      texlive-pstricks \
13      imagemagick \
14      unzip \
15      python3 \
16      ghostscript \
17      less && \
18    apt-get clean && \
19    rm -rf /var/lib/apt/lists/*
20
21# Pandoc installieren
22RUN cabal update && \
23    cabal install pandoc-2.1.1 && \
24    ln -s /root/.cabal/bin/pandoc /usr/bin/pandoc
25
26# Mitteleuropäische Zeitzone
27# (siehe https://serverfault.com/questions/683605)
28RUN cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime
29
30# Fonts für LaTeX installieren
31# ADD rheinwerkfonts.tgz /usr/local/share/texmf
32# RUN texhash
33
34# Volume /data, bei docker run mit dem Arbeitsverzeichnis
35# verbinden, also: docker run -v $(pwd):/data
36WORKDIR /data
37VOLUME  ["/data"]
38
39ENTRYPOINT ["/bin/bash"]

Die Kollegen richten also - wie ich mit SphinxDoc - eine Umgebung ein, in der sie mit Hilfe von Markdown und dem Werkzeug pandoc dann HTML als auch LaTeX-Versionen für Print/PDF generieren können.

Auch hier gibt es eine aktualisierte Variante:

Dockerfile pandoc Installationen nach Öggl/Kofler (AKTUELLE Version)
 1# Datei Dockerfile
 2FROM ubuntu:20.04
 3ENV TZ="Europe/Berlin"
 4RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
 5    echo $TZ > /etc/timezone && \
 6    apt-get update -y && \
 7    apt-get install -y -o Acquire::Retries=10 \
 8                     --no-install-recommends \
 9      texlive-latex-recommended \
10      texlive-latex-extra \
11      texlive-fonts-recommended \
12      texlive-lang-german \
13      texlive-pstricks \
14      texlive-fonts-extra \
15      imagemagick \
16      unzip \
17      python3 \
18      ghostscript \
19      locales \
20      joe \
21      vim \
22      curl \
23      wget \
24      ca-certificates \
25      less && \
26    apt-get clean && \
27    rm -rf /var/lib/apt/lists/*
28
29# Pandoc installieren
30RUN curl -L https://github.com/jgm/pandoc/releases/download/2.14/pandoc-2.14-1-amd64.deb \
31   -o /tmp/pandoc.deb && \
32   dpkg -i /tmp/pandoc.deb && \
33   rm /tmp/pandoc.deb
34
35# Fonts installieren
36# (die Font-Datei dürfen wir nicht weitergeben)
37# ADD myfonts.tgz /usr/local/share/texmf
38# RUN texhash
39
40# Volume /data, bei docker run mit dem Arbeitsverzeichnis
41# verbinden, also: docker run -v $(pwd):/data
42# Fedora, RHEL:    docker run -v $(pwd):/data:z
43VOLUME  ["/data"]
44
45# Startkommando
46ENTRYPOINT ["/bin/bash"]

Docker Kommandos

Auflistung von Docker Befehlen: Docker Befehle

Docker Kommandos auf docs.docker.com

Docker Kommandos auf docs.docker.com

Wir haben schon einigen Docker CLI Kommandos genutzt. Jetzt sollen komplettere Aufstellungen folgen.

Die Aufrufe sind nach Kategorien gegliedert. Die Aufrufe lassen sich teilweise in langer und kurzer Schreibung aufrufen:

docker container ps -a     # oder auch kürzer
docker ps -a

Das hat auch mit historischen Entwicklungen innerhalb der Docker-Versionen zu tun! Eine neue und saubere Kommanostruktur wurde mit Version 1.13 eingeführt.

Tipp

Paket docker-bash-completion in der Shell nutzen: also fleißig mit Tab-Tab vervollständigen!

Wir beginnen aber wie immer mit der eingebauten Hilfe…

docker Hilfe

Onlineportal für Docker CLI:

https://docs.docker.com/engine/reference/commandline/cli/

Tipp

Die Befehle (z.B. docker events) lassen sich einfach in URL an Stelle von cli ersetzen!

Und natürlich kann man auch jederzeit mal die interaktive Docker Hilfe nutzen.

docker help (teilweise Zeilen gekürzt)
Usage:	docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default "/home/joeb/.docker")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") ...info
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default ".../.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default ".../.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/home/joeb/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  builder     Manage builds
  config      Manage Docker configs
  container   Manage containers
  engine      Manage the docker engine
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

Mit der Hilfe kann man sich auch weiter in die Kommando-Hierarchien begeben:

docker container ps –help
Usage:	docker container ls [OPTIONS]

List containers

Aliases:
  ls, ps, list

Options:
  -a, --all             Show all containers (default shows just running)
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print containers using a Go template
  -n, --last int        Show n last created containers (includes all states) (default -1)
  -l, --latest          Show the latest created container (includes all states)
      --no-trunc        Don't truncate output
  -q, --quiet           Only display numeric IDs
  -s, --size            Display total file sizes

Und ja: es handelt sich bei der Textausgabe der Hilfe nicht um einen Fehler - es wurde docker container ps --help aufgerufen - man erkennt dann die Aliase.

Und zuletzt wurden auch klassische Man-Pages für die docker-Kommandos implementiert, die man einfach über mit „-“ (Bindestrich) zusammengesetzte Aufrufe erhält: man docker-start

docker Subkommandos

Allgemeine Docker Kommandos:

Kommandos

Funktionalität

docker container

Hauptbefehl: Container verwalten

docker events

laufend (!) Aktionen des Docker-Systems anzeigen

docker info

Status Docker-System

docker image

Hauptbefehl: Images verwalten

docker login/logout

am Docker-Account an-/abmelden

docker network

Hauptbefehl: Docker-Networking verwalten

docker node

Haupbefehl: Docker Swarm Knoten verwalten

docker search

Images (unter docker.io) suchen

docker secret

Hauptbefehl: Secrets für Services

docker service

Hauptbefehl: Services verwalten (siehe Cluster)

docker stack

Hauptbefehl: Stack (Gruppe von Services) verwalten

docker stats

laufend (!) CPU, MEM anzeigen lassen

docker swarm

Haupbefehl: Swarm einrichten / verwalten

docker system

Haupbefehl: Infos zu Docker System

docker version

Docker Version(en) anzeigen lassen

docker volume

Hauptbefehl: Volumes verwalten

Es folgen ein paar individuelle Anmerkungen zu einzelnen docker-Kommandos.

docker events

Eine laufende Konsole - also gerne wieder mit mehreren Terminalfenstern arbeiten (siehe Tilix).

# Alle Events in einem bestimmten Zeitraum:
docker events --since '2019-01-01' --until '2019-01-10'
# in den letzten 50 Minuten
docker events --since '50m'
# für ein bestimmtes Image (oder auch 'container=...')
docker events --since '40m' --filter 'image=alpine'
# Event types filtern:
docker events --since '2019-01-01' --filter 'container=alpinejoeb' --filter 'event=start'

Die Ausgaben können formatiert (Parameter --format) ausgegeben werden (auch JSON).

Anm.: Linux Kernel verteilen Privilegien (Capabilities)

Hier: Docker Prozess im Host finden und CapEff finden: cat /proc/PID/status | grep CapEff

Die Hex-Kodierung CapEff des Prozesse analyisieren: capsh --decode=<hexcode>

Tools capsh in Paket libcap-progs (Suse) oder libcap (CentOS).

docker info

Die Infos zum laufenden Docker-System.

Die Anzahl der laufenden Container anzeigen mit docker info | grep Running.

docker search

Einfache Suche: docker search ubuntu

Anzahl Images (hier: ubuntu): docker search ubuntu | grep "\/ubuntu\ " | wc -l

Filtern: docker search --filter=stars=7 --filter=is-official=true ubuntu

docker stats

Entspricht dem Linux-Klassiker top für die Shell.

docker system

Speichernutzung anzeigen lassen mit docker system df

Aufräumen / „Echt Alles ;-) Tabularasa“ mit `` docker system prune`` (--all --force)

docker network …

Hauptbefehl für Docker-Networking (siehe auch wieder docker network --help)

Kurze Befehlsliste: docker network ...

  • create (Netzwerk erstellen)

  • connect <nwid> <cname/cid>

  • inspect <nwname/nwid>

  • ls (Netzwerke auflisten)

  • prune (ungenutzte Netzwerke löschen; siehe docker-compose)

Online: Infoseite Docker Networking

docker image

Docker Kommandos für Images:

Kommandos

Funktionalität

docker image

Hauptbefehl: Images verwalten

docker build

neues Image mit Dockerfile

docker images

Images auflisten: docker image ls

docker history

Build-History eines Images

docker inspect

lokale Images analysieren

docker pull

Image herunterladen / aktualisieren

docker push

Image in Docker Repo hochladen

docker rmi

Image löschen

docker save / load

aus Images einen Tarball erzeugen

docker tag

Image-Namen bzw. -Tag anpassen

docker pull

Wenn nur ein Imagename angegeben wird, dann wird das Image mit Tag :latest gepullt!

Images mit Tag:latest müssen nicht immer die aktuellsten Images sein!

Kompletter Aufruf: docker pull [OPTIONS] REGISTRY:REG-PORT/IMAGE:TAG|@DIGEST

Optionen: -a | --all-tags um alle Images(:tags) mit einem Imagenamen zu pullen (gesamtes Image-Repository)

docker images oder auch docker image ls

Mit Option --no-trunc komplettere Ausgaben und -q für quiet, was einfach die (kurzen) IDs ausgibt!

Alle Images auflisten:

docker images -a

REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
mariadb                    <none>              2bdd97ca79d9        6 days ago          366MB
joebrandes/testwebserver   latest              9ff70d3871d4        7 days ago          183MB
<none>                     <none>              7c54877665f7        7 days ago          183MB
<none>                     <none>              6a247201e8a3        7 days ago          183MB
<none>                     <none>              aef9419d7b92        7 days ago          183MB
<none>                     <none>              c21c0c4fe351        7 days ago          183MB
<none>                     <none>              a3ff1c7635da        7 days ago          183MB
<none>                     <none>              2bd50cd1f5b1        7 days ago          86.7MB
<none>                     <none>              86e536f3da5c        7 days ago          86.7MB
hello-world                latest              fce289e99eb9        2 weeks ago         1.84kB
wordpress                  latest              9ec2fcdda9ef        2 weeks ago         420MB
mariadb                    latest              4f2e75647d2a        2 weeks ago         366MB
ubuntu                     18.10               d4452947e3fa        2 weeks ago         73.7MB
ubuntu                     18.04               1d9c17228a9e        2 weeks ago         86.7MB
alpine                     latest              3f53bb00af94        3 weeks ago         4.41MB

Die hier aufgelisteten none:none Images enstehen durch das Layersystem von Images und belegen und verschwenden keinen Platz im System!

Problematisch sind Image die mit none:none bei normalem docker images (ohne -a) auftauchen:

Dangling Images - verwaiste Einträge

Finden von Dangling Images: docker images -f "dangling=true"

Löschen / Aufräumen: per Filtern oder mit docker image prune

docker images -f "dangling=true" -q | xargs -n1 docker rmi -f
# oder einfach mit:
docker image prune

docker inspect oder auch docker image inspect

Formatierte Ausgaben mit Parameter --format

docker inspect --format='{{.Config.Cmd}}' alpine:latest
[/bin/sh]
# oder einfacher mit:
docker inspect alpine:latest | grep -i Cmd

Das lässt sich auch wieder aufbereiten (Tool jq):

docker image inspect alpine:latest | jq -CS                       # C Color; S sortiert
docker image inspect alpine:latest | jq -CS .[0].Config.Cmd       # Zugriff auf Array
[
"/bin/sh"
]

Die Ausgabe von Docker Kommandos ist auch über Go-Templates möglich: (Go Templates )

docker image inspect alpine:latest --format '{{.Config.Cmd}}'
[/bin/sh]
docker image inspect alpine:latest --format '{{json .Config.Env}}' | jq
[
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
]

Diese Ausgabeformate lassen sich auch bei anderen cmd-Techniken nutzen (siehe docker container ls ...).

docker save | load

Speichert Images in einem Tarball - nicht mit dem Export / Import von Containern verwechseln

docker save -o ~/alpine-out.tar alpine
tar -tvf alpine-out.tar

-rw-r--r-- 0/0            1511 2018-12-21 01:21 3f53bb00af943dfdf81...129d57d5991.json
drwxr-xr-x 0/0               0 2018-12-21 01:21 a21b1050952cdc06771...57cae64904b/
-rw-r--r-- 0/0               3 2018-12-21 01:21 a21b1050952cdc06771...57cae64904b/VERSION
-rw-r--r-- 0/0            1184 2018-12-21 01:21 a21b1050952cdc06771...57cae64904b/json
-rw-r--r-- 0/0         4672000 2018-12-21 01:21 a21b1050952cdc06771...57cae64904b/layer.tar
-rw-r--r-- 0/0             202 1970-01-01 01:00 manifest.json
-rw-r--r-- 0/0              89 1970-01-01 01:00 repositories

In layer.tar befindet sich das eigentliche Image mit den Ordnerstrukturen /, /bin, /usr, …

Diese Sicherung lässt sich dann auf einem anderen Rechner wieder loaden.

docker container

Docker Kommandos für Container:

Kommandos

Funktionalität

docker container

Hauptbefehl: Container verwalten

docker attach

I/O eines Containers mit Terminal connecten

docker commit

neues Image aus Container

docker cp

Kopieren von Daten zwischen Container <-> Host

docker create

Container erzeugen, aber nicht starten

docker diff

veränderte Dateien eines Containers erzeugen

docker exec

Kommando in laufendem Container ausführen

docker export

Container in Archiv speichern

docker import

Container aus Archiv erzeugen

docker inspect

Konfiguration und Status eines Containers

docker kill

Container sofort beenden

docker logs

Container-Loggings

docker pause/unpause

Container anhalten/fortsetzen

docker port

Container Ports auflisten

docker ps

Container auflisten

docker rename

Container umbenennen

docker restart

Container neu starten

docker rm

Container löschen

docker run

neuen Container erzeugen und starten

docker start

Container starten

docker stop

Container anhalten

docker top

Container Prozesse anzeigen

docker update

Container Optionen anpassen

docker wait

Container Ende erwarten

docker attach

Auf Container die man mit docker run -it oder docker start -a -i gestartet hat, kann man ja über die interaktive Konsole zugreifen.

Andernfalls kann man mit docker attach diese Funktionalität nachholen.

docker commit

Man sollte besser über Dockerfile und Builds arbeiten, weil sonst die Aufbauten der Images nicht mehr nachvollziehbar sind!

docker cp

Manuelle Kopieren von Daten zwischen Container und Host, was normaler Weise automatisch beim Erzeugen von Images genutzt wird.

echo "Testing" > /tmp/testdatei
docker start alpinejoeb
docker container cp /tmp/testdatei alpinejoeb:/
docker exec alpinejoeb cat /testdatei
docker stop alpinejoeb

docker diff

Abweichungen zwischen Container und ursprünglichem Image auflisten.

  • A (added - hinzugefügt)

  • C (changed - geändert)

  • D (deleted - gelöscht)

docker exec

Befehle in einem laufenden Contaier aufrufen. Der Container muss aktiv sein / laufen.

Wird eine Shell im exec benutzt und mit exit verlassen, dann läuft der Container weiter!

docker export

Beim Exportieren eines Containers werden alle Layer zusammengefasst! Man spricht vom flatten für Image Layer. Das ist beim docker save | load für Images gänzlich anders.

Anm.: Daten in Volumes werden nicht berücksichtigt!

docker images

Bitte auf Plural achten! Tipp: docker images -q listet nur die IDs auf und kann somit gut zum Pipeling für andere Docker-Aufrufe genutzt werden!

docker inspect

Arbeitet mit Images und Containern und erzeugt Infos im JSON-Format.

JSON anzeigen:

docker inspect -s mariadb-test5
...
...
    {
        "Id": "cd42b1a7c4542f76174f936e5a2060f1f87e3511d3fe5e07bb27e15a1ca74ea5",
        "Created": "2019-01-06T19:56:47.958915783Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "mysqld"
        ],
        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 0,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-01-06T19:56:48.881461371Z",
            "FinishedAt": "2019-01-06T20:15:04.192413984Z"
        },
...
...

Analyse über Parameter -f (format)

docker inspect -s -f "{{.State.Status}}" mariadb-test5
docker inspect -s -f "{{.State.FinishedAt}}" mariadb-test5

docker ps (kurz für: docker container ps)

Filterung mit Kriterium: -f <Kriterium=Wert>

Filterungs-Schalter aus Hilfen zu den Tools docker-ps bzw. docker-container-ls|ps

Filter output based on these conditions:
- ancestor=(<image-name>[:tag]|<image-id>| image@digest )
  containers created from an image or a descendant.
- before=(<container-name>|<container-id>)
- expose=(<port>[/<proto>]|<startport-endport>/[<proto>])
- exited=<int> an exit code of <int>
- health=(starting|healthy|unhealthy|none)
- id=<ID> a container's ID
- isolation=(default|process|hyperv) (Windows daemon only)
- is-task=(true|false)
- label=<key> or label=<key>=<value>
- name=<string> a container's name
- network=(<network-id>|<network-name>)
- publish=(<port>[/<proto>]|<startport-endport>/[<proto>])
- since=(<container-name>|<container-id>)
- status=(created|restarting|removing|running|paused|exited)
- volume=(<volume name>|<mount point destination>)

Formatierte / tabellarische Ausgaben mit Schalter --format:

docker container ls -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Labels}}"
docker container ls -a --format '{{printf "%-30s%-30s" .Names .RunningFor}}'
# auch hier wieder JSON Formatierung möglich:
docker container ls -a --format '{{json . }}' | jq

Formatierungs-Schalter (siehe Go-Templates) gerne wieder per Hilfen zu den Tools docker-ps bzw. docker-container-ls|ps

Valid placeholders for the Go template are listed below:
- .ID           - Container ID.
- .Image        - Image ID.
- .Command      - Quoted command.
- .CreatedAt    - Time when the container was created.
- .RunningFor   - Elapsed time since the container was started.
- .Ports        - Exposed ports.
- .Status       - Container status.
- .Size         - Container disk size.
- .Names        - Container names.
- .Labels       - All labels assigned to the container.
- .Label        - Value of a specific label for this container.
                  For example '{{.Label "com.docker.swarm.cpu"}}'.
- .Mounts       - Names of the volumes mounted in this container.
- .Networks     - Names of the networks attached to this container.

Exit Status aus Aufruf docker container ps -a

Die Nummern in Angabe Exited (#) von Spalte STATUS beziehen sich auf Exit-Meldungen beim Verlassen, stoppen oder killen eines Containers.

Eigene Docker Exit Return Code:

  • 125 Docker Daemon hat Fehler

  • 126 Container Kommando kann nicht aufgerufen werden

  • 127 Container Kommando konnte nicht gefunden werden

Ansonsten orientiert sich das Exit-Coding an

docker run

Erzeugt und startet einen neuen Container. Dabei wird, falls noch kein Image lokal vorhanden das entsprechende Image erst gepullt - also lokal bereitgestellt!

Bei Image-Namen ohne Tag wird versucht das image:latest genommen!

Siehe auch Extensives Manual für Kondsolentool docker-run!

Optionen

Funktionalität

–cpus=“1.25“

maximal 1,25 CPU Cores

-d

Container im Hintergrund (detached)

-e VAR=value

Variable für Container setzen

-h

Hostname

-i

interaktiv ausführen lassen

-m 512m

Container-RAM auf 512 MiB limitieren

–name cname

Containername

–network nwname

Netzwerk verwenden

-p localport:containerport

Portweiterleitungen zwischen Host und Container

-P

alle Port des Containers mit zufälligen Host-Ports

–rm

Container nach Ausführung löschen

-t

Pseudo-Terminal mit Standardausgabe verbinden

-v containerdir

Containerverzeichnis als Volume

-v vname:cdir

Volume mit Namen erzeugen

-v /localdir:cdir

Host-Dir mit Container-Dir verbinden

–volumes-from cname

Volume eines anderen Containers nutzen

Bemerkung

Enthalten Images keine aktiven Prozesse werden Container-Instanzen nicht am Leben gehalten!

Solche Prozesse (z.B. /bin/bash) müssen natürlich im Image vorhanden sein und direkt und sofort für den Container genutzt werden: also -it und nicht -d!

docker start | stop

Mit Parameter -ai (attach) direkt in eine Shell eines Containers starten: docker start -ai containername

Tipp

Die Container-Instanz wird mit exit beendet! Mit Strg+P Strg+Q läuft Container weiter!

Alle vorhandenen Container stoppen: docker stop $(docker ps -a -q)

Alle gestoppten Container entfernen: docker rm $(docker ps --filter "status=exited")

Oder mit neuem prune (dt.: stutzen, beschneiden) Schalter: docker container prune

docker top

Angelehnt an das top Kommando - hier aber als Einzelausgabe.

Aber der Reihe nach… wir starten erst einmal einen Container: docker start alpine (oder natürlich docker run ...).

CONTAINER ID   IMAGE    COMMAND    CREATED        STATUS        PORTS    NAMES
ba4471eeb783   alpine   "/bin/sh"  10 days ago    Up 17 minutes          alpinejoeb

Analyse auf Docker-Host mit ps axf ergibt (Anm. gekürzt und Umbrüche erzeugt):

1705 ?        Ssl    0:00  \_ docker-containerd
--config /var/run/docker/containerd/containerd.toml
--log-level info

3602 ?        Sl     0:00      \_ docker-containerd-shim -namespace moby
-workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/ba4471eeb783b...

3619 pts/0    Ss+    0:00          \_ /bin/sh

Man erkennt die PIDs für Container und Shell.

Jetzt mal die Prozesse im Container klassisch: docker container exec alpinejoeb ps ax

PID   USER     TIME  COMMAND
  1   root     0:00  /bin/sh
 11   root     0:00  ps ax

Und mit dem docker container top alpinejoeb -x Kommando: (Anm.: -x verkürzte Ausgabe)

PID                 TTY                 STAT                TIME                COMMAND
3619                pts/0               Ss+                 0:00                /bin/sh

Hinweis

Also völlig unterschiedliche Prozess-IDs aus verschiedenen Ansichten! Der erste Prozess im Container hat immer die Container-PID 1.

Prozesse lassen sich jederzeit von außen stoppen (killen).

Test:

# Endlosschleife im Container exec-uten:
docker container exec -d alpinejoeb /bin/sh \
  -c "while true; do echo palimpalim; sleep 1; done"

# Prozess für Schleife im Container ermitteln
docker container exec alpinejoeb ps ax (hier: Schleife mit PID 16)
# Prozess mit Container-PID 16 stoppen
docker container exec kill 16

docker-compose

Jetzt wollen wir die Bereitstellungen von Containern verbessern.

Docker Compose Overview auf docs.docker.com

Docker Compose Overview auf docs.docker.com

Mit docker run geht das zwar relativ einfach, aber wir wollen die Anweisungen zentral organisieren.

YAML

Die Konfiguration wird in der Textdatei docker-compose.yml bereitgestellt. Es handelt sich also um ein YAML gestylte Konfigurationsdatei.

Infoseiten zu YAML:

Für die Konformität der *.yml-Dateien kann wieder ein ordentlicher Editor (siehe VS Code) mit entsprechender Unterstützung sorgen.

Hinweis

Die Einrückungen (mit Leerzeichen) müssen genau passen - sie bestimmen die Gliederungen!

Kurzanleitung:

  • Abschnitt mit —

  • Kommentar mit #

  • Liste mit Bindestrich - oder in [eins, zwei, drei]

  • Hash mit key: wert oder {name: Joe, nachname: Brandes}

  • Textblock (mit Zeilenumbrüche) mit |

  • Textblock (ohne Zeilenumbrüche) mit >

Beispiel:

Beispiel YAML
# Datei sample.yaml
data:
  list:
    - item1
    - item2
  key1: >
    Dieser Text ist dem
    Schlüssel 'data.key1' zugeordnet.
  key2: |
    code line 1
    code line 2

YAML-Tool: shyaml (ein Python-Script)

openSUSE: sudo pip install shyaml

Beispielaufruf: shyaml get-value data.key1 < sample.yaml

compose - Technik

Technischer Hintergrund…

In aktueller Docker-Technik kann man die docker-compose Techniken auch mit docker stack deploy Techniken - also: Swarm Services - ausführen und arbeitet quasi mit einem Minimal-Swarm von einer Docker-Instanz!

Hinweis

Das docker-compose Python-Skript kann Problemchen bereiten (Python!)

Wir beschränken uns - an dieser Stelle - auf docker-compose und behalten uns die Swarm-Techniken für später auf.

Webportal zu docker-compose: Docker Compose

Releases / Downloads GitHub: docker-compose Releases

Einfacher Download bzw. Installation:

curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m`
        -o /usr/bin/docker-compose
chmod +x /usr/bin/docker-compose        # Originalanleitung mit /usr/local/bin - siehe $PATH

docker-compose.yml

Was für die Docker Standardtechniken (docker run) das Dockerfile darstellt ist nun die Konfigurationsdatei docker-compose.yml für unser Tool docker-compose!

docker-compose.yml (Wordpress-Installation)
# Datei test/docker-compose.yml
version: '3.7'

services:
  db:
    image: mariadb:latest
    volumes:
      - /var/dc-test-db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: geheim
    restart: always

  wordpress:
    image: wordpress:latest
    volumes:
      - /var/dc-test-www:/var/www/html
    ports:
      - "8082:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD: geheim
    restart: always

Dieses Hello WordPress!-Beispiel zu docker-compose zeigt die zusätzliche „Intelligenz“ des docker-compose-Tools gegenüber den Basistools Docker.

cd test                    # hier ist das docker-compose.yml
mkdir /var/dc-test-www     # Volume Wordpress HTML; kann man weglassen (!)
mkdir /var/dc-test-db      # Volume MariaDB Databases; kann man weglassen (!)
docker-compose up -d

Test hier einfach wieder mit Browser (URL): localhost:8082

Danach kann man alles beenden und löschen:

docker-compose down                        # es bleiben nur die Volumes!
rm -Rf /var/dc-test-db /var/dc-test-www    # Volumes müssen manuell gelöscht werden

Netzwerke für docker-compose.yml

services:
  web:
    ...
    networks:
      - mynet

# auf Top-Level die Netzwerke definieren
networks:
  mynet:
    external:
      name: host

Bei der letzten Konfiguration ist das Docker-eigene Host-Netzwerk gemeint (siehe docker network ls).

Netzwerkports

ports:
  - "8080:80"
  - "8443:443"

Auf die Hierarchie-Ebene für Definitionen achten.

Volumes

# Docker docker-compose.yml in Ordner testing
version: '3.7'
services:
  nginx:
    volumes:
      - webdata:/var/www/html
    ...
volumes:
  webdata:

Docker erstellt selbst ein Volume: /var/lib/docker/volumes/testing_webdata/_data

Mit einem weiteren docker-compose Beispiel (Joomla-Installation) können wir die Nutzung von Docker Volumes sehen:

Beispiel mit CMS Joomla und Volume webdata:

docker-compose.yml (Joomla-Installation) mit Volume
# Datei: joomla/docker-compose.yml
version: '3.1'
services:
  joomla:
    image: joomla:apache-php7
    ports:
      - 8080:80
    volumes:
      - webdata:/var/www/html
    environment:
      JOOMLA_DB_HOST: mariadb
      JOOMLA_DB_NAME: dockerbuch
      JOOMLA_DB_USER: dockerbuch
      JOOMLA_DB_PASSWORD: johroo2zaeQu
  mariadb:
    image: mariadb:10
    environment:
      MYSQL_ROOT_PASSWORD: eengi7suXeut
      MYSQL_DATABASE: dockerbuch
      MYSQL_USER: dockerbuch
      MYSQL_PASSWORD: johroo2zaeQu
volumes:
  webdata:

Testen der Persistierten Speicherung von Webdaten und Diskussion die Volumes in eigene Datenstrukturen zu binden.

docker-compose <commands>

  • config (Analyse)

  • up | down (up normalerweise kombiniert mit -d)

  • events

  • kill (falls stop|down nicht funzt)

  • logs

  • pause | unpause

  • ps

Volumes

Volumes lassen sich unter Docker als Mounts technisch nutzen und können unterschiedlich erstellt/gebunden sein.

  • Bind Mounts (z.B. durch -v /var/dc-test-www:/var/www/html)

  • Docker Volumes (mit docker volume create .. manuell erzeugen oder s.o. als Direktiven in docker-compose.yml oder Dockerfile)

Nur echte Volumes lassen sich mit docker volume ls auflisten.

Die Volumes lassen sich genauer mit docker volume inspect ... analysieren.

Mini-Swarm

An dieser Stelle nur zum reinschnuppern

Hinweis

Ich habe mich entschieden dieses Kurzkapitel zu Docker Swarm hier zu belassen, obwohl man diese Orchestrierung aktuell (2023) so gut wie nicht mehr einsetzt. Nicht ohne Grund unterstützen auch die Docker Entwicklungen die Kubernetes Orchestrierungen.

Mit docker stack deploy einen Cluster mit nur einem Docker-Mitglied nutzen.

Gefahr

Bei vorherigen Übungen mit docker-compose (s.o.) inkl. Volumes bitte vorher aufräumen/löschen!

Docker-Schwarm initieren: docker swarm init

docker swarm init                                      # Docker Swarm initieren
cd test                                                # hier ist das docker-compose.yml
mkdir /var/dc-test-www                                 # Volume Wordpress HTML
mkdir /var/dc-test-db                                  # Volume MariaDB Databases
docker stack deploy -c docker-compose.yml stacktest    # und los geht es...

docker stack rm stacktest                              # alles (bis auf Volumes) löschen!

Das Beispiel zeigt ganz schön die zusätzliche Abstraktionsebene beim Testen der Docker-Technik.

Testen der WordPress-Installation im Browser (URL): 172.20.0.2:8082

Also: die Portumsetzung quasi eine Netzwerk-Ebene weiter (siehe GW-Netzwerk)! Die richtige IP (hier im Beispiel: 172.20.0.2) analysieren Sie über docker network Analyse (oder einfach mit ip a s auf Docker Host: siehe GW-Bridge).

Der Docker läuft weiterhin im Swarm-Modus!

Beenden mit: docker swarm leave --force

Für Docker Swarm dann auch weitere Deploy-Einstellungen (später mehr bei Swarm):

  • deploy.mode

  • deploy.placement.constraint ; Regeln: node.id, node.hostname, node.role

Wenn später mehrere Node (Docker Host Swarm Mitglieder) gejoint werden (docker swarm join ...) müssen weitere Vorbereitungen und Konfigurationen beachtet werden: insbesondere die Nutzung von Zeitservice NTP, damit die Nodes genau gleich „ticken“.

Basis-Images

Für die meisten Docker-Umsetzungen werden erst einmal vorbereitete Images genutzt.

Docker official Images

Docker official Images

Docker Hub

Alle bisher benutzten Images in allen Beispielen basieren auf Grund-Images.

Diese Basis-Images werden per Docker Registry in Form von Repositories bereitgehalten. Später wollen wir uns von der Docker Registry trennen und werden unsere eigenen Registrys betreiben wollen.

Die Suche nach vertrauensvollen Basis Images: Docker Registry

Offizielle Docker Basis-Images

Offizielle Docker Basis-Images

Mit der Registrierung auf dem Docker-Hub haben Sie Einblick in die automatisierten Sicherheitsüberprüfungen für die verschiedenen Images in einem Repository (Reiter Tags).

Docker Account - Tags

Docker Account - Tags - Sicherheitslücken

Oder natürlich mit der Docker CLI: Docker CLI Search

Beispielaufrufe:

docker search ubuntu                                # Images ubuntu suchen
docker search --filter "is-official=true" ubuntu    # offizielle Images Ubuntu
docker search --filter stars=10 debian              # min. 10 Sterne

Official Images (Docker)

Hier ein paar der offiziellen Images (Anzahl gesamt: 16; Stand: Jan 2019)

Hinweis

Den Terminus Official Images will Docker reserviert wissen!

Die offiziellen Images haben einen einfachen Namen: also alpine und nicht testcom/alpine!

  • Scratch

    für das Imagen „FROM scratch“

  • Alpine

    Ein Imaga-Build from scratch mit kleinem Linux-rootfs-TAR - der aktuelle Docker Builds Liebling!

    Werden wir noch häufiger nutzen und bedarf einer weiteren Vertiefung, da es andere Administrationsmechanismen (z.B. Paketverwaltung) nutzt, als die Standard-Linux-OS.

  • CentOS

    Image des RED HAT Community OS

  • Debian

    Image Debian

  • Fedora

    Image des RED HAT Fedora OS

  • Ubuntu

    Image von Canonicals Ubuntu

  • Busybox

    The Swiss Army Knife of Embedded Linux

  • Bash

    … nur die Bash

  • Amazon Linux

    Amazon Linux is provided by Amazon Web Services (AWS)

Beachten: der Unterstrich in den Links für die offiziellen Images.

Hier mal eine kleine Übersicht über die gängigen Image-Größen:

Distribution

Docker Image Größe

Alpine Linux

ca. 4 MByte

CentOS 7

ca. 210 MByte

Debian 9 (Stretch)

ca. 100 MByte

Ubuntu 16.04 LTS

ca. 110 MByte

Ubuntu 18.04 LTS

ca. 80 MByte

Image Tags

Über Repositories in der Docker Registry können unterschiedliche Images bereitgestellt werden, die man über ihre Tags genauer bestimmt.

Beispielhaft Übersicht (online - Images Centos): https://hub.docker.com/_/centos?tab=tags

Anm.: auf dieser Übersicht sehen angemeldet Docker Hub User auch immer die Sicherheitsanalysieren zu den Images!

Das lässt sich auch in der Kommandozeile zaubern: (Anm.: Tool jq genutzt für lesbare Darstellung)

curl -sL https://index.docker.io/v1/repositories/library/centos/tags | jq '.[].name'

"latest"
"5"
"5.11"
"6"
"6.10"
"6.6"
"6.7"
"6.8"
"6.9"
"7"
"7.0.1406"
"7.1.1503"
"7.2.1511"
"7.3.1611"
"7.4.1708"
"7.5.1804"
"7.6.1810"
...

Für eigene Images gerne ein eigenes Präfix für die Images nutzen: joebrandes/alpine:15.0

Eigenes Basisimage

(s.a. Vertrauenswürdige Images)

Wichtig: jedes lokale erstellte Image kann immer nur über eine Registry genutzt werden!

Tarball

Wir erstellen/installieren ein Template-System (hier: openSUSE) und erstellen hieraus einen Tarball.

tar --numeric-owner --exclude=/proc --exclude=/sys --exclude=/.snapshots -cvf opensuse.tar /

Dieses lässt sich dann auf dem Docker-Host wieder Importieren.

docker import opensuse.tar joebrandes/opensuse:42.3

Image-Erzeugung per Skript

Beispiel: YUM-Based mit Skript online

Oder über Moby-Project:

wget https://raw.githubusercontent.com/moby/moby/master/contrib/mkimage-yum.sh
bash mkimage-yum.sh joebrandes/centos

Debian / Ubuntu

Diese Systeme gehen mit einem eigenen Tool zum Extrahieren eines Tarball aus einem System an den Start: debootstrap

Das Tool kann über das gleichnamige Paket installiert werden.

debootstrap --variant=minbase stretch ./rootfs

tar -C ./rootfs -c . | docker import - joebrandes/debian:9

Anm.: nach Test ca. 165 MB groß!

Alpine Linux

Für das Linux zeichnet die Firma Gliderlabs verantwortlich.

Alpine Linux Website

Alpine Linux Website

Die Website sagt es ja ganz richtig: Small. Simple. Secure. Allerdings wird verschwiegen, dass man sich damit auch gerne den meist gewöhnten Komfort bei der Nutzung der Standard-Distros schenken kann!

Quellen zur weiteren Vertiefung mit Alpine Linux:

Alpine Technik

So klein und schön Alpine Linux auch ist - es verhält und nutzt sich allerding auch anders als seine anderen Linux-Alternativen.

  • als C-Standardbibliothek wird musl statt glibc genutzt

    das stellt häufig ein Problem bei zu kompilierenden Programmen dar

    einfachere Auswertung von /etc/resolv.conf (keine domain und search Beachtung)

    es existiert für Alpine Linux optimierte glibc (pkg-glibc )

  • als Init-System wird OpenRC statt systemd oder sysv-init genutzt

    erinnert eher als klassisches init-System und arbeitet mit /etc/inittab

    Wichtig: OpenRC ist installiert! Arbeitet aber nicht! S.a. Logging (rsyslog nachinst.)

  • Linux Kommandos stammen von BusyBox

Alpine Linux lässt sich schnell ausprobieren:

docker run -it -h alpine --name alpine alpine

Eine mögliche Ausgabe in der Konsole:

docker run alpine
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
cd784148e348: Pull complete
Digest: sha256:46e71df1e5191ab8b8034c5189e325258ec44ea739bba1e5645cff83c9048ff1
Status: Downloaded newer image for alpine:latest
/ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.8.2
PRETTY_NAME="Alpine Linux v3.8"
HOME_URL="http://alpinelinux.org"
BUG_REPORT_URL="http://bugs.alpinelinux.org"
/ #

Container-Analyse (in separater Shell natürlich): docker ps -s (Größen anzeigen)

zeigt einen nur wenige Bytes großen Container, was normal ist für frisch erstellte Container.

Alpine Shell - BusyBox

Die Alpine Shell ist standarmäßig /bin/sh (Teil von BusyBox)

Die Bash lässt sich nachinstallieren, was den Komfort erhöht, aber auch die Speichergrößen anschwellen lässt.

apk add --update bash bash-completion

Enthält ca. 140 Linux Standardkommandos, die als Symlinks zu busybox integriert sind.

Siehe: ls /bin /sbin -l

Hilfe zu BusyBox: https://busybox.net/downloads/BusyBox.html

Alpine Hilfe / Doku

Es gibt keine man-Pages oder den Pager less!

Nachinstallation möglich mit:

apk add --update man man-pages mdocml-apropos less less-doc
export PAGER=less
apk add --update bash-doc

Die man-Pages der Tools habe immer die -doc Paketendung!

Hilfe zu diesen Topics: Alpine Doku

Paketverwaltung apk

Das Verwalten von Paketen (Software) mit apk unter Alpine Linux in Kürze:

Kommando

Funktion

apk add <paketname>

installiert Pakete

apk del <paketname>

entfernt Paket

apk info (<paketname>)

listet installierte Pakete auf (auch mit -L und --who-owns)

apk search <paketname>

sucht Paket in Paketquellen

apk stats

zeigt Anzahl Pakete

apk update

zeigt, welche Pakete aktualisierbar sind

apk upgrade

aktualisiert Pakete

Paket auflisten lassen in Roh-Alpine: apk info | sort

apk info
/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
v3.8.2-19-g151c2021d6 [http://dl-cdn.alpinelinux.org/alpine/v3.8/main]
v3.8.2-18-gd7f33f856a [http://dl-cdn.alpinelinux.org/alpine/v3.8/community]
OK: 9546 distinct packages available
/ # apk info | sort
alpine-baselayout
alpine-keys
apk-tools
busybox
libc-utils
libressl2.7-libcrypto
libressl2.7-libssl
libressl2.7-libtls
musl
musl-utils
scanelf
ssl_client
zlib
/ #

Empfehlung/Übung: ein apk update vor irgendwelchen Installationen / Konfigurationen! Es gibt gut 9500 Pakete!

Tipp

In Dockerfile ein apk add --no-cache zum installieren nutzen: es wird ein –update durchgeführt, aber nach dem Install wird das System wieder bereinigt!

Hier ein beispielhafter Aufruf:

apk add –no-cache nutzen
# Datei Dockerfile
...
RUN apk add --no-cache \
    build-base \
    python-dev \
    jpeg-dev \
    zlib-dev \
    ffmpeg \
    && pip install sigal \
    && pip install cssmin \
    && apk del build-base python-dev jpeg-dev zlib-dev

Paketübersicht online: https://pkgs.alpinelinux.org/packages

Online sind auch die Paketquellen erkennbar. Anzeige der Paketquellen mit:

cat /etc/apk/repositories

Docker Registries

Wir wollen unsere eigene Docker Registry betreiben. Hierfür stehen verschiedene technischen Umsetzungen zur Verfügung.

Distribution - Registry als Official Image auf Docker Hub

Distribution - Registry als Official Image auf Docker Hub

Die Registry steht in den Versionen V1 und V2 zur Verfügung. Vor den Bereitstellungen sollte man die entsprechenden Versionen recherchieren (siehe CentOS / RHEL oft noch in den alten Distros mit V1).

Registry Techniken:

  • V1 - in Python implementiert

  • V2 - in Golang (EMPFEHLUNG)

Desweiteren starten wir erst einmal mit einer Insecure Registry - also ohne verschlüsselte Transporte.

Registry bereitstellen

übersicht über die Bereitstellungen für Docker Registry:

  • Registry Software auf Github https://github.com/docker/distribution

    Anm.: wird in Seminaren nicht genutzt!

  • Registry als Docker Image vom Docker Hub https://hub.docker.com/_/registry

  • Software in Linux-Distributionen - und wieder: bitte die Version der Registry vorher klären

  • Docker Hub Account

    Anm.: der Account hat auch Vorteile beim Einschätzen von Docker Hub Images!

Erinnerung: die Docker Technik hält Konfiguration vor, wo sie standardmäßig die Registry erwartet:

docker system info | grep -i registry
Registry: https://index.docker.io/v1/

Das lassen wir auch erst einmal so. Auch um die verschlüsselte Kommunikation mit unseren Registries oder die Nutzung von Registry-Mirrors werden wir uns (ggf.) erst später kümmern.

Registry Image

Die Umsetzung möglichst auf Debian-System. Anm./Alternative: eigenes Docker-Registry-Tool dann z.B. mit Suse-System.

Ein offizielles Registry-Image lässt sich auf dem Docker Hub finden und mit docker-compose nachhaltig implementieren.

Für eine Ansprache der eigenen Docker Registry nutzen wir z.B. hub.example.org oder andere FQDNs nach Wahl.

Diese Adresse müssen wir natürlich auflösen lassen - am einfachsten über die /etc/hosts.

Tipp

Bei der Nutzung Hyper-V Default Switch erhält man FQDNs und Namensauflösungen: hostname.mshome.net.

Aber: keine echtes DNS und Routing!

Jetzt benötigen wir nur noch ein Docker Compose Verzeichnis für die docker-compose.yml und schon kann es losgehen.

Docker Compose Ordner anlegen

mkdir ~/docker/registry && cd $_

und in Ordner wechseln.

docker-compose.yml (Registry)
registry:
  image: registry:2
  container_name: registry
  restart: always
  ports:
    - 5000:5000
  volumes:
    - /srv/docker/registry:/var/lib/registry

Und los geht es: docker-compose up -d

Damit jetzt auch der unsichere Zugriff auf die Registry möglich ist, muss Docker über /etc/docker/daemon.json entsprechend konfiguriert werden:

{
    [ggf. Vorherige Einträge - diese Zeile weglassen;-)],
    "insecure-registries": [ "hub.example.org:5000" ]
}

Testen der eigenen Registry:

docker pull ubuntu:16.04
docker tag ubuntu:16.04 hub.example.org:5000/ubuntu:16.04
# und jetzt pushen:
docker push hub.example.org:5000/ubuntu:16.04
# löschen der Images:
docker image rm ubuntu:16.04
docker image rm hub.example.org:5000/ubuntu:16.04
# und jetzt das Image aus eigener Registry holen:
docker pull hub.example.org:5000/ubuntu:16.04

Die genutzte Registry (quasi der Weg für das Image) erschließt sich also aus dem Image-Namen!

Hinweis

Ändern Sie den Namen der Registry muss man Anpassungen an Dockerfiles und docker-compose.yml-Dateien vornehmen!

Analyse des Registry-Containers:

docker exec registry ps aux
docker exec registry cat /etc/docker/registry/config.yml

Mit dieser config.yml kann die Registry Konfiguration dann auch angepasst/überschrieben werden.

Links zur Docker Registry:

Registry Distro-Package

Die Umsetzung erfolgt auf einem openSUSE-System mit dem Paket docker-distribution-registry.

Es muss mit systemctl entsprechend gecheckt (systemctl status registry) und gestartet (systemctl start registry) werden.

Auch hier muss wieder eine Konfiguration für insecure-registries nach obigem Beispiel für die Standard-Registry vorgenommen werden.

Also über /etc/docker/daemon.json entsprechend konfiguriert:

{
    [ggf. Vorherige Einträge - diese Zeile weglassen;-)],
    "insecure-registries": [ "opensuse.mshome.net:5000" ]
}

Repositories einer Registry anzeigen lassen:

curl http://opensuse.mshome.net:5000/v2/_catalog

Hinweis

Tests erst einmal nur mit den jeweils lokalen Maschinen, sonst benötigt man ja vollständiges DNS und Routing!

Das Löschen von Images in privaten Registries ist extrem unhandlich und umständlich (Literatr: Liebel, Kap. 6.4.4, S. 418ff).

Registry Docker Hub

Empfehlung: eigenen Account auf https://hub.docker.com/signup erzeugen für Repositories.

Docker Befehle: docker login | logout

Authentifizierung hinterlegt (!) in /etc/docker/key.json

Docker Hub

Docker Hub - Webportal

Anm.: und ich kann nicht garantieren, dass diese tollen images das heute noch liegen ;-) !

Literatur

Die folgenden Docker Bücher liefern die Schwerpunkte zu unserer Seminarpraxis und den Übungen.

Literatur (Unsplash: susan-q-yin-2JIvboGLeho-unsplash.jpg)

Literatur (Unsplash: susan-q-yin-2JIvboGLeho-unsplash.jpg)

Und natürlich liefert auch die Linksammlung viele Quellen für weitere Beschäftigungen.

Hinweis

Texte und Anmerkungen zu den Büchern von Amazon bzw. Verlagen

Docker - Praxisbuch

Autoren: Bernd Öggl und Michael Kofler

Docker: Das Praxisbuch für Entwickler und DevOps-Teams.

Docker: Das Praxisbuch für Entwickler und DevOps-Teams.
Gebundene Ausgabe: 431 Seiten
Verlag: Rheinwerk Computing; Auflage: 1 (24. August 2018)
Sprache: Deutsch
ISBN-10: 3836261766
ISBN-13: 978-3836261760
Größe und/oder Gewicht: 17,2 x 3 x 24,6 cm

Software-Container verstehen und produktiv einsetzen

Docker ist aus der modernen Softwareentwicklung nicht mehr wegzudenken. Ob Sie Entwickler oder Administrator sind, ob Sie gerade einsteigen oder bereits produktiv mit Software-Containern arbeiten: Dieses Buch zeigt Ihnen Docker und die Containerwelt.

Dabei lässt es Sie auch bei Troubleshooting und Orchestrierung nicht alleine. Inkl. Best Practices, umfangreichem Werkzeugkasten und vielen Tipps zu Projektmigration, Container-Sicherheit, Kubernetes und mehr.

Docker: Das Praxisbuch für Entwickler und DevOps-Teams.

Docker: Das Praxisbuch für Entwickler und DevOps-Teams.

Aus dem Inhalt:

  • Konzepte und Kommandos

  • Eigene Docker-Images

  • Container-Sicherheit

  • Webserver und Tools

  • Datenbanksysteme

  • Programmiersprachen

  • Webapplikationen und CMS

  • Praxisbeispiel: Webapplikation, Grafana, Gitlab und mehr

  • Anwendungen migrieren

  • Deployment

  • Continuous Integration und Continuous Delivery

  • Orchestrierung mit Swarm und Kubernetes

  • Docker in der Cloud: AWS, Azure, Google Cloud

Rückseite - Docker: Das Praxisbuch für Entwickler und DevOps-Teams.

Rückseite - Docker: Das Praxisbuch für Entwickler und DevOps-Teams.

Skalierbare Container

Oliver Liebel

Skalierbare Container-Infrastrukturen für Ihr Unternehmen

Skalierbare Container-Infrastrukturen: Das Handbuch für Administratoren und DevOps-Teams.
Inkl. Container-Orchestrierung mit Docker, Rocket, Kubernetes, Rancher & Co.

Gebundene Ausgabe: 1071 Seiten
Verlag: Rheinwerk Computing; Auflage: 1 (28. April 2017)
Sprache: Deutsch
ISBN-10: 3836243660
ISBN-13: 978-3836243667
Größe und/oder Gewicht: 18,4 x 6,9 x 25,6 cm

Die nächste Evolutionsstufe der Virtualisierung ist ein Pflichtthema für jedes Unternehmen, dem sich DevOps-Teams und Administratoren stellen müssen: Hochskalierbare und ausfallsichere Microservice-Umgebungen.

Mit diesem Handbuch verstehen Sie die Konzepte hinter den Technologien und können Container-Infrastrukturen auf Basis von Docker in Verbindung mit Swarm Mode, Kubernetes, Rancher, Mesos und DC/OS planen, aufbauen und orchestrieren. So stellen Sie Software schneller bereit und vereinfachen das Deployment und die Wartung Ihrer Infrastruktur – damit Ihre IT-Landschaft auch zukünftig den Anforderungen an Skalierbarkeit und Planungssicherheit gewachsen ist!

Skalierbare Container-Infrastrukturen für Ihr Unternehmen

Skalierbare Container-Infrastrukturen für Ihr Unternehmen

Aus dem Inhalt:

  • Warum Container? DevOps vs. Infrastruktur-Admin. Microservices und Skalierbarkeit

  • Continuous Integration / Continuous Delivery

  • DevOps vs. Infrastruktur-Admin, Microservices und Skalierbarkeit

  • Container Basics: Namespaces, Portierbarkeit, Sicherheit

  • Docker Container: Build, Ship and Run… everywhere? Applikationen im Container, Best Build Practices

  • Fortgeschrittene Verwaltung von Docker Containern: Layer, Storage Backends, Volumes und mehr

  • Trusted Registry, TLS, LDAP-Anbindung

  • Atomic, CoreOS/Container Linux und Rocket

  • World of Tiers – Orchestrierungs-Angelegenheiten

  • Geclusterte Key/Value Stores, Service Registry und Discovery: consul, etcd, zookepper

  • Schwarmintelligenz? Container-Cluster mit Swarm Mode, Docker Data Center

  • Planung, Installation, Administration eines Kubernetes-Clusters

  • Rancher

  • Mesos und DC/OS

  • Ausfallsichere und skalierbare Software Defined Storage-Backends für Container-Cluster: Ceph und Gluster

  • Wohin führt der Weg

Rückseite - Skalierbare Container-Infrastrukturen für Ihr Unternehmen

Rückseite - Skalierbare Container-Infrastrukturen für Ihr Unternehmen

Aktuelle Auflage:

Verlag: Rheinwerk Computing; Auflage: 2 (26. Oktober 2018)
Sprache: Deutsch
ISBN-10: 3836263858
ISBN-13: 978-3836263856

Linux-Server

Linux-Server: Das umfassende Handbuch. Inkl. Samba, Kerberos, Datenbanken, KVM und Docker, Ansible u.v.m. (Ausgabe 2019)

Mit eigenen Kapiteln zu Virtualisierung (Kap. 20) und Docker Containern (Kap. 21).

Auflage: 5 (23. November 2018)

Linux-Server: Das umfassende Handbuch. Inkl. Samba, Kerberos, Datenbanken, KVM und Docker, Ansible u.v.m. (Ausgabe 2019)

Gebundene Ausgabe: 1270 Seiten
Verlag: Rheinwerk Computing; Auflage: 5 (23. November 2018)
Sprache: Deutsch
ISBN-10: 3836260921
ISBN-13: 978-3836260923
Größe und/oder Gewicht: 22,2 x 7,3 x 24,6 cm

Wie Sie Linux-Server effizient nach den aktuellen Standards administrieren, vermittelt Ihnen dieses Buch. Von Hochverfügbarkeit über Sicherheit bis hin zu Scripting und Virtualisierung: Sie lernen Linux-Server distributionsunabhängig intensiv kennen.

Das Buch bietet Ihnen über benötigtes Hintergrundwissen hinaus zahlreiche Praxisbeispiele zu den häufigsten in Unternehmen eingesetzten Distributionen. Und dank Shell-Programmierung, Python, Ansible sowie den im Buch vorgestellten Tools und Automatisierungsskripten lassen Sie Ihre Rechner für sich arbeiten!

Linux-Server (2018/2019)

Linux-Server (2018/2019)

Aus dem Inhalt:

  • Administrationsgrundlagen

  • Devices und Paketmanagement

  • Dateisysteme und Berechtigungen

  • Scripting und Shell-Coding

  • Dienste

  • Web-, Mail-, Proxy-, FTP- und Druckserver

  • Samba, LDAP, Kerberos, NFSv4

  • Infrastruktur und Netze

  • Hochverfügbarkeit

  • Virtualisierung (KVM, Docker)

  • Routing, Bonding, Firewalls

  • DHCP, DNS, OpenSSH

  • Versionskontrolle (VCS)

  • Sicherheit, Monitoring & Co.

  • Backup und Recovery

  • Verschlüsselung

  • Automatisierung

  • Ansible

  • PKI mit OCSP

Rückseite - Linux-Server (2018/2019)

Rückseite - Linux-Server (2018/2019)

Hyper-V

Microsoft Hyper-V: Das Handbuch für Administratoren. Aktuell zu Windows Server 2016

Microsoft Hyper-V: Das Handbuch für Administratoren. Aktuell zu Windows Server 2016

Gebundene Ausgabe: 948 Seiten
Verlag: Rheinwerk Computing; Auflage: 3 (29. Mai 2017)
Sprache: Deutsch
ISBN-10: 383624327X
ISBN-13: 978-3836243278
Größe und/oder Gewicht: 18,4 x 6 x 24,9 cm

Wenn Sie mit Hyper-V unter Windows Server 2016 Server oder Desktops virtualisieren und Ihre Infrastruktur noch effizienter verwalten und auslasten möchten, liegen Sie mit diesem Buch goldrichtig.

Nicholas Dille, Marc Grote, Jan Kappen und Nils Kaczenski sind gefragte und in der Community bestens bekannte Hyper-V-Experten. Gemeinsam bieten Ihnen die Autoren neben allen wichtigen Grundlagen und fortgeschrittenen Virtualisierungstechniken vor allem eines: umfangreiches Praxiswissen.

Microsoft Hyper-V

Microsoft Hyper-V

Aus dem Inhalt:

  • Grundlagen Hyper-V

  • Host-Server

  • Storage

  • Netzwerk

  • VMs und Applikationen

  • Container

  • Verfügbarkeit

  • Betrieb, Backup und Recovery

Rückseite - Microsoft Hyper-V

Rückseite - Microsoft Hyper-V

Linksammlung

Die folgende Linksammlung natürlich ohne Anspruch auf Vollständigkeit ;-) und mit dem Versuch einer Gliederung.

Linksammlung - eine Unsplash Crop Impression

Linksammlung (Bild Unsplash: jon-tyson-i0LcODk-V1Q-unsplash.jpg)

Bitte den folgenden Tipp beachten!

Tipp

Erst nach dem Seminar stöbern!

Und los geht es…

Docker

Links zur Docker Registry:

Best-Pracises / How-Tos

Tools:

Ausgabeformatierungen:

Diverses

Kubernetes

Cheat Sheets

Cheat Sheets - https://scriptcrunch.com/docker-useful-hacks/

Cheat Sheets - scriptcrunch.com/docker-useful-hacks/

Security

seccomp:

Exit-Coding

Videos

Erinnerung: Bitte erst nach dem Seminar ;-)

ReStructuredText

Hier folgen abschließend noch die Meta-Infos zur Dokumentenversionspflege mit Hilfe von restructuredText:

restructuredText

restructuredText auf Wikipedia

Kurzinfo auf Wikipedia:

reStructuredText (kurz ReST, reST oder RST) ist eine vereinfachte Auszeichnungssprache (Markup) mit dem Ziel, in der reinen Textform besonders lesbar zu sein.

Wikipedia - restructuredText

Die reST-Dokumenten lassen sich nahezu beliebig in gewünschte Formate wandeln:

  • ODT - OASIS Open Document Format for Office Applications

    Kurzform: OpenDocument, ODF – engl. Offenes Dokumentformat für Büroanwendungen

  • Textformate wie für LibreOffice, Microsoft Word

  • HTML - diverse HTML-Varianten (Websitestile)

  • LaTex

    professioneller Schriftsatz mit Exportmöglichkeiten nach PostScript und PDF

  • PDF (bzw. PostScript)

  • Epub - Standard für eBooks

Desweiteren lassen sich die Dokumente

  • professionell verlinken (taggen)

  • indizieren und

  • durchsuchen.

Bildinfos

Alle Bildmaterialien in dieser Ausarbeitung wurden nach bestem Wissen recherchiert und sind gemäß ihrer geforderten Bedingungen hinsichtlich des Autors kommentiert.

Unsplash.com - Freie Bilder

Unsplash.com - Freie Bilder

Die entsprechenden Bildmaterialien entstammen folgenden Quellen:

  • Eigene Bildmaterialien

    oder Bildkompositionen

  • Wikipedia

    Link zum Wikipedia Bild (inkl. Autorennennung)

  • Unsplash

    Aus dieser Quelle werden alle Bildmaterialien mit Name attributisiert:

    Bild: magnet-me-beCkhUB5aIA-unsplash.jpg

    Unsplash Autor: magnet-me; Bild-Code: beCkhUB5aIA

    Aus dem Unsplash-Bild-Code (hier: beCkhUB5aIA) lässt sich der Bildlink zum Unsplash-Portal zusammenbauen:

    https: // unsplash.com / photos / beCkhUB5aIA

Abweichende Bild-Quellen wurden entsprechend kommentiert/dokumentiert.

Status dieser Unterlage

Meine inhaltlichen Aufbereitungen zu den Themen unserer Seminarreihe unterliegen ständigen Änderungen und Aktualisierungen.

Bemerkung

Diese Dokument befindet sich in stetiger Überarbeitung. Fehlerbereinigung (Typos) oder eine ggf. noch fehlende Indexierung der Dokumente ist ein Work in Progress und findet auch im Seminar statt.

Fragen Sie also gerne auch einmal später nach einer aktualisierten Variante dieser Ausarbeitung und beziehen sich dabei bitte auf die entsprechende Versionsnummer des Dokuments (oder der angegebenen Versionierung).

Version

Versionierungsmerkmale für die reST-Dokumentstrukturen

Hier folgen jetzt Meta-Infos zur Dokumentenversionspflege:

Version:

2.2-2023

Language:

de

Description:
Unterlagen zu Docker Seminaren Trainer Joe Brandes.
Erstellt mit restructuredText / Sphinx / ReadTheDocs / sphinx_typo3_theme!
Keywords:

Docker, Seminarunterlage, Trainer Joe Brandes

Copyright:

Joe Brandes

Author:

Joe Brandes

License:

GNU General Public License, either version 2 of the License or any later version.

Rendered:

10.04.2023