1. Software verpacken mit Docker
Expertenkreis Java, 18.05.2017, GEDOPLAN
Hendrik Jungnitsch, GEDOPLAN GmbH
2. Problemstellung
Anwendung läuft in unterschiedlichen Umgebungen
Produktion
Test / Integration
Entwicklerrechner
Umgebungen in der Regel unterschiedlich konfiguriert
Aufsetzen einer neuen gleichartigen Umgebung schwierig
=> Schlecht für Continous Integration und Delivery
7. Images
Definieren einer Anwendung mit allen Abhängigkeiten
Bibliotheken, Binaries etc.
Identifiziert über Tagname: (registry/)repo/image:version
Beispiele für Befehle:
Auflisten der Images auf Dockerhost
Entfernen eines Images
$ docker images
$ docker rmi image_name
8. Image Layer
Images können auf anderen Images aufbauen
Erzeugt jeweils einen neuen Layer
Immer ein Basisimage benötigt
Linux-Distribution
Storage-Driver
Union Filesystem
Images sind immutable
Basisimage (Debian)
Layer 1 (JRE)
Layer 2 (Wildfly)
Layer 3 (Anwendung)
9. Registries
Docker Registries verwalten Images
Docker Hub - zentrale öffentliche Registry
Viele offizielle Basis- oder Anwendungsimages
Eigene Images können bereitgestellt werden
Betreiben einer eigenen Registry möglich
Für Images, die nicht öffentlich sein sollen
Zum Cashen von Images
10. Registries
Übermitteln von Images per Push
Beziehen von Images per Pull
Layer werden einzeln übertragen
Nur Layer mit Änderungen werden ausgetauscht
$ docker push jboss/wildfly
$ docker pull jboss/wildfly
Registry
12. Container
Lauffähige Komponente in Docker
Erzeugt auf Basis eines Images
Erstellen und Starten über Run-Befehl
Starten und Stoppen von Containern
Entfernen
$ docker run -d --name=mysql_server -t mysql
$ docker stop mysql_server
$ docker start mysql_server
$ docker rm mysql_server
13. Container
Erzeugen einen weiteren Layer über Image
Schreiben nur in eigenem Layer
Immutable Infrastructure
Erzeugen eines neuen Images
Commit
Basisimage (Debian)
Layer 1 (JRE)
Layer 2 (Wildfly)
Layer 3 (Anwendung)
Container
15. Docker Run Befehl
Erzeugt Container zu einem Image und startet diesen
Image kann Einstiegspunkt definieren, wird bei run ausgeführt
Angeben eines anderen Startpunkes in run-Befehl möglich
Container kann interaktiv oder im Hintergrund gestartet werden
Weitere Konfigurationsparameter
Umgebungsvariablen
Networking
Volumes
16. Dockerfiles
Definieren ein Docker Image
Beziehen sich auf ein Basisimage
Hinzufügen von Dateien möglich
Ausführen von Befehlen
Aufbau der Layer
Können Einstiegspunkt festlegen
FROM alpine
ADD startmysql.sh /var/startmysql.sh
RUN apk add --update mysql &&
mkdir -p /etc/mysql/conf.d &&
mkdir /run/mysqld &&
rm -rf /var/cache/apk/* &&
chmod 644 /etc/mysql/my.cnf
CMD ["/var/startmysql.sh"]
17. Build Command
Erzeugen eines Images aus einem Dockerfile
Vergeben eines Tagnamens möglich
Definieren eines Build-Kontextes
Ressourcen stehen in Build zur Verfügung (z. B. für ADD)
Kann übergeben werden als
Verzeichnis
URL z. B. Git-Repository, Remote Tar-Archiv
Einzelnes Dockerfile
$ docker build –t mytagname /pathtodockerfile/
19. Volumes
Persistente Daten sollten nicht in Containern gespeichert werden
Kein Neuerstellen des Containers möglich
Daten können in Volumes abgelegt werden
Daten bleiben erhalten auch nach Entfernen des Containers
Daten können von Containern geteilt werden
Beeinflusst nicht das Image
Verschiedene Datenspeicher möglich über Driver Plugins
Hostpath, NFS, verschiedene Cloudspeicher etc.
20. Volumes
Einhängepunkte können in Dockerfile definiert werden
Volume erstellen und zuweisen bei Run (Hostpath)
Volume erstellen (NFS)
$ docker run -d --name=mysql_server -v /data/mysql:/var/data/mysql
VOLUME ["/var/data/mysql"]
$ docker volume create --driver local
--opt type=nfs
--opt o=addr=192.168.1.1,rw
--opt device=:/data/volumes/mydatabase
mydatabase
21. Networking
Historisch bedingt drei Netzwerktypen direkt verfügbar
Bridge (Default) – Alle Container, die nichts spezifizieren
None – Eigenes Netzwerk für den Container
Host – Netzwerk-Stack des Hosts
Benutzerdefinierte Netzwerke möglich
Bridge – Isoliertes Netzwerk auf einem Host
Overlay – Netzwerk, das mehrere Hosts überspannt
Custom-Plugin
22. Networking
Eigenes Bridge-Netzwerk definieren
Container innerhalb des Netzwerkes können kommunizieren
Über Containername bzw. Alias
Container in Netzwerk starten
Host-Port-Mapping
$ docker network create --driver bridge my_network
$ docker run -d -p=3306:3306 --name=my_network mysql
$ docker run --network=my_network --name=mysql_server mysql
24. Eigene Registries
Es besteht die Möglichkeit, eine eigene Registry zu betreiben
Für interne Images oder als Cache von Docker-Hub
Verschiedene Implementierungen vorhanden
Docker-Registry, Nexus, …
Registry URL als Prefix in Tagnamen
$ docker run -d -p 5000:5000 --name registry registry:2
$ docker push localhost:5000/mysql
25. Docker-Compose
Definieren komplexerer
Anwendungen
Java-Anwendung
+ Datenbank
+ . . .
Definiert in einem YAML-File
Deklarative Beschreibung
Konfiguration wie bei Run
version: '2‚
services:
mysqldb:
image: localhost:5000/mysql
volumes:
- "/data/mysql:/var/data/mysql„
restart: always
demoapp:
depends_on:
- mysqldb
build: .
image: localhost:5000/demo
restart: always
environment:
DB_CONNECTION_URL: mysqldb:3306
DB_SCHEMA: demo
26. Docker-Compose
Installieren z. B. über pip:
Starten der kompletten Anwendung mit einem Befehl
Erzeugt nur veränderte oder nicht laufende Services
Definiert eigenes Netzwerk für alle enthaltenen Container
Kann auch umkonfiguriert werden
Weitere Features
Healthchecks, mehrere Replikas etc.
$ docker-compose up -d
$ apt-get install python-pip -y
$ pip install docker-compose
27. Docker Host
Anwendung
Überblick Demo Projekt
Registry
MySQL
Wildfly
Poject-Folder
Dockerfile
compose.yml
App
Build
Compose
Volume
Port 8080
Sourcen
Java EE
Anwendung
MySQL
Wildfly
App
Push
Datenbank
Java App
Pull
28. Best-Practices
Images bauen mit Source-to-Image z. B. über Dockerfiles
Verwalten der Sourcen in Git
Passende Basisimages auswählen (Größe, benötigte Werkzeuge etc.)
Ein Container pro Anwendung (Datenbank, Java-Anwendung, …)
Persistente Daten in Volumes ablegen
Alle Umgebungen verwenden die gleichen Images
Sowohl für eigene Anwendungen als auch für Infrastruktur sinnvoll
30. Fazit
Sehr interessant für Paketieren von Software
Anwendungen unabhängig von Programmiersprache verpackt
Einfacher Austausch zwischen den Umgebungen
Ermöglicht Continuous-Delivery
Fördert Wiederverwendung
Dokumentation der Konfiguration durch Dockerfiles etc.