# Docker getting started
Im ersten Teil geht es darum, ein Docker image zu erstellen und im zweiten darum dieses auszuführen.
## Image erstellen
Es gibt mehrere Methoden ein Docker Image zu erstellen. Man fängt aber immer damit an eine *Dockerfile* zu erstellen.
### Auswahl des Basis-Images
Nun öffnen wir die Dockerfile und wählen ein Basis-Image aus. Das Basis-Image kann beliebig sein und darauf baut dann
das Image auf. Beispiele für solch ein Basis-Image kann z.B. sein:
- Ubuntu: ```ubuntu```
- Debian: ```debian```
- CentOS: ```centos```
- Alpine Linux: ```alpine```
- Fedora: ```fedora```
- OpenSUSE: ```opensuse```
- Oracle Linux: ```oraclelinux```
- Windows Server Core: ```mcr.microsoft.com/windows/servercore```
- Windows Nano Server: ```mcr.microsoft.com/windows/nanoserver```
- Webserver:
- NGINX: ```nginx```
- Apache HTTP Server: ```httpd```
- Node.js: ```node```
- Python: ```python```
- Ruby: ```ruby```
- Datenbanken:
- MySQL: ```mysql```
- PostgresSQL: ```postgres```
- MongoDB: ```mongo```
- Redis: ```redis```
- MariaDB: ```mariadb```
- Weitere Anwendungen:
- Java: ```openjdk```
- PHP: ```php```
- Go: ```golang```
- .NET Core: ```mcr.microsoft.com/dotnet/core/sdk```
- WordPress: ```wordpress```
- Django: ```django```
So nutzt man z.B. ein Image in der *Dockerfile*:
```dockerfile
FROM ubuntu:latest
```
### Hinzufügen von Anweisungen
nachdem in der ersten Zeile unser verwendetes Basis-Image steht werden wir uns nun den gängigsten Anweisungen widmen, welche wir nutzen,
um das Image zu konfigurieren und Daten oder Anwendungen hinzuzufügen. Hier sind die gängigsten Anweisungen:
- ```RUN```: Führt Befehle aus, um Pakete zu installieren oder Anwendungen innerhalb des Images zu konfigurieren.
- ```COPY```: Kopiert Dateien oder Verzeichnisse vom Host in das Image.
- ```ADD```: Ähnlich wie COPY, kann aber auch URLs und TAR-Archive verarbeiten.
- ```ENV```: Setzt Umgebungsvariablen innerhalb des Images.
- ```EXPOSE```: Gibt an, auf welchem Port die Anwendung in dem Container lauscht.
- ```CMD```: Definiert den Befehl, der ausgeführt wird, wenn der Container gestartet wird.
- ```ENTRYPOINT```: Gibt den ausführbaren Befehl oder das Skript an, das beim Start des Containers ausgeführt wird.
Nun können wir z.B. git in unser Image installieren, nachdem der Container gestartet worden ist:
```dockerfile
FROM ubuntu:latest
# Git installieren
RUN apt-get update && apt-get install -y git
```
Danach können wir die *bash* starten damit sich die Konsole öffnet:
```dockerfile
FROM ubuntu:latest
# Git installieren
RUN apt-get update && apt-get install -y git
# Arbeitsverzeichnis
ENTRYPOINT [ "bash" ]
```
___Note:___ Der ```ENTRYPOINT``` ist das erste auszuführende Skript im Container!
Nun können das Image etwas weiter ausbauen und z.B. Stable Diffusion von *AUTOMATIC1111* herunterladen und ausführen:
```dockerfile
# Verwende das offizielle Ubuntu-Basisimage mit dem Tag "latest"
FROM ubuntu:latest
# Aktualisiere das Paket-Repository und installiere Git
RUN apt-get update && apt-get install -y git
# Lege das Arbeitsverzeichnis im Container fest
WORKDIR /app
# Klone das Git-Repository in das Arbeitsverzeichnis im Container
RUN git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git /app
# Navigiere in den Ordner des Git-Repositories
WORKDIR /app/stable-diffusion-webui
# Führe das Shell-Skript "webui.sh" aus
CMD ["/app/webui.sh"]
```
Dies war natürlich ein naiver Ansatz, denn so müssen wir auch beachten, was wir später in unserer ausführbaren
Datei brauchen.
⚠️Wenn wir das Programm mithilfe von einer GPU ausführen lassen wollen brauchen wir *nvidia-docker*.
Das muss aber auf dem Host-System installiert werden. ⚠️
So sieht nun schlussendlich unsere fertige Dockerfile aus:
```dockerfile
# Verwende das offizielle Ubuntu-Basisimage mit dem Tag "latest"
FROM ubuntu:latest
# Aktualisiere das Paket-Repository und installiere Git und Python 3
RUN apt-get update && apt-get install -y git python3 python3.10-venv
# Installiere die erforderlichen NVIDIA-Bibliotheken und -Treiber innerhalb des Containers
RUN apt-get install -y nvidia-cuda-toolkit
# Lege das Arbeitsverzeichnis im Container fest
WORKDIR /app
# Klone das Git-Repository in das Arbeitsverzeichnis im Container
RUN git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git /app/stable-diffusion-webui
# Navigiere in den Ordner des Git-Repositories
WORKDIR /app/stable-diffusion-webui
# Erstelle einen neuen Benutzer "sduser" im Container
RUN useradd -ms /bin/bash sduser
# Ändere den Besitzer des Arbeitsverzeichnisses auf den Benutzer "sduser"
RUN chown -R sduser:sduser /app
# Wechsle zum Benutzer "sduser"
USER sduser
# Lege einen *temporären* Argument an, damit NUR die CPU benutzt wird
ENV COMMANDLINE_ARGS="--use-cpu all --skip-torch-cuda-test --precision full --no-half --listen"
# Führe das Shell-Skript "webui.sh" aus
CMD ["bash", "/app/stable-diffusion-webui/webui.sh"]
```
Beachte aber das hier die GPU NICHT mit eingebunden worden ist, da die Flag: ```--skip-torch-cuda-test``` gesetzt worden ist.
Die weiteren Flags sind da um die Probleme mit einer nicht vorhanden GPU zu beheben. Diese sollten auch entfernt werden, sobald man eine
GPU benutzen will. ❗
Wenn die GPU funktioniert startet man den Container später mit dem flag ```--gpus all```.
Hier sind alle Flags, welche man bei Stable Diffusion WebUI verwenden kann (von AUTOMATIC1111):
[Command Line Arguments and Settings](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Command-Line-Arguments-and-Settings)
## Container aus dem Image erstellen
Navigiere in den Ordner wo die *Dockerfile* liegt und baue das Image.
Mit unserem vorherigen Beispiel sähe der Befehl nun z.B. so aus:
```
docker build -t stablediffown .
```
⚠️ Beachte jedoch das Docker dafür gestartet sein muss. ⚠️
Mit dem ```-t```-Flag kann man einem Image einen benutzerdefinierten Namen geben.
Anschließend kann man überprüfen, ob das Image erstellt worden ist:
```
docker images
```
Hier sollte normalerweise das aktuelle Image angezeigt werden.
## Erstmaliges starten des Containers
Starte nun den Container und gebe diesen Container einen Namen, wenn dies gewünscht ist.
Gleichzeitig konfiguriere den Container. Also Portweiterleitung, etc. .
Hier sind mehrere Konfigurationsmöglichkeiten:
- mit GPU-Support (--gpus)
- mit Namensgebung (--name)
- mit Portweiterleitung (-p)
- mit einem Volumen zur permanenten Datenspeicherung (-v)
- mit Aufrechterhalten der Konsole (-it)
```
docker run --gpus all -p PORT_AUF_HOST:PORT_IM_CONTAINER -v /pfad/auf/host:/pfad/im/container -it my_image_name
```
Man kann sowohl relative Pfade als auch absolute Pfade verwenden.
Relative Pfade:
```./verzeichnis/auf/...```
Absolute Pfade:
```/verzeichnis/auf/...```
⚠️ Die Ordner müssen auf dem Host System existieren. ⚠️
Die relativen Pfade gelten immer von dort aus wo der Befehl ```docker run``` ausgeführt wird.
Falls manche Ordner im Container noch nicht existieren sollten werden diese automatisch angelegt.
Ohne GPU:
```
docker run --name MeinEigenerContainer -p 7860:7860 -it stablediffown
```
Mit GPU:
```
docker run --name MeinEigenerContainer --gpus all -p 7860:7860 -it stablediffown
```
*Finaler Command beim erstmaligen Starten des Containers **ohne** GPU:*
Hier wird nun der Name des Containers festgelegt, eine Portweiterleitung durchgeführt und die jeweiligen
Volumen mounted.
```
docker run --name SDTest -p 8080:7860 -v C:\Users\Name\Desktop\Docki\ds\extensions:/app/stable-diffusion-webui/extensions -v C:\Users\Name\Desktop\Docki\ds\models:/app/stable-diffusion-webui/models -v C:\Users\Name\Desktop\Docki\ds\outputs:/app/stable-diffusion-webui/outputs -it stablediffown
```
## Stoppen eines Containers
Es gibt 2 Methoden, entweder über die ID, oder über den Container-Namen:
Zeige alle laufenden Container an:
```
docker ps
```
Mit ID stoppen:
```
docker stop CONTAINER_ID
```
Mit Container-Namen stoppen:
```
docker stop CONTAINER_NAME
```
## Erneutes starten eines Containers
Hier brauchen die Konfigurationen nicht erneut angegeben werden. Man kann diese aber natürlich, wenn man diese
ändern will dennoch angeben.
```
docker start SDTest
```
## Komplettes entfernen eines Containers
```
docker rm --name=CONTAINER_NAME
```