class: middle, center, tnw-intertitle

# Vorbereitungen

---

# Vorbereitungen

#### Play With Docker einrichten

- Haben sich alle bei https://hub.docker.com oder https://cloud.docker.com registriert?

.ex[
- Bei https://labs.play-with-docker.com einloggen

- Eine VM erstellen

- In der VM die Übungsdaten herunterladen:  
    `git clone https://github.com/thenativeweb/play-with-docker`

- Testen, ob Docker in der VM funktioniert:  
    `docker version`

    Es sollte die Version von Client *und* Server angezeigt werden
]

---

class: middle, center, tnw-intertitle

# Grundlagen

---

# Grundlagen

#### Docker ist…

- Keine Hardware-Virtualisierung

- Isolierung von Prozessen mittels Linux-Features

    - Cgroups (Limitierung von Ressourcen, z.B. CPU)

    - Namespaces (Eigenständige Sichten auf Ressourcen, z.B. PIDs)

    - Aber: Gemeinsamer Kernel

- Inzwischen auch nativ für Windows (Server 2016, Windows 10)

- Auf anderen Betriebssystemem: Docker-Engine läuft in einer **Linux**-VM
---

# Grundlagen

#### Grundbegriffe

- Docker-Engine

- Docker-Host

- Docker-Image

- Docker-Container

- Docker-Registry

---
class: split-50

# Grundlagen

#### Installation

.column[
#### Linux

- Schnellster Weg:

        curl -fsSL get.docker.com \
             -o get-docker.sh
        sh get-docker.sh
- [Manuelle Installation](https://docs.docker.com/engine/installation/)

- Standardpakete der Distribution hinken oft hinterher
]

.column[
#### Windows

- Schnellster Weg:

    Image auf Azure auswählen: `Windows Server 2016 with Containers`
- [Manuelle Installation](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/index)
]

---

class: middle, center, tnw-intertitle

# Erstellen eines Docker-Images

---

# Erstellen eines Docker-Images
#### Docker-Image

- Virtuelles Dateisystem für die Prozesse im Container

- Dockerfile enthält alle Anweisungen zum Bauen des Images

- Nach dem Build read-only

- In Layers aufgebaut

    - Für jede Anweisung im Dockerfile ein Layer

    - Layers auch read-only!

- Startkommando des (ersten) Prozesses, der im Container laufen soll

---

# Erstellen eines Docker-Images
#### Dockerfile

Bauanleitung für ein Docker-Image

Häufig verwendete [Anweisungen](https://docs.docker.com/engine/reference/builder/):

.column[
- `FROM`

- `ENV`

- `EXPOSE`

- `COPY` (oder `ADD`)

- `RUN`
]

.column[
- `USER`

- `VOLUME`

- `WORKDIR`

- `ENTRYPOINT`

- `CMD`
]

---

# Erstellen eines Docker-Images
#### Demo: Konfigurator

.center[
![Demo](./demo-god-meme.jpg)
]

---

# Erstellen eines Docker-Images
#### Neues Image bauen

.ex[
- Ins Verzeichnis `play-with-docker` wechseln

- Dockerfile anlegen (`vi Dockerfile`):

    - Basierend auf dem `node` Image

    - Datei `app.js` in das Verzeichnis `/code` des Images kopieren

    - Diese Datei mit `node` ausführen lassen

- Image mit dem Namen `sample` bauen
]

---

# Erstellen eines Docker-Images
#### Images verwalten

- Unter `docker image …` sind alle Befehle zur Verwaltung von Images zusammengefasst

.ex[
- Die Unterkommandos von `docker image` anzeigen

- Die lokal installierten Images auflisten
]

- Häufig noch ältere Aliase zu finden:  
    z.B. `docker images` anstelle von `docker image ls`

---

# Erstellen eines Docker-Images
#### Images anlysieren

- Mit `docker image inspect` werden Details zum Image angezeigt

- Mit `docker image history` werden die Anweisungen zum Bau des Images angezeigt

.ex[
- Das von uns gebaute Image mit beiden Befehlen analysieren
]

---

class: middle, center, tnw-intertitle

# Starten von Containern

---

# Starten von Containern

(Zu Images kommen wir später nochmal zurück)

Start eines Containers:

- Das Dateisystem des Images wird in den Namespace gemountet   
    Read-only!

- Neuer temporärer, beschreibbarer Layer wird erzeugt

- Das im Image gespeicherte Kommando wird ausgeführt

---

# Starten von Containern

- Mit `docker container run` wird ein neuer Container gestartet

- Default: Im Vordergrund aber nicht interaktiv

- Verhalten durch Optionen bestimmt. Kommando kann sehr lang werden!

---

# Starten von Containern
#### Name

Der Container kann einen Name bekommen

- Nur für die Verwendung mir den Docker-Kommandos

- Sonst wir ein Zufallsname vergeben

- Auch die ID kann benutzt werden

- Syntax: `--name NAME`

---

# Starten von Containern
#### Ports

- Dockerfile: `EXPOSE` (nur Dokumentation)

- Ports sind nur über die IP des Containers erreichbar

- Man kann beim Start Ports publishen:

    - Der Port wird auf das Host-System weitergeleitet

    - Port von Host und Container kann unterschiedlich sein

    - Syntax: `-p HOST_PORT:CONTAINER_PORT`

---

# Starten von Containern
#### Interaktiv

- Wartet auf Eingabe

- Option `-i`, meist in Verbindung mit `-t` (Pseudo-TTY)

---

# Starten von Containern
#### Detached

- Startet den Prozess im Hintergrund

- Kehrt sofort wieder zurück

- Konsolenausgabe: `docker container logs`

- Stoppen: `docker container stop`

---

# Starten von Containern
#### Übungen

.ex[
- Das `sample` Image im `detached`-Modus starten

- Den Container wieder stoppen

- Neu starten und diesmal Port 3000 publishen

- Im Browser die bereitgestellte Webseite öffnen

- Einen `ubuntu` Container interaktiv (mit Pseudo-TTY) starten
]

---

# Starten von Containern
#### Gestartete Container

- Mit `docker container ls` werden die laufenden Container aufgelistet

- Alias: `docker ps`

- Die Option `-a` listet auch gestoppte Container auf

- Stoppen: `docker container stop`

    Wieder starten: `docker container start`

- Gestoppten Container entfernen: `docker container rm`

---

class: middle, center, tnw-intertitle

# Docker-Images revisited

---

# Docker-Images revisited
#### Docker-Registry

- https://hub.docker.com bzw. Teil von https://cloud.docker.com

- Ermöglicht den Austausch von Images

- Jeder kann Images herunterladen

- Anmeldung notwendig zum Bereitstellen von Images

- Unendlicher Speicher *for free!*

- Auch möglich: Private Registry

---

# Docker-Images revisited
#### Image suchen

- Webseite

- Kommandozeile `docker search`

.ex[
- Nach einem Image für `nginx` suchen:

    - Auf der Kommandozeile

    - Auf der Webseite
]

---

# Docker-Images revisited
#### Image bereitstellen

- Jeder kann kostenlos öffentliche Images bereitstellen

- Private Images kosten Geld

- Anlegen von Repositories für Docker-Images über die Weboberfläche

- Name des Images muss mit dem Benutzernamen beginnen: `Benutzername/Imagename`

- Zuerst einloggen, um Berechtigung zu bekommen: `docker login`

- Hochladen eines Images: `docker image push`

- Herunterladen eines Images: `docker image pull`

---

# Docker-Images revisited
#### Image bereitstellen

.ex[
- Auf https://hub.docker.com oder https://cloud.docker.com ein neues Repository mit Namen `sample` anlegen

- Das `sample` Image nochmals mit dem Namen `Benutzername/sample` bauen

- `docker login` ausführen  
    **Achtung:** Das Passwort wird auf einer externen Maschine verwendet!

- Das gebaute Image hochladen

- Das Image eines anderen Teilnehmers herunterladen
]

---

# Docker-Images revisited
#### Tags

- Ermöglichen die Versionierung/Differenzierung eines Images

- Images mit gleichem Namen aber unterschiedlichem Tags überschreiben sich nicht

- Tag wird an den Namen angehängt: `Benutzername/Imagename:Tag`

- Image taggen: `docker image tag`

    - Auch zum Umbenennen von Images verwendet

---

# Docker-Images revisited
#### Tags

.ex[
- Das Image `Benutzername/sample` mit `1.0` taggen

- Das getaggte Image in die Docker-Registry hochladen

- Auf https://hub.docker.com die Tags des Images anzeigen lassen

- Das getagte Image eines anderen Teilnehmers herunterladen
]

---

# Docker-Images revisited
#### ENTRYPOINT vs. CMD

- Entweder `ENTRYPOINT` oder `CMD` *muss* vorhanden sein

- `ENTRYPOINT` enthält das auszuführende Kommando

- `CMD` enthält Optionen, die angehängt werden

- `CMD` kann ersetzt werden durch Kommandos, die an `docker run` angehängt werden  
    `ENTRYPOINT` durch Parameter änderbar

- Schreibweise: JSON-Array

    z.B.: `["node", "/code/app.js"]`

---

# Docker-Images revisited
#### Layers

- Jede Anweisung im Dockerfile erzeugt einen Layer im Dateisystem des Images

- Datei, die alle Änderungen der Anweisung enthält

- Zugriff auf eine Datei im Container:

    - Die Layers werden der Reihe nach durchsucht. Erster Fund wird zurückgeliefert

- Vorteil: Caching

---

# Docker-Images revisited
#### Layers

.column[
#### Problem

Inhalt einer Datei kann in anderen Layern nicht gelöscht werden!

- Datei wird nur als gelöscht markiert

- Die Größe des Images nimmt nicht ab

- Vertrauliche Daten sind in den unteren Layern noch vorhanden und können extrahiert werden
]

.column[
#### Lösungen

- Mehrere Kommandos in eine RUN-Anweisung zusammenfassen

- `--squash`

- Multi-Stage Builds
]

---

# Docker-Images revisited
#### Layers

.ex[
- Die Layers des `sample` Images mittels `docker image history` auflisten
- Das Image nochmal mit der Option `--squash` bauen
- Die Layers des neuen Images auflisten
]

---

# Docker-Images revisited
#### Multi-Stage Builds

<code><pre>
<b>FROM</b> golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

<b>FROM</b> alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY <b>--from=0</b> /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
</pre></code>

---

# Docker-Images revisited
#### Multi-Stage Builds mit benannten Stages

<code><pre>
<b>FROM</b> golang:1.7.3 <b>as builder</b>
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

<b>FROM</b> alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY <b>--from=builder</b> /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
</pre></code>

---

# Docker-Images revisited
#### Manifest Lists (a.k.a. Multi-Arch Builds)

- Docker Image für unterschiedliche Systemarchitekturen  
    z.B. Linux-amd64, Linux-arm, Windows-amd64

- Das passende Image wird automatisch heruntergeladen

- Bisher über unterschiedliche Tags gelöst (`1.0-linux-arm`)

- Noch in Entwicklung

    - [3rd-party Tool](https://github.com/estesp/manifest-tool) benötigt

    - Wird in Docker Client integriert (`manifest` Kommando)

---

class: middle, center, tnw-intertitle

# Persistenz

---

# Persistenz

- Ein Container schreibt in einen temporären Layer (Copy-On-Write)

- Wenn Container gelöscht wird, sind auch alle Daten verloren

- Möglichkeiten zur Persistierung:

    - Bind Mount

    - Volumes

- Wird als Option bei `docker run` angegeben

---

# Persistenz
#### Bind Mount

- Verwendet Dateisystem des Hosts

- Dateien/Ordner auf Host überdecken Dateien/Ordner im Container

- `--mount type=bind,source=<Pfad auf Host-System>,target=<Pfad im Container>`

- Alternative Option `-v <Pfad auf Host-System>:<Pfad im Container>`

- Absoluter Host-Pfad! ($PWD)

---

# Persistenz
#### Volumes

- Von Docker selbst verwaltet

- Daten werden mit Layern des Containers gemerged

- Verwalten von Volumes: `docker volume`

- `--mount type=volume,source=<Volume-Name>,target=<Pfad im Container>`

- Nicht-existierende Volumes werden automatisch erzeugt

---

# Persistenz
#### TempFS

- Spezieller Mount-Typ

- Geschriebene Daten werden in-memory gespeichert

- Nach *Stoppen* des Containers sind Daten gelöscht

- Nur Linux

---

# Persistenz
#### Übungen

.ex[
- Ins Verzeichnis `play-with-docker` wechseln

- `app.js` nach `app2.js` kopieren: `cp app.js app2.js`

- Dockerfile so anpassen, dass `app.js` nicht kopiert wird, sondern ein Mount-Point für das Verzeichnis `/code` angelegt wird

- Das Image `mount-sample` bauen

- Einen Container starten und das aktuelle Verzeichnis nach `/code` im Container mounten

- Den Container stoppen

- Den Start des Container ändern, um das Kommando `node /code/app2.js` auszuführen
]
---

class: middle, center, tnw-intertitle

# Remote-Steuerung von Docker

---

# Remote-Steuerung von Docker

- Mit `docker-machine` kann der Docker-Engine auf beliebigen Maschinen gesteuert werden

- Kann Docker installieren

    - AWS, Azure und DigitalOcean

    - Linux-Systeme über SSH

    - Lokale VM über VirtualBox oder VMware Fusion

---

# Remote-Steuerung von Docker

- Kommunikation mit remote Engine über TLS gesichert

- Published Ports aber immer noch nur auf remote Maschine erreichbar!

    - Adresse der remote Maschine verwenden

    - SSH-Tunnel auf lokale Maschine

---

class: middle, center, tnw-intertitle

# Multi-Container Applikationen

---

# Multi-Container Applikationen
#### Grundlagen

- Gleichzeitiges Starten einer beliebigen Anzahl von Containern

- Definition der Struktur über [`docker-compose.yml`](https://docs.docker.com/compose/compose-file/)

    - Alle von `docker run` bekannten Einstellungen auch hier möglich

    - Service: Ein oder mehrere Container mit den gleichen Einstellungen

---

# Multi-Container Applikationen
#### Starten und Stoppen

- Die Container werden mit `docker-compose up` gestartet

    - Option `-d` startet die Container im Hintergrund

    - Es können auch einzelne Container angegeben werden

- Gestoppt wird der Verbund mit `docker-compose down`

- In laufende Container kann über `docker-compose exec` eingestiegen werden

- `docker-compose run` startet eine neue Instanz eines Services (interaktiv)

---

# Multi-Container Applikationen
#### Skalieren von Services

- Mittels `docker-compose scale` kann für einen Service die Anzahl der Instanzen geändert werden

- Bei `docker-compose up` kann direkt die Option `--scale` mitgegeben werden

---

# Multi-Container Applikationen
#### Kommunikation

- Die Container können untereinander auf alle Ports zugreifen

- DNS-Auflösung nach Service-Namen möglich

    - nützlich z.B. für Umgebungsvariablen: `DB_HOST=database`

    - Mehrere Instanzen eines Services: Round-Robin

---

# Multi-Container Applikationen
#### Übungen I/II

.ex[
- Eine `docker-compose.yml` erstellen, die folgende Services definiert:

    - `webservice`: Basiert auf dem Image `sample`

    - `client`: Basiert auf dem Image `tutum/curl`

- Die Applikation im Hintergrund starten

- Eine neue Instanz des `client`-Services starten und die Webseite vom `webservice` herunterladen
]

---

# Multi-Container Applikationen
#### Übungen II/II

.ex[
- Über die Umgebungsvariablen eine andere Lieblingsfarbe einstellen  

- Die Applikation stoppen und neu im Hintergrund starten

- Die Anzahl der Instanzen des `webservice` erhöhen

- Wie ändert sich die Ausgabe beim mehrmaligen Herunterladen der Webseite?
]

---

class: middle, center, tnw-intertitle

# Netzwerk

---

# Netzwerk

- Bridge: Standard

- Overlay: Docker Swarm

    - Für jede Applikation ein oder mehrere Netzwerke möglich

- Host: Container verwendet Netzwerkstack vom Host

- None: Container hat keine Netzwerkverbindung

- Verwalten von Netzwerken über `docker network`

.ex[
- Die vorhandenen Netzwerke anzeigen
]

---

class: middle, center, tnw-intertitle

# Orchestrierung

---

# Orchestrierung

- Automatische Verteilung von Docker-Services in einem Cluster

    - Rescheduling bei Ausfall von Knoten

    - Routing von Netzwerkverkehr

- [Docker Swarm](https://docs.docker.com/engine/swarm/)

- Zukünftig [Kubernetes](https://kubernetes.io/) direkt unterstützt

- Weitere Lösungen wie z.B. [Hashicorp Nomad](https://www.nomadproject.io/)

---

# Orchestrierung
#### Docker Stack

- Multi-Container Applikation auf Docker Swarm

- `docker-compose.yml` dient als Basis

- Ein Stack kann private Netzwerke definieren (z.B. für Frontend, Backend)

- Optionen für Anzahl der Replikas eines Services

- Constraints, um nur auf bestimmten Swarm-Knoten zu laufen

    - z.B. Speichergröße, Systemumgebung, frei definierbare Labels

---

# Orchestrierung
#### Docker Stack

.ex[
- Das Image `scherermichael/play-with-docker` als Stack deployen und dabei Port 3000 publishen

- Den Service auf 5 Replikas erweitern

- Das Image `dockersamples/visualizer:stable` zum Stack hinzufügen, um eine Visualisierung des Clusters zu erhalten
]

---

class: middle, center, tnw-intertitle

# Docker für Windows

---

# Docker für Windows
#### Grundlagen

- Einstieg:  
    https://docs.microsoft.com/en-us/virtualization/windowscontainers/

- 2 Typen von Containern:

    - Windows Server-Container

        - Auf Windows 10 nur über Hyper-V-Isolation wegen anderem Kernel

    - Hyper-V-Container

        - Option: `--isolation=hyperv`

        - Zukünfig auch auf Linux-Basis

---

# Docker für Windows
#### Fallstricke I/II

- Backslash ist Escape-Zeichen in Dockerfile!

    - <code># escape=\`</code> einfügen

- Netzwerkunterstützung nicht vollständig

    - z.B. Zugriff auf Ports über localhost nicht möglich

- Mounten in Windows Server-Container intern mittels Symlinks gelöst

    - Ärgerlich für Node.js-Anwender:  
        Pfad kann nicht korrekt aufgelöst werden

---

# Docker für Windows
#### Fallstricke II/II

- Dateizugriffsrechte:

    - Windows Server-Container: ACL

    - Hyper-V-Container: Account `LocalSystem` wird verwendet

- Hyper-V verträgt sich nicht mit anderen Virtualisierungslösungen

---

# Docker für Windows
#### Übungen

.ex[
- Lokal installierte Images anzeigen

- Alle Images von Microsoft suchen

- Multi-Arch-Image `hello-world` ausführen

- Tags des Images `hello-world` auf https://hub.docker.com anzeigen lassen

- IIS als Container starten
]
