Zum Inhalt

Dockerfile

Ziel

In diesem Projekt geht es um das Dockerfile und das Erstellen von eigenen Images. Sie werden:

  • ein eigenes Dockerfile für einen Service erstellen
  • einen zweiten Service in das Dockerfile hinzufügen und die Services verbinden

Hilfsmittel

  • Versuchen Sie, die unten stehenden Aufgaben mit Hilfe der Folien und des Cheatsheets eigenständig zu lösen.
  • Sollten Sie dabei Probleme haben, finden Sie bei jeder Aufgabe einen ausklappbaren Block, in dem der Lösungsweg beschrieben wird.

Aufgabe 1 - Ein erstes Dockerfile erstellen

  • Erstellen Sie einen neuen Unterordner mein-erstes-image des Workspace-Ordners /home/coder/workspace.
  • Erstellen Sie in dem Ordner ein Dockerfile mit folgenden Eigenschaften:
    • Baseimage: ubuntu:20.04
    • Entrypoint: ["/bin/echo", "Hallo"]
    • Command: ["Welt"]
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Öffnen Sie den Explorer von VSCode mit Strg + B oder alternativ per Klick auf das Datei-Icon (über der Lupe) in der linken Leiste.
  • Erstellen Sie über den Explorer einen neuen Ordner mit dem Namen mein-erstes-image.
  • Erstellen Sie in dem Ordner eine Datei mit dem Namen Dockerfile.
  • Fügen Sie folgenden Inhalt in die Datei ein:
    FROM ubuntu:20.04
    
    ENTRYPOINT ["/bin/echo", "Hallo"]
    CMD ["Welt"]
    

Aufgabe 2 - Ein erstes Image bauen

2.1: Image bauen

Bauen Sie im Terminal aus dem Dockerfile ein Image mit dem Namen demo01.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Öffnen Sie ein Terminal (Menü > Terminal > New Terminal).
  • Wechseln Sie mit cd mein-erstes-image in den erstellten Ordner. cd steht für Change Directory.
  • Führen Sie pwd aus. pwd liefert Ihnen das aktuelle Verzeichnis. Sie sollten die Ausgabe /home/coder/workspace/mein-erstes-image erhalten.
  • Sollten Sie die Ausgabe nicht erhalten, wechseln Sie in das Verzeichnis mit cd /home/coder/workspace/mein-erstes-image.
  • Bauen Sie nun das Image mit:
    docker build -t demo01 .
    
  • Sie sollten nach dem fertigen Build eine Ausgabe sehen, die ähnlich zu folgender aussieht:
    Step 3/3 : CMD ["Welt"]
    ---> Running in fdef47b21535
    Removing intermediate container fdef47b21535
    ---> 6296257370ba
    Successfully built 6296257370ba
    Successfully tagged demo01:latest
    

2.2: Image starten

Starten Sie das Image im Vordergrund (ohne -d). Es sollte "Hallo Welt" ausgeben.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Starten Sie das Image mit folgendem Befehl:
    docker run demo01
    

2.3: Image mit Argumenten starten

Starten Sie das Image, sodass es "Hallo <name>" ausgibt, wobei <name> Ihr Name sein sollte.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Starten Sie das Image mit folgendem Befehl:
    docker run demo01 <name>
    

Aufgabe 3 - Vorbereitung einer kleinen Webapp

3.1: app.py anlegen

Erstellen Sie im Ordner /home/coder/workspace/mein-erstes-image eine Datei app.py mit folgendem Inhalt:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Web App with Python Flask!'

app.run(host='0.0.0.0', port=80)

Diese Pythondatei definiert und startet eine kleine Flask-Webanwendung. Die Anwendung ist über Port 80 erreichbar.

3.2: requirements.txt anlegen

Erstellen Sie im Ordner /home/coder/workspace/mein-erstes-image eine Datei requirements.txt mit dem Inhalt:

Flask>2<3

Ihr Ordner sollte nun wie folgt aussehen:

├── app.py
├── Dockerfile
└── requirements.txt

0 directories, 3 files

Aufgabe 4 - Dockerfile für die Webapp erweitern

4.1: Python installieren

Installieren sie mit Hilfe von apt-get die Pakete python3 und python3-pip.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Ihr Dockerfile sollte nun wie folgt aussehen:
    FROM ubuntu:20.04
    
    RUN apt-get update && apt-get install -y \
            python3 \
            python3-pip \
        && rm -rf /var/lib/apt/lists/*
    

Zunächst wird der Paketmanager auf den neuesten Stand gebracht. Anschließend sollen die Pakete installiert werden. Dieser Teil des Befehls ist essenziell. Der Update- und der rm-Befehl ist Best Practice und wird im nachfolgenden Kapitel genauer behandelt. Die Option -y gibt dabei mit, dass auf die Installationsfrage automatisch yes geantwortet wird. Zuletzt sollten wir den Paket-Cache löschen, um das Image klein zu halten.

4.2: Abhängigkeiten installieren

  • Erweitern Sie Ihr Dockerfile, sodass die Datei requirements.txt in das Image in den Ordner /app kopiert wird. Nutzen Sie den WORKDIR-Befehl, um in den Kontext /app zu wechseln.
  • Installieren Sie die Abhängigkeiten mit folgendem Befehl:
python3 -m pip install -r requirements.txt
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Ihr Dockerfile sollte nun wie folgt oder ähnlich aussehen:
    FROM ubuntu:20.04
    
    RUN apt-get update && apt-get install -y \
            python3 \
            python3-pip \
        && rm -rf /var/lib/apt/lists/*
    
    WORKDIR /app
    COPY requirements.txt .
    RUN python3 -m pip install -r requirements.txt
    

4.3: Webapp einbinden und starten

  • Kopieren Sie die Datei app.py in das Image.
  • Dokumentieren Sie Port 80 als Zugang zur Anwendung.
  • Führen Sie python3 app.py beim Start des Images aus.
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Ihr Dockerfile sollte nun wie folgt aussehen:
    FROM ubuntu:20.04
    
    RUN apt-get update && apt-get install -y \
            python3 \
            python3-pip \
        && rm -rf /var/lib/apt/lists/*
    
    WORKDIR /app
    COPY requirements.txt .
    RUN python3 -m pip install -r requirements.txt
    
    COPY app.py .
    
    EXPOSE 80
    CMD ["python3", "app.py"]
    

4.4: Image bauen und testen

  • Bauen Sie das Image mit dem neuen Dockerfile.
  • Starten Sie das Image mit einer Portweiterleitung, sodass Sie die Webapp über den Browser erreichen.
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Führen Sie zum Bauen folgenden Befehl aus:
    docker build -t demo01 .
    
  • Starten Sie das Image wie folgt:
    docker run -p 8080:80 demo01
    
  • Versuchen Sie die Webapp in einem neuen Tab unter http://code-0.labs.corewire.de:8080/ zu öffnen.
  • Wichtig:
    • http nicht https
    • code-0 durch Ihre Instanz ersetzen.
  • Bei Erfolg können Sie wieder zur VSCode Instanz wechseln und den Container mit Strg+C beenden.

Aufgabe 5 - User im Container ändern

5.1: Nicht-Root Benutzer anlegen

Aus Sicherheitsgründen wollen wir die Webapp im Container nun mit einem Benutzer ausführen, der keine Root-Rechte besitzt. Dafür müssen wir einen Benutzer anlegen. Das geht mit folgendem Befehl:

groupadd --system --gid 10100 app-runner-group \
    && useradd --system --gid 10100 --uid 10100 app-runner-user
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Ihr Dockerfile sollte nun wie folgt aussehen:
    [...]
    RUN python3 -m pip install -r requirements.txt
    
    RUN groupadd --system --gid 10100 app-runner-group \
        && useradd --system --gid 10100 --uid 10100 app-runner-user
    
    COPY app.py .
    [...]
    

5.2: Nicht-Root Benutzer verwenden

Stellen Sie nun sicher, dass die Webapp mit dem angelegten Nutzer app-runner-user ausgeführt wird.

Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Ihr Dockerfile sollte nun wie folgt aussehen:
    [...]
    RUN groupadd --system --gid 10100 app-runner-group \
        && useradd --system --gid 10100 --uid 10100 app-runner-user
    
    USER app-runner-user
    COPY app.py .
    [...]
    

5.3: Image bauen und testen

  • Bauen Sie das Image mit dem neuen Dockerfile.
  • Starten Sie das Image mit einer Portweiterleitung, sodass Sie die Webapp über den Browser erreichen.
Lösung (Klicken Sie auf den Pfeil, falls Sie nicht weiterkommen)
  • Führen Sie zum Bauen folgenden Befehl aus:
    docker build -t demo01 .
    
  • Starten Sie das Image wie folgt:
    docker run -p 8080:80 demo01
    
  • Versuchen Sie die Webapp in einem neuen Tab unter http://code-0.labs.corewire.de:8080/ zu öffnen.
  • Wichtig:
    • http nicht https
    • code-0 durch Ihre Instanz ersetzen.
  • Bei Erfolg können Sie wieder zur VSCode Instanz wechseln und den Container mit Strg+C beenden.

Privilegierte Ports (Ports < 1024) ohne Root-Rechte

Seit Docker 20.10.0 (Release: 08.12.2020, Release notes) können Container auch Ports < 1024 verwenden ohne Root-Rechte zu benötigen.

Eine alternative Lösung für ältere Versionen, den Container ohne Root-Rechte laufen zu lassen wäre, in der app.py Port 80 durch zum Beispiel Port 8080 zu ersetzen und die Portweiterleitung bei docker run entsprechend anzupassen.

Sie haben nun erfolgreich eine bestehende Anwendung containerisiert. Im Dockerfile haben Sie alles definiert, was notwendig ist damit die Anwendung ohne Fehler ihren Zweck erfüllen kann.