1. What is Docker?

  • Frage: Was wäre, wenn es kein Docker gäbe

    • Wir müssten für alles, einen eigenen Server aufsetzen

  • Es können verschiedene Linux-Distributionen als Host und im Docker verwendet werden

    • Es werden die Kernel-Funktionen geteilt

  • Jeder Linux-Container hat einen Namespace

    • vergleichbar mit Scheuklappen

    • es gibt zB nur ein virtuelles Netzwerk. Jeder Container sieht nur dieses Netzwerk.

    • Container run in user space and use kernel of host

    • Docker builds on Linux Containers (LXC)

  • Nachteil von Docker-Containern zu virtuellen Maschinen

    • Die Trennung ist nicht so hart → Sicherheitsaspekte

    • Virtuelle Maschinen sind sicherer.

    • "Die Wand zwischen Host und Docker-Container ist bei Docker-Containern nicht so dick"

      • Virtuelle Maschine: Eigenes Haus mit eigener Zufahrt

      • Docker-Container: Wie Eigentumswohnung

    • Wenn Inhalt trusted oder semi-trusted → Docker-Container

    • Wenn Inhalt untrusted → Virtuelle Maschinen oder gar keine Virtualisierung

    • Mann kann Host-OS und Docker-Container-OS kann man nicht mischen

      • nur Win-Win oder Linux-Linux

container vm

  • Vorteile

    • Fast

      • Boot time

    • Small

    • Agile

      • Docker-in-Docker

    • Portabel

    • Immutable

      • Server werden nicht mehr gepatcht

        • Analogie: Hauskatze vs Kühe in Stall eines bäuerlichen Betriebs

  • Windows-Subsystem

    • (Vollwertiger) Kernel, der auch auf Windows zugreifen kann

    • Speziell für Schüler ist WSL brauchbar

    • Aus dem Microsoft-Store

      • Use the WSL 2 based engine → dann braucht man die Hyper-V Virtualiserung nicht mehr

      • Docker Toolbox ist veraltet (Legacy) und sollte nicht mehr verwendet werden → Docker Community Edition bzw Docker Desktop verwenden

      • Docker Desktop funktioniert nun auch auf Windows Home

    • Zugriff auf lokale Festplatte: /mnt/..

    • man kann auch Windows Programme starten zB calc

    • Windows Terminal (wt) im File Explorer oben eingeben (in Adressleiste)

2. Docker’s Technical Components

  • Linux Container Format

  • Isolation Layers

  • Logging

  • Interactive shell

    • Harry-Potter-Programmieren: kein SSH usw

  • Docker Daemon

    • bietet nach außen eine RESTful API an, mit der man Container steuern kann

    • Sämtliche Kommandos laufen über die REST-API

      • Kleines NodeJS, Quarkus oder c# Programm zum starten eines Containers

      • auch mit Insomnia, Postman usw möglich

  • Clients

    • Docker Dashboard

      • Einfache GUI zum Starten, Stoppen und Review von Docker

    • Plugins in VSCode, IntelliJ, …​

3. What to Use Docker For?

  • Make dev/test/prod-cycle more productive

    • Developers build containers, not apps

    • Containerize build-, test- and CI-tools

  • Segregation of Duties

    • Klarere Abgrenzung der Aufgabenbereiche in der Wirtschaft

      • Früher Admin → heute eher nicht mehr

      • Ein Dev kümmert sich um die Apps (die in Containern laufen)

      • Ein Ops kümmern sich um den Betrieb der Container

  • Microservices

    • Isolieren Dienste (Services)

    • Konsistent über die Phasen (stages): dev/test/prod

      • Mit Docker können viele Aspekte von verteilten Systemen geübt werden

  • Testen auch komplexer Umgebungen lokal

    • Containers sind leichtgewichtig

4. Lab

docker info
docker run -it --rm ubuntu  (1) (2)
1 -it …​ interactive terminal
2 --rm …​ remove container after stopping (exiting the shell)
Achte auf die Geschwindigkeit (beim Start) des Docker Containers
VSC-plugin

vsc docker plugin

Tool im VSC → Remote Development
VSC-remote-plugin

vsc docker remote plugin

  • Den Docker Container im VSC links oben mit rechter Maustaste anklicken

  • Attach to Container anklicken

vsc remote access to container

5. Docker Cluster Solutions

  • Docker Swarm (wird kaum verwendet)

  • Kubernetes

  • Azure Kubernetes Service (AKS)

    • soll für Schüler kostenfrei sein,

    • nur die virtuellen Maschinen sind kostenpflichtig

    • Azure Sponsorship

    • 100 Doller = 100 Euro, hartes Limit, kann nicht überzogen werden

    • wenn man eine Bestätigung (Schülerausweis) hochlädt, kann es sein, dass man jählich 100 $ bekommt

    • für Projekte eher nicht geeignet

    • ALs Lehrer kann man sich auf azure.com einen free-account anlegen

      • Man muss Kreditkarte hinterlegen

      • nach 30 Tagen unbedingt löschen → Im Kalender eintragen

6. Access Docker Remotely

  • Man kann im EDV Saal einen Linux Rechner mit einem Docker-Daemon betreiben

  • Die Clients müssen nur eine Umgebungsvariable setzen und brauchen dann keine Root Rechte

// Set environment variable (secure by default)
export DOCKER_HOST=tcp://40.68.81.114:2375
docker info
docker ps
Diese Lösung NIE, NIE, NIE ungeschützt im Internet verwenden https://docs.docker.com/engine/security/https/
  • Man braucht dann die Docker-Client-Tools

    • nur downloaden und entpacken

    • nichts muss installiert werden

7. Diverse Befehle

docker ps
docker ps -a
docker ps --no-trunc
docker run -it --rm --name my-ubuntu ubuntu
docker attach my-ubuntu # wenn man eine interaktive shell schließt, kann man wieder darauf connecten
docker container list
docker container ls
docker container ls -a
docker rm <container-id>
docker rm my-ubuntu
docker rm -f my-ubuntu # löscht einen laufenden Container
docker top
docker run -d --name my-timer ubuntu /bin/bash -c "while true; do date; sleep 1; done"
docker inspect network

7.1. Windows Container

  • Sind groß

  • instabil

  • langsam

In der Schule nicht empfohlen

7.2. docker events

docker events

7.4. Übungen

docker run -d -p 8080:80 nginx:alpine
docker run -d -p 8080:80 --name my-nginx nginx (1)
docker exec -it my-nginx /bin/bash (2)
cd /usr/share/nginx/html (3)
ls -l
echo hello world > index.html
cat index.html
1 starten des Servers → http://localhost:8080
2 Zugriff auf Shell des Containers
3 in /usr/share/nginx/html liegen die statischen Dokumente

8. Docker Networking

8.1. Access Containers from inside Docker Network

bridge network network access

  • bridge: Standard-Network

  • none: kein Netzwerk

  • host: hängt im Netzwerk des hosts

# Terminal 1
docker run -d -p 8080:80 --name my-nginx nginx
# Terminal 2
docker run -it --rm --name my-ubuntu ubuntu
# Terminal 3
docker inspect my-ubuntu
docker inspect my-nginx

Install curl in Terminal 3 and access nginx with name (doesn’t work) and internal ip (works)

8.2. Create Docker Network

docker network create -d bridge my-isolated-net
docker inspect my-isolated-net
Vergeben eines links
# Terminal 1
docker run -d -p 8080:80 --net=my-isolated-net --name webserver nginx:alpine
# Terminal 2
docker run -it --rm --net=my-isolated-net --name my-ubuntu --link webserver:myserver ubuntu
# Terminal 3
docker inspect webserver
docker inspect my-ubuntu
apt-get update
apt-get install curl
curl webserver # shows index.html
Im Host-Netzwerk laufen lassen
docker run -d --net=host ubuntu

9. docker-compose

  • docker run …​ kann lang und unübersichtlich werden

  • in docker-compose.yml kann der Aufruf sauber durchgeführt werden

  • Aufruf mit docker-compose up

10. Lab: Postgre-sql

Login bei pg-admin

pg admin login

  1. Die erstellte Tabelle in pg-admin pg admin

version: "3.8"
services:
  pg-db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: secret

  pg-admin:
    image: dpage/pgadmin4
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@demo.com
      PGADMIN_DEFAULT_PASSWORD: secret
      PGADMIN_LISTEN_PORT: 80
    ports:
      - "8080:80"
    links:
      - "pg-db:pg-db"

10.1. Minecraft Übung mit Docker

Minecraft Server in Docker mit verschiedenen Konfigurationen hochfahren

10.2. Volume Demo

docker run --rm \
    -v ${PWD}/website:/usr/share/nginx/html:ro \
    -p 8080:80 \
    --name webserver \
    nginx:alpine
  • Windows-Volumes können in einen Linux Docker grundsätzlich gemounted werden

    • für Text- und Konfigurationsdateien

    • jedoch nicht für Datenbankdateien

  • Im Produktivbetrieb ist immer eine Versionsnummer für das Image anzugeben

Semantische Versionierung: https://semver.org/lang/de/
app.ts
const greetingParagraph = document.getElementById('greeting') as HTMLParagraphElement;

greetingParagraph.innerText = "Hello Docker";
Dieser Container kompiliert den ts-code
docker run --rm \
       -d \
       -v ${PWD}:/app \
       -w /app \
       node:alpine npx tsc --watch
Dieser Container zeigt

#[source,bash]

docker run --rm \
       -v ${PWD}:/app \
       -w /app \
       -p 3000:3000 -p 3001:3001
       node:alpine npx browser-sync start --server --watch
  • -v - Syntax ist veraltet, jetzt --mount

11. Lab 030 - Docker Volumes

docker run -d \
           -e POSTGRES_PASSWORD=secret \
           -e PGDATA=/pgdata \
           --net pg-net \
           -v ${PWD}/pgdata:/pgdata \
           --name pg-db postgres
Create a Docker Volume
docker volume create dbstore
docker run -d \
           -e POSTGRES_PASSWORD=secret \
           -e PGDATA=/dbdata \
           --mount 'type=volume,src=dbstore,dst=/dbdata' \
           --name pg-db \
           postgres
docker run --rm \
           --mount 'type=volume,src=dbstore,dst=/dbdata' \
           -w /dbdata ubuntu /bin/bash -c "ls -la"
docker run --rm \
           --mount 'type=volume,src=dbstore,dst=/dbdata' \
             --mount 'type=bind,src=/home/rainer/backup,dst=/backup' \
	         ubuntu tar cvf /backup/backup.tar /dbdata
           -w /dbdata ubuntu /bin/bash -c "ls -la"
Backup the files from the storage
docker run --rm \
  --mount 'type=volume,src=dbstore,dst=/dbdata' \
  --mount 'type=bind,src=/tmp/backup,dst=/backup' \
	ubuntu tar cvf /backup/backup.tar /dbdata

ls –la /tmp/backup/

In MacOS the source-binding-folder is supposed to have write-permission and must therefore be listed in Docker FILE SHARING

docker folders with write permission

12. Docker Images

Ein Docker Image ist wie eine Klasse:

  • es ist wie ein Muster, eine Vorlage

  • mit einem Image alleine kann man nichts anfangen

  • von einem Image können mehrere Container erstellt werden

  • Ein Image verbraucht keine CPU-Zeit, da es nicht läuft

docker images
docker run -it ubuntu  (1)
echo hallo > greet.txt
exit
docker ps -a (2)
1 Ein Container wird erstellt
2 man sieht der Container ist gestoppt

12.1. Docker Commit

wird in der Praxis nicht/kaum verwendet, nur hier zu Demonstrationszwecken
docker commit <hex> ubuntu-with-greeting
docker images
docker history ubuntu-with-greeting:latest
docker run -it --rm ubuntu-with-greeting
docker history ubuntu-with-greeting:latest
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
5cc3b3847f03        2 minutes ago       /bin/bash                                       34B
9140108b62dc        2 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           2 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>           2 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     0B
<missing>           2 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   811B
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:da80f59399481ffc3…   72.9MB
  • Docker ist in Zwiebelschichten aufgebaut

  • Man kann zusätzliche Funktionalität hinzufügen

    • zB Base Image mit Puppeteer (headless chrome) anreichern

  • eigene Images für Testen usw erstellen

12.2. Dockerfile

  • Dockerfile ist eigentlich eine eigene "Programmiersprache" (nicht wirklich, sondern eine deklarative Sprache ohne Schleifen usw.)

12.2.1. Lab

  • Create folder

mkdir hello-dockerfile
cd hello-dockerfile
  • Open in your IDE and create a file named Dockerfile

FROM ubuntu
RUN echo Hallo > greet.txt
  • Start the build

docker build -t ubuntu-from-dockerfile .
output
Sending build context to Docker daemon   7.68kB
Step 1/2 : FROM ubuntu
 ---> 9140108b62dc
Step 2/2 : RUN echo Hallo > greet.txt
 ---> Running in 686d0f7bd479
Removing intermediate container 686d0f7bd479
 ---> de4bd9e4a79a
Successfully built de4bd9e4a79a
Successfully tagged ubuntu-from-dockerfile:latest
Dockerfile commands are easy cheesy (RUN, …​), but the shell-scripts are often complicated
  • Jedes RUN ist eine "Zwiebelschicht"

12.3. Häufigste Befehle

  • FROM

  • RUN um Shell Scripts zu starten

  • COPY

12.3.1. COPY

Create a file greet2.txt in yout local folder

FROM ubuntu
RUN echo Hallo > greet.txt
COPY *.txt /
  • mit COPY kann man aus dem Verzeichnis in dem das Dockerfile liegt, Dateien in das Image kopieren

  • mit einem Parameter kann dieses Verzeichnis geändert werden

kontrollieren mit
docker run --rm ubuntu-from-dockerfile cat /hello2.txt
Bei 2-maligen ausführen wird der Cache verwendet
Sending build context to Docker daemon  11.78kB
Step 1/3 : FROM ubuntu
 ---> 9140108b62dc
Step 2/3 : RUN echo Hallo > greet.txt
 ---> Using cache
 ---> de4bd9e4a79a
Step 3/3 : COPY hello2.txt /
 ---> Using cache
 ---> dfcea995e3ed
Successfully built dfcea995e3ed
Successfully tagged ubuntu-from-dockerfile:latest
  • Durch gezieltes Erstellen mehrerer RUN-Statements kann man

  • Mit .dockerignore können Dateien ausgeschlossen werden, dh sie werden mit COPY nicht übertragen

FROM ubuntu
RUN apt-get update
RUN echo Hallo > greet.txt
WORKDIR app2
COPY *.txt .
  • Problem: Hier würde er bei einem apt-get update das gecachte Image verwenden.

  • Workaround 1 (dirty): verwende ENV Variable

FROM ubuntu
ENV date='2020-10-13'
RUN apt-get update
RUN echo Hallo > greet.txt
WORKDIR app2
COPY *.txt .
  • Workaround 2: Cache löschen

docker build -t ubuntu-from-dockerfile . --no-cache
  • --build-arg: Parameter für Dockerfile

12.3.2. CMD

  • Ist jenes Statement, welches ausgeführt wird, wenn der Container gestartet wird

zB CMD ["/bin/bash"]

  • Das Command wird erst beim Start des Containers ausgeführt, nicht beim Build des Images

12.3.3. ENTRYPOINT

ENTRYPOINT ...
CMD ...

12.3.4. ARG und ENV

  • ARG gilt nur für Build-zeitpunkt im Dockerfile

  • ENV ist Environment Variable und gilt dann auch om Docker Container

13. Lab 040 - nodejs

mkdir docker-node-express
docker run --rm -v ${PWD}:/app -w /app node npm init -y
docker run --rm -v ${PWD}:/app -w /app node npm install express hbs (1)
docker run --rm -v ${PWD}:/app -w /app node npm install -D @types/express copyfiles typescript
docker run --rm -v ${PWD}:/app -w /app node npx tsc --init
1 install express und handlebar https://handlebarsjs.com/
gitignore
node_modules/
dist/
docker run --rm -v ${PWD}:/app -w /app node npm run build
docker run --rm -v ${PWD}:/app -p 8080:8080 -w /app node npm start

040 result1 browser

  • Dockerfile muss nicht im build-Context enthalten sein

  • .dockerignore muss nicht im build-Context enthalten sein

Dockerfile
FROM node
WORKDIR /app
COPY . .
RUN npm install && npm run build
docker build -t myexpress .
  • es gibt kein volume mounting , die app ist bereits hineingebacken

  • Kritikpunkte

    • der gesamte Ordner wird mit COPY . . in das Image kompileiert

    • der gesamte typescript-Ordner ist im Image drinnen

  • → Daher wird der build-Prozess in mehrere Teile zerteilt

13.1. Multi-Stage-Build

Dockerfile
FROM node AS BUILDER
WORKDIR /app
COPY . .
RUN npm install && npm run build

(1)

FROM node:alpine
WORKDIR /app
COPY --from=builder /app/dist . (2)
COPY --from=builder /app/package.json . (3)
RUN npm install --only-prod
EXPOSE 8080 (4)
CMD ["node","app.js"]
1 hier könnte ein Image mit meinen Unit-Tests sein
2 aus dem builder-image werden die Ergebnisse kopiert
3 zu Dokumentationszwecken wird der Port angegeben
  • Multi-Stage wird immer dann durchgeführt, wenn es eine build-pipeline gibt

  • Bei Verwendung eines Automationsservers (Jenkins, travis, …​) wird oft kein multi-staging verwendet

build the image
docker build -t myexpress .

or

docker build -t myexpress . --no-cache
look at the size of the images
docker images
run the image
docker run -d -p 8080:8080 myexpress

13.3. Upload to Docker Registry (Docker Hub)

docker tag myexpress htlleonding/myexpress
docker images
Ein Tag wurde erstellt, zeigt aber auf das bestehende Image
REPOSITORY                                    TAG                 IMAGE ID            CREATED             SIZE
htlleonding/myexpress                         latest              42fb7a80c3ed        About an hour ago   201MB
myexpress                                     latest              42fb7a80c3ed        About an hour ago   201MB
....
docker login
docker push htlleonding/myexpress

13.4. Deployment to Azure

  • Resource Groups → docker-seminar

  • Add "Web App"

  • In Marketplace choose "Web App for Containers"

  • Create

    • name: docker-seminar-xxx

    • Region: West Europe

    • Sku and size: Free F1

    • image: htlleonding/myexpress

14. Lab - Reverse Proxy

Source: Rainer Stropek

060 lab architecture

  • Die Verwendung eines API Gateways verhindert Probleme mit CORS (Cross-Origin-Resource-Sharing)

docker-compose.yml
version: "3.8"
services:
  backend:
    build: ./backend
    ports:
      - "8081:80"
    networks:
      - mynet
  frontend:
    build: ./frontend
    networks:
      - mynet
  proxy:
    build: ./proxy
    networks:
      - mynet
    ports:
      - "8080:80"
networks:
  mynet:
    driver: bridge
nginx configuration (Reverse Proxy)
events {
}
http {
    upstream ui {
        server frontend;
    }
    upstream api {
        server backend;
    }

    server {
        listen 80;

        location /api {
            proxy_pass http://api;
        }
        location / {
            proxy_pass http://ui;
        }
    }
}

15. Distributed Application Runtime

u.a. von MS initiiert

16. Lab Hugo

16.1. Variante 1: Register GitHub-Repo in Docker-Hub

050 docker github registration

16.2. Variante 2: Use GitHub Actions

  • create <project-root>/github/workflow/

  • in github secrets erstellen

    • Settings - Secrets

    • DOCKERHUB_USERNAME

    • DOCKERHUB_TOKEN

to be continued …​