Skript/Docker: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| (9 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
<noinclude> | |||
{{:Seminar/Docker/Inhalte}} | '''Skript/Docker''' - Verstehen und anwenden | ||
=== Inhalt === | |||
{{:Seminar/Linux/Docker/Inhalte}} | |||
= 01 Überblick = | = 01 Überblick = | ||
[[Docker]] | |||
{{:Docker}} | {{:Docker}} | ||
= 02 Grundlagen = | = 02 Grundlagen = | ||
[[Docker/Grundlagen]] | |||
{{:Docker/Grundlagen}} | {{:Docker/Grundlagen}} | ||
= 03 Installation = | = 03 Installation = | ||
[[Docker/Installation]] | |||
{{:Docker/Installation}} | {{:Docker/Installation}} | ||
= 04 Containerisieren = | = 04 Containerisieren = | ||
[[Docker/Containerisieren]] | |||
{{:Docker/Containerisieren}} | {{:Docker/Containerisieren}} | ||
= 05 Aktualisieren = | = 05 Aktualisieren = | ||
[[Docker/Aktualisieren]] | |||
{{:Docker/Aktualisieren}} | {{:Docker/Aktualisieren}} | ||
= 06 Datenbank = | = 06 Datenbank = | ||
[[Docker/Datenbank]] | |||
{{:Docker/Datenbank}} | {{:Docker/Datenbank}} | ||
= 07 Mounts = | = 07 Mounts = | ||
[[Docker/Mounts]] | |||
{{:Docker/Mounts}} | {{:Docker/Mounts}} | ||
= 08 Multi-Container = | = 08 Multi-Container = | ||
[[Docker/Multi-Container]] | |||
{{:Docker/Multi-Container}} | {{:Docker/Multi-Container}} | ||
= 09 Compose = | = 09 Compose = | ||
[[Docker/Compose]] | |||
{{:Docker/Compose}} | {{:Docker/Compose}} | ||
= 10 Image-Erstellung = | = 10 Image-Erstellung = | ||
[[Docker/Image-Erstellung]] | |||
{{:Docker/Image-Erstellung}} | {{:Docker/Image-Erstellung}} | ||
= 11 Docker-Swarm = | = 11 Docker-Swarm = | ||
[[Docker/Swarm]] | |||
{{:Docker/Swarm}} | {{:Docker/Swarm}} | ||
= 12 Ausblick = | = 12 Ausblick = | ||
[[Docker/Ausblick]] | |||
{{:Docker/Ausblick}} | {{:Docker/Ausblick}} | ||
| Zeile 42: | Zeile 61: | ||
__KEIN_INHALTSVERZEICHNIS__ | __KEIN_INHALTSVERZEICHNIS__ | ||
</noinclude> | </noinclude> | ||
[[Kategorie:Seminar/Docker]] | |||
Aktuelle Version vom 12. Oktober 2026, 14:54 Uhr
Skript/Docker - Verstehen und anwenden
Inhalt
01 Überblick
02 Grundlagen
Beschreibung
03 Installation
Docker/Installation - Docker auf Debian installieren
Beschreibung
Docker/Engine läuft nativ unter Linux
Systemvoraussetzungen
| Anforderung | Beschreibung |
|---|---|
| Prozessor (CPU) | x86-64-Architektur, min. 2 GHz (Single-Core) |
| Arbeitsspeicher (RAM) | min. 2 GB (für die Docker-Anwendung mit GUI benötigen Sie mindestens 4 GB RAM) |
| Betriebssystem | Linux, Benutzer mit Root-Rechten |
| Kernel | 4.19 oder höher, mit Unterstützung für cgroups, Namespaces, Overlay-Dateisystem und Seccomp-Filter |
| Festplattenspeicher | min. 20 GB |
| Internetverbindung | Download von Docker-Images und Paketen |
| Git-Client | SOLLTE installiert sein |
Installation
- Installation aus dem Debian-Repository
sudo apt install docker.io docker-cli docker-compose docker-buildx
Docker-Systemgruppe
- Docker ohne sudo
Um Docker-Befehle ohne sudo verwenden zu können, muss der Benutzer Mitglied der Systemgruppe docker sein
- Gruppe hinzufügen
sudo groupadd docker
- Gruppe beitreten
sudo usermod -aG docker <USER>
04 Containerisieren
Beschreibung
- Containerisieren einer Anwendung eines Dockerfiles
- Zur Erstellung eines Images
- Container starten
- Laufende Anwendung prüfen
- Beispiel
ToDo-Manager der auf Node.js basiert
- JavaScript-Vorkenntnisse sind nicht erforderlich
Anwendung
- Anwendung herunterladen
getting-started-app-Repositorys klonen
git clone https://github.com/docker/getting-started-app.git
- Inhalt des geklonten Repositorys
tree -L 1 -a getting-started-app
└── getting-started-app/
├── .dockerignore
├── package.json
├── README.md
├── spec/
├── src/
└── yarn.lock
Dockerfile
- Dockerfile anlegen
Ein Dockerfile ist einfach eine textbasierte Datei, die ein Skript mit Anweisungen enthält
- Docker verwendet dieses Skript, um ein Container-Image zu erstellen
Erstellen Sie im Verzeichnis getting-started-app eine Datei namens Dockerfile mit folgendem Inhalt
# syntax=docker/dockerfile:1
FROM node:lts-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
Dieses Dockerfile beginnt mit einem node:lts-alpine-Basis-Image, einem leichtgewichtigen Linux-Image, auf dem Node.js und der Yarn-Paketmanager vorinstalliert sind
- Es kopiert den gesamten Quellcode in das Image, installiert die notwendigen Abhängigkeiten und startet die Anwendung
- Beschreibung
Syntax
Image
- Image erstellen
cd getting-started-app
- docker buildx build
docker buildx build -t getting-started .
Der Befehl docker buildx build verwendet das Dockerfile, um ein neues Image zu erstellen
- Sie haben vielleicht bemerkt, dass Docker eine Menge "Schichten" heruntergeladen hat
- Das liegt daran, dass Sie dem Builder mitgeteilt haben, dass Sie mit dem node:lts-alpine-Abbild beginnen wollen
- Da Sie dieses aber nicht auf Ihrem Rechner hatten, musste Docker das Abbild herunterladen
Nachdem Docker das Image heruntergeladen hat, kopierten die Anweisungen aus der Dockerdatei Ihre Anwendung und installierten mithilfe von Garn die Abhängigkeiten Ihrer Anwendung
- Die CMD-Direktive gibt den Standardbefehl an, der beim Starten eines Containers aus diesem Image ausgeführt werden soll
Das Flag -t schließlich kennzeichnet Ihr Image
- Stellen Sie sich dies als einen für Menschen lesbaren Namen für das endgültige Image vor
- Da Sie dem Abbild den Namen getting-started gegeben haben, können Sie auf dieses Abbild verweisen, wenn Sie einen Container starten
Das . am Ende des Docker-Build-Befehls teilt Docker mit, dass es im aktuellen Verzeichnis nach dem Dockerfile suchen soll
Container
- Container starten
Starten Sie Ihren Container mit dem Befehl docker run und geben Sie den Namen des soeben erstellten Images an
docker run -d -p 3000:3000 getting-started
Mit dem Flag -d (kurz für --detach) wird der Container im Hintergrund ausgeführt
- Das bedeutet, dass Docker Ihren Container startet und Sie zur Terminal-Eingabeaufforderung zurückkehren
- Außerdem werden keine Protokolle im Terminal angezeigt
Das Flag -p (kurz für --publish) erstellt eine Port-Zuordnung zwischen dem Host und dem Container
- Das Flag
-pnimmt einen String-Wert im Format HOST:CONTAINER an, wobei HOST die Adresse des Hosts und CONTAINER der Port des Containers ist - Der Befehl leitet den Container-Port 3000/TCP auf den Host-Port 3000/TCP weiter.
- Ohne die Port-Zuordnung wäre es nicht möglich, vom Host aus auf die Anwendung zuzugreifen.
- Öffnen Sie nach ein paar Sekunden Ihren Webbrowser auf http://<host_ip>:3000
- Sie sollten Ihre Anwendung sehen
Fügen Sie ein oder zwei Elemente hinzu und prüfen Sie, ob sie wie erwartet funktioniert
- Sie können Elemente als vollständig markieren und entfernen
- Ihr Frontend speichert erfolgreich Elemente im Backend
Zu diesem Zeitpunkt haben Sie einen laufenden ToDo-Listen-Manager mit ein paar Einträgen
Wenn Sie einen kurzen Blick auf Ihre Container werfen, sollten Sie mindestens einen Container sehen, der das Getting-Started-Image verwendet und auf Port 3000 läuft
- Um Ihre Container zu sehen, können Sie die CLI oder die grafische Oberfläche von Docker Desktop verwenden
- Container auflisten
docker ps
Es sollte eine ähnliche Ausgabe wie die folgende erscheinen
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
df784548666d getting-started "docker-entrypoint.s..." vor 2 Minuten Up 2 Minuten 3000->3000/tcp priceless_mcclintock
- Nächste Schritte
- Änderung an Anwendungen vornehmen
- Laufende Anwendung mit einem neuen Image aktualisieren
- Weitere nützliche Befehle
05 Aktualisieren
Beschreibung
- Aktualisieren von Anwendungen
In Docker/Containerisieren wurde eine ToDo-Anwendung containerisiert
- Hier sollen die Anwendung und das Image aktualisiert werden
- Themen
- Image aktualisieren
- Image neu erstellen
- Container stoppen
- Container entfernen
Quellcode aktualisieren
Ändern von "No items yet! Add one above!" in "Sie haben noch keine ToDo-Einträge! Fügen Sie oben einen hinzu!", wenn keine ToDo-Listeneinträge vorhanden sind
Quellcode ändern
- Hilfetext ändern
Ändern Sie in der Datei src/static/js/app.js die Zeile 56, um den neuen leeren Text zu verwenden
- <p className="text-center">No items yet! Add one above!</p>
+ <p className="text-center">Sie haben noch keine ToDo-Einträge! Fügen Sie einen oben hinzu!</p>
Aktualisiertes Images erstellen
docker buildx build -t getting-started .
Aktualisierten Container starten
docker run -dp 3000:3000 getting-started
- Fehlermeldung
docker: Error response from daemon: driver failed programming external connectivity on endpoint laughing_burnell
(bb242b2ca4d67eba76e79474fb36bb5125708ebdabd7f45c8eaf16caaabde9dd): Bind für <server_ip>:3000 fehlgeschlagen: Port ist bereits vergeben
Fehler tritt auf, wenn Sie den neuen Container zu starten, während der alter Container noch läuft
- Der Grund dafür ist, dass der alte Container bereits den Port 3000 des Hosts verwendet und nur ein Prozess auf dem Rechner (einschließlich Container) auf einen bestimmten Port hören kann.
Um dies zu beheben, müssen Sie den alten Container entfernen
Container entfernen
Um Container zu entfernen, müssen Sie zunächst angehalten werden
- Container-ID ermitteln
docker ps
- Container anhalten
Ersetzen Sie <container-id> durch die ID von docker ps
docker stop <container-id>
- Container entfernen
docker rm <container-id>
- Container mit einem einzigen Befehl stoppen und entfernen
docker rm -f <container-id>
- Container-Namen
Anstelle von Container-ID kann auch der Container-Name verwendet werden
Jeder Container hat eine NAME-Eigenschaft
- Wenn der Benutzer keinen Namen manuell festgelegt hat, generiert Docker einen zufälligen Namen, wobei das erste Wort des Namens ein Adjektiv und das zweite Wort der Nachname eines Wissenschaftlers ist
Aktualisierten Container starten
docker run -dp 3000:3000 getting-started
Aktualisieren Sie Ihren Browser auf <server_ip>:3000 und Sie sollten Ihren aktualisierten Hilfetext sehen
Nächste Schritte
- Images mit anderen teilen
06 Datenbank
Beschreibung
Persistieren einer Datenbank
- Beispiel
- Bis lang ist die To-do-Liste leer, wenn Sie den Container starten
- Warum ist das so?
- In diesem Kapitel wird dargestellt, wie der Container funktioniert
Containers-Dateisystem
Wenn ein Container läuft, verwendet er die verschiedenen Schichten eines Images für sein Dateisystem.
- Jeder Container erhält auch seinen eigenen "Scratch Space", um Dateien zu erstellen/zu aktualisieren/zu löschen.
- Alle Änderungen werden in einem anderen Container nicht sichtbar, obwohl sie das gleiche Image verwenden
Praxis
Um dies in Aktion zu sehen, werden Sie zwei Container starten. In einem Container erstellen Sie eine Datei. In dem anderen Container überprüfen Sie, ob die gleiche Datei existiert.
1. Starten Sie einen Alpine-Container und erstellen Sie in diesem eine neue Datei
docker run --rm alpine touch greeting.txt
2. Alle Befehle, die Sie nach dem Image-Namen (in diesem Fall Alpine) angeben, werden innerhalb des Containers ausgeführt. In diesem Fall legt der Befehl touch greeting.txt eine Datei namens greeting.txt im Dateisystem des Containers an.
3. Starten Sie einen neuen Alpine-Container und verwenden Sie den Befehl stat, um zu überprüfen, ob die Datei existiert
docker run --rm alpine stat greeting.txt
Sie sollten eine ähnliche Ausgabe wie die folgende sehen, die anzeigt, dass die Datei im neuen Container nicht existiert.
stat: can't stat 'greeting.txt': No such file or directory
Die Datei greeting.txt, die vom ersten Container erstellt wurde, existiert nicht im zweiten Container.
- Das liegt daran, dass die beschreibbare "oberste Schicht" eines jeden Containers isoliert ist.
- Auch wenn beide Container dieselben Schichten verwenden, die das Basis-Image bilden, ist die beschreibbare Schicht für jeden Container einzigartig
- Hinweis
- Der Parameter
--rmdes Befehlsdocker runwird verwendet, um den Container und seine beschreibbare Ebene nach Abschluss des Prozesses automatisch zu löschen.
Container-Volumen
Jeder Container wird beim Start erneut auf Basis des Images erstellt
- Ein Container kann während der Laufzeit Dateien erstellen, ändern und löschen. Allerdings gehen alle Änderungen beim Entfernen des Containers verloren
- Durch die Verwendung von Volumes können Daten außerhalb des Containers gespeichert und beim Entfernen des Containers beibehalten werden
- Volumes
- Ermöglichen, bestimmte Dateisystempfade des Containers wieder mit dem Host-Rechner zu verbinden.
- Wenn Sie ein Verzeichnis im Container mounten, werden Änderungen an diesem Verzeichnis auch auf dem Host-Rechner sichtbar.
- Wenn Sie dasselbe Verzeichnis über mehrere Container-Neustarts hinweg mounten, sehen Sie dieselben Dateien
Es gibt zwei Haupttypen von Volumes
- Letztlich werden beide verwendet, jedoch wird zunächst mit Volume-Mounts begonnen.
Persistieren der ToDo-Daten
- Persistieren der ToDo-Daten
- Standardmäßig speichert die Todo-App ihre Daten in einer SQLite-Datenbank unter /etc/todos/todo.db im Dateisystem des Containers
- SQLite ist eine relationale Datenbank, die alle Daten in einer einzigen Datei ablegt
- Da die Datenbank aus einer einzelnen Datei besteht, kann diese Datei auf dem Host-System persistiert und von einem neuen Container weiterverwendet werden, um den vorherigen Zustand beizubehalten
- Durch das Erstellen eines Volumes und das Mounten an das Verzeichnis, in dem die Daten liegen, werden die Daten dauerhaft gespeichert
- Alle Schreibvorgänge in die Datei todo.db werden auf dem Host im Volume gespeichert
- Docker verwaltet das Volume vollständig, einschließlich des physischen Speicherorts. Es genügt, den Namen des Volumes zu kennen
Volume erstellen und Container starten
Sie können das Volume erstellen und den Container über die CLI oder die grafische Oberfläche von Docker Desktop starten.
1. Volume erstellen
docker volume create todo-db
2. Container anhalten und entfernen
- Stoppen und Entfernen des Todo-App-Containers, während er noch kein verwendet
<code>docker rm -f <id></code>
3. Starten Sie den todo-App-Container, aber fügen Sie die Option --mount hinzu, um ein Volume zu mounten. Geben Sie dem Volume einen Namen und mounten Sie es in <code>/etc/todos</code> im Container, wodurch alle Dateien, die unter dem Pfad erstellt werden, erfasst werden
<syntaxhighlight lang="bash" highlight="1" line copy>
docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
- Hinweis
- Wenn Sie Git Bash verwenden, müssen Sie für diesen Befehl eine andere Syntax verwenden.
docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=//etc/todos getting-started
Überprüfen, ob die Daten erhalten bleiben
- Sobald der Container hochgefahren ist, öffnen Sie die Anwendung und fügen Sie Ihrer ToDo-Liste einige Einträge hinzu
- Stoppen und entfernen Sie den Container für die Todo-App. Verwenden Sie Docker Desktop oder
docker ps, um die ID zu ermitteln, und danndocker rm -f <id>, um ihn zu entfernen. - Starten Sie einen neuen Container unter Verwendung der vorherigen Schritte
- Öffnen Sie die App. Sie sollten Ihre Objekte immer noch in Ihrer Liste sehen
- Entfernen Sie den Container, wenn Sie mit dem Auschecken Ihrer Liste fertig sind
volume inspect
Um herauszufinden, wo Docker die Dateien eines bestimmten Volumes speichert, kann man den Befehl docker volume inspect verwenden.
docker volume inspect todo-db
Sie sollten eine Ausgabe wie die folgende sehen:
[
{
"CreatedAt": "2019-09-26T02:18:36Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Optionen": {},
"Scope": "local"
}
]
Der Mountpoint ist der tatsächliche Speicherort der Daten auf der Festplatte.
- Hinweis
- Beachten Sie, dass Sie auf den meisten Rechnern über Root-Zugriff verfügen müssen, um vom Host aus auf dieses Verzeichnis zuzugreifen
Zusammenfassung
In diesem Abschnitt haben Sie gelernt, wie man Containerdaten persistiert
07 Mounts
Docker/Mounts Skript/Docker
Beschreibung
- Datenbank persistieren
- Änderungen an Anwendungen während der Entwicklung sehen, ohne das Image neu zu erstellenIm nächsten Abschnitt
- Volume-Mounts und Bind-Mounts unterstützt Docker auch andere Mount-Typen und Speichertreiber
- um komplexere und spezialisierte Anwendungsfälle zu behandeln
Mounts
- Bind Mounts
Methode in Docker, bei der ein Verzeichnis oder eine Datei vom Hostsystem in einen Container eingebunden wird
- Dabei verwendet der Container die echten Daten vom Host, und Änderungen im Container wirken sich unmittelbar auf den Host aus (und umgekehrt)
- Verwenden von Bind Mounts

Im vorherigen Abschnitt haben Sie ein Volume Mount verwendet, um die Daten in Ihrer Datenbank zu speichern Bind Mounts werden ebenfalls verwendet und weisen einige Besonderheiten auf:
- Ein Bind Mount verbindet ein echtes Verzeichnis oder eine Datei vom Host-System direkt mit einem Container
- Im Gegensatz zu einem Volume Mount werden die Daten physisch auf dem Host an dem angegebenen Pfad gespeichert und nicht im von Docker verwalteten Speicher
- Änderungen, die im Container vorgenommen werden, sind sofort auf dem Host sichtbar – und umgekehrt
- Diese Methode eignet sich besonders für Entwicklung und Debugging, wenn es wichtig ist, Codeänderungen sofort zu sehen, ohne das Image neu zu bauen
- Bind Mount hängt von der Dateistruktur und den Pfaden des Hostsystems ab, was die Portabilität der Container verringert
Im Folgenden wird die Verwendung von Bind Mounts und des Tools nodemon beschrieben, um Dateiänderungen zu überwachen und die Anwendung automatisch neu zu starten
Vergleiche von Volume-Typen
- Beispiele
| Benanntes Volume | type=volume,src=my-volume,target=/usr/local/data |
| Bind-Mount | type=bind,src=/path/to/data,target=/usr/local/data |
- Unterschiede Volume-Einhängungen und Bind-Einhängungen
| Benannte Volumes | Bind-Mounts | |
|---|---|---|
| Speicherort des Hosts | Docker wählt aus | Sie entscheiden |
| Füllt das neue Volume mit Containerinhalten | Ja | Nein |
| Unterstützt Volume-Treiber | Ja | Nein |
Bind-Mounts
Um mit Bind Mounts zu arbeiten, kann ein kurzes Experiment durchgeführt werden, um das Funktionsprinzip praktisch zu verstehen
1. In das Verzeichnis getting-started-app wechseln
2. Den folgenden Befehl ausführen, um Bash in einem Ubuntu-Container mit einem Bind Mount zu starten
docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
- Die Option
--mount type=bindweist Docker an, einen Bind-Mount zu erstellen, wobeisrcdas aktuelle Arbeitsverzeichnis auf dem Host-Rechner (getting-started-app) undtargetdas Verzeichnis ist, das im Container erscheinen soll (/src)
3. Nach dem Ausführen des Befehls startet Docker eine interaktive Bash-Sitzung im Stammverzeichnis des Dateisystems des Containers
pwd; ls
bin dev home media opt root sbin srv tmp var boot etc lib mnt proc run src sys usr
4. Wechseln Sie in das src-Verzeichnis
- Dies ist das Verzeichnis, das Sie beim Start des Containers gemountet haben
- Wenn Sie den Inhalt dieses Verzeichnisses auflisten, werden die gleichen Dateien angezeigt wie im Verzeichnis getting-started-app auf Ihrem Host-Rechner
cd src; ls
Dockerfile node_modules package.json spec src yarn.lock
5. Erstellen Sie eine neue Datei namens myfile.txt
touch myfile.txt; ls
Dockerfile myfile.txt node_modules package.json spec src yarn.lock
6. Öffnen Sie das Verzeichnis getting-started-app auf dem Host und stellen Sie fest, dass sich die Datei myfile.txt in diesem Verzeichnis befindet
├── getting-started-app/
│ ├── Dockerdatei
│ ├── meineDatei.txt
│ ├── node_modules/
│ ├── package.json
│ ├── spec/
│ ├── src/
│ └── yarn.lock
- Löschen Sie auf dem Host die Datei
myfile.txt - Listen Sie im Container noch einmal den Inhalt des
app-Verzeichnisses auf - Stellen Sie fest, dass die Datei jetzt verschwunden ist
ls
Dockerfile node_modules package.json spec src yarn.lock
7. Beenden Sie die interaktive Containersitzung mit Strg + D
Entwicklungscontainer
- Die Verwendung von Bind-Mounts ist für lokale Entwicklungsumgebungen üblich
- Der Vorteil ist, dass auf dem Entwicklungsrechner nicht alle Build-Tools und Umgebungen installiert sein müssen
- Mit einem einzigen Docker-Run-Befehl ruft Docker die Abhängigkeiten und Tools ab
Ausführen Anwendung
- Ausführen Anwendung in einem Entwicklungscontainer
Die folgenden Schritte beschreiben, wie man einen Entwicklungscontainer mit einem Bind-Mount ausführt, der die folgenden Aufgaben erfüllt
- Binden Sie Ihren Quellcode in den Container ein
- Installieren aller Abhängigkeiten
- Starten von nodemon, um auf Änderungen im Dateisystem zu achten
- Vergewissern Sie sich, dass derzeit keine Getting-Started-Container laufen
1. Führen Sie den folgenden Befehl aus dem get-started-app-Verzeichnis aus
docker run -dp 3000:3000 \
-w /app --mount type=bind,src="$(pwd)",target=/app \
node:18-alpine \
sh -c "yarn install && yarn run dev"
| Zeile | Parameter | Beschreibung |
|---|---|---|
| 1 | -dp 3000:3000 | Wird im abgetrennten Modus (im Hintergrund) ausgeführt und erstellt eine Port-Zuordnung |
| 2 | -w /app | Legt das "Arbeitsverzeichnis" oder das aktuelle Verzeichnis fest, von dem aus der Befehl ausgeführt werden soll |
| 3 | --mount type=bind,src="$(pwd)",target=/app | Bindet das aktuelle Verzeichnis vom Host in das /app-Verzeichnis im Container ein |
| 4 | node:18-alpine | Das zu verwendende Image
|
| 5 | sh -c "yarn install && yarn run dev" | Der Befehl
|
2. Sie können die Protokolle mit docker logs -f <container-id> einsehen
- Sie wissen, dass Sie bereit sind, wenn Sie dies sehen:
$ docker logs -f <container-id>
nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
3. Wenn Sie mit dem Betrachten der Protokolle fertig sind, beenden Sie diese mit Strg+ C
Entwickeln von Anwendungen
- Aktualisieren Sie Ihre Anwendung auf Ihrem Host-Rechner und sehen Sie sich die Änderungen im Container an
- Ändern Sie in der Datei src/static/js/app.js in Zeile 109 die Schaltfläche "Element hinzufügen" so, dass sie einfach "Hinzufügen" lautet:
- {submitting ? 'Adding...' : 'Add Item'}
+ {submitting ? 'Adding...' : 'Add'}
- Speichern Sie die Datei
- Aktualisieren Sie die Seite in Ihrem Webbrowser, und Sie sollten sehen, dass die Änderung aufgrund des Bind-Mounts fast sofort übernommen wird
- Nodemon erkennt die Änderung und startet den Server neu
- Es kann ein paar Sekunden dauern, bis der Node-Server neu gestartet ist
- Wenn Sie eine Fehlermeldung erhalten, versuchen Sie, die Seite nach ein paar Sekunden neu zu starten
- Sie können alle anderen Änderungen vornehmen, die Sie vornehmen möchten
- Jedes Mal, wenn Sie eine Änderung vornehmen und eine Datei speichern, wird die Änderung aufgrund des Bind-Mounts in den Container übernommen
- Wenn Nodemon eine Änderung feststellt, startet es die Anwendung innerhalb des Containers automatisch neu
Wenn Sie fertig sind, stoppen Sie den Container und erstellen Sie Ihr neues Image mit:
docker buildx build -t getting-started .
08 Multi-Container
Docker/Multi-Container Docker/Multi-Container - Multi-Container
Beschreibung
- Mehrcontainer-Anwendungen
Die Mehrcontainer-Architektur trennt Zuständigkeiten, vereinfacht den Betrieb und ermöglicht gezieltes Skalieren
- Datenbankkomponenten (z. B. MySQL) werden als separater Container ausgeführt
- Entwurfsprinzip
Ein Container = eine klar abgegrenzte Aufgabe
Anwendungsteile bleiben lose gekoppelt, Images bleiben kompakt und wartbar
- Vorteile
- API/Frontend und Datenbank haben unterschiedliche Lastprofile und werden unabhängig skaliert
- Anwendungs- und DB-Images werden getrennt gebaut, getestet und aktualisiert
- Lokal kann die Datenbank in einem Container laufen; in der Produktion kann dasselbe System einen verwalteten Datenbankdienst nutzen – ohne Änderungen am Anwendungs-Image
- Pro Container ein Hauptprozess
- Mehrere Prozesse erfordern einen Prozessmanager und erhöhen die Komplexität von Start/Shutdown
- Empfehlung
- MySQL separat betreiben und die Anwendung als Verbund miteinander gekoppelter Container ausführen
- So bleibt die Architektur verständlich, betrieblich robust und leicht anpassbar (Skalierung, Updates, Umgebungswechsel)
Jetzt haben Sie eine Anwendung, die ihre Daten in einer externen Datenbank speichert, die in einem separaten Container läuft
- Sie haben ein wenig über Container-Netzwerke und die Erkennung von Diensten mithilfe von DNS gelernt
Container-Vernetzung

- Standardmäßig sind Container isoliert und sehen weder Prozesse noch andere Container auf demselben Host
- Damit Container Daten austauschen können, benötigen sie ein gemeinsames Netzwerk
- Dazu müssen die Container in dasselbe Netzwerk eingebunden werden
MySQL starten
Es gibt zwei Möglichkeiten, einen Container in ein Netzwerk einzubinden
- Netzwerk beim Start des Containers zuweisen
- Bereits laufenden Container mit einem Netzwerk verbinden
In diesem Abschnitt wird zuerst ein Netzwerk erstellt und der MySQL-Container beim Start daran angeschlossen
- Erstellen Sie das Netzwerk
docker network create todo-app
- MySQL-Container starten und mit dem Netzwerk verbinden
- Dabei werden Umgebungsvariablen gesetzt, die MySQL für die Initialisierung verwendet
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:8.0
Im vorherigen Befehl sehen Sie die --network-alias-Flagge
- In einem späteren Abschnitt werden Sie mehr über dieses Flag erfahren.(!)
- Hinweis
- Der obige Befehl gibt das Volume todo-mysql-data an, das in /var/lib/mysql gemountet ist
- Docker erstellt das Volume automatisch, falls es zuvor nicht mit docker volume create erstellt wurde
- Überprüfung der Verbindung zur Datenbank
docker exec -it <mysql-container-id> mysql -u root -p
- Wenn die Passwortabfrage erscheint, geben Sie secret ein
- Führen Sie in der MySQL-Shell eine Liste der Datenbanken auf und überprüfen Sie, ob die Datenbank todos angezeigt wird
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.00 sec)
- Beenden Sie die MySQL-Shell, um zur Shell auf Ihrem Rechner zurückzukehren
mysql> exit
Sie haben jetzt eine todos-Datenbank und können sie benutzen
Verbindung zu MySQL herstellen
Nach dem Start des MySQL-Containers kann innerhalb desselben Docker-Netzwerks über DNS auf den Dienst zugegriffen werden (Hostname: mysql)
- Zur Überprüfung der Namensauflösung wird der Diagnose-Container nicolaka/netshoot verwendet
- Netshoot-Container im selben Netzwerk starten
docker run -it --network todo-app nicolaka/netshoot
- Im Container DNS-Auflösung für den Hostnamen mysql testen
dig mysql
Das Ergebnis sollte in etwa wie folgt aussehen:
; <<>> DiG 9.18.8 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32162
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mysql. IN A
;; ANSWER SECTION:
mysql. 600 IN A 172.23.0.2
;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Oct 01 23:47:24 UTC 2019
;; MSG SIZE rcvd: 44
- Im ANSWER SECTION erscheint ein A-Record für mysql, der auf 172.23.0.2 zeigt (die tatsächliche IP kann abweichen)
- Die Auflösung erfolgt über den Docker-internen DNS-Resolver, weil dem MySQL-Container zuvor der Netzwerkalias --network-alias mysql zugewiesen wurde
- Docker-DNS läuft typischerweise unter 127.0.0.11 und löst Service-/Aliasnamen netzwerkintern
- mysql ist außerhalb des Docker-Netzwerks kein gültiger FQDN, innerhalb des Netzwerks jedoch als Alias nutzbar
Anwendungen im selben Docker-Netzwerk verbinden sich daher einfach mit dem Hostnamen mysql
Starten Sie Ihre Anwendung mit MySQL
Die todo-App unterstützt das Setzen einiger Umgebungsvariablen, um die MySQL-Verbindungseinstellungen festzulegen
- Diese sind
| Parameter | Beschreibung |
|---|---|
| MYSQL_HOST | der Hostname für den laufenden MySQL-Server |
| MYSQL_USER | der Benutzername, der für die Verbindung verwendet werden soll |
| MYSQL_PASSWORD | das Passwort, das für die Verbindung verwendet werden soll |
| MYSQL_DB | die zu verwendende Datenbank nach der Verbindung |
- Sicherheitshinweis
- Während die Verwendung von env vars zur Festlegung von Verbindungseinstellungen für die Entwicklung allgemein akzeptiert wird, wird davon dringend abgeraten, wenn Anwendungen in Produktion laufen
- Ein sicherer Mechanismus besteht darin, die Unterstützung für Geheimnisse des Orchestrators zu nutzen (Docker Swarm Secrets, Kubernetes Secrets)
- In Laufzeit-Containern werden Geheimnisse i. d. R. als Dateien bereitgestellt
- Viele Images/Apps (u. a. MySQL und die Todo-App) unterstützen dazu Umgebungsvariablen mit dem Suffix _FILE, die auf eine Datei mit dem Wert verweisen
- Docker wertet _FILE nicht aus; die Anwendung muss die Variable lesen und den Dateiinhalt verwenden
- Für MySQL: MYSQL_PASSWORD_FILE statt MYSQL_PASSWORD
- Erstellen eines MYSQL-Containers
- Geben Sie jede der vorherigen Umgebungsvariablen an und verbinden Sie den Container mit Ihrem App-Netzwerk
- Stellen Sie sicher, dass Sie sich im Verzeichnis getting-started-app befinden, wenn Sie diesen Befehl ausführen
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -c "yarn install && yarn run dev"
- Wenn Sie sich die Logs für den Container ansehen (docker logs -f <container-id>), sollten Sie eine Meldung ähnlich der folgenden sehen, die anzeigt, dass die mysql-Datenbank verwendet wird
nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Connected to mysql db at host mysql
Listening on port 3000
- Öffnen Sie die Anwendung in Ihrem Browser und fügen Sie Ihrer ToDo-Liste ein paar Einträge hinzu
- Verbinden Sie sich mit der mysql-Datenbank und prüfen Sie, ob die Einträge in die Datenbank geschrieben werden
- Denken Sie daran, dass das Passwort geheim ist
docker exec -it <mysql-container-id> mysql -p todos
Und in der mysql-Shell führen Sie Folgendes aus:
mysql> select * from todo_items;
+--------------------------------------+--------------------+-----------+
| id | name | completed |
+--------------------------------------+--------------------+-----------+
| c906ff08-60e6-44e6-8f49-ed56a0853e85 | Tue erstaunliche Dinge! | 0 |
| 2912a79e-8486-4bc3-a4c5-460793a575ab | Sei fantastisch! | 0 |
+--------------------------------------+--------------------+-----------+
Deine Tabelle sieht anders aus, weil sie deine Artikel enthält
- Aber Sie sollten sie dort gespeichert sehen
Konfiguration
Dateien
| Datei | Beschreibung |
|---|---|
09 Compose
Docker/Compose Docker/Compose - Verwaltung mehrerer Container, die gemeinsam eine Anwendung bilden
Beschreibung
Docker Compose ist ein Werkzeug zur Definition und Verwaltung mehrerer Container, die gemeinsam eine Anwendung bilden.
Die gesamte Umgebung wird in einer compose.yaml-Datei beschrieben und kann mit einem einzigen Befehl gestartet oder gestoppt werden.
Der Vorteil von Compose besteht darin, dass Sie Ihren Anwendungsstack in einer Datei definieren können, diese im Stammverzeichnis Ihres Projekt-Repositorys aufbewahren können (es ist jetzt versionskontrolliert) und es anderen Personen leicht ermöglichen, zu Ihrem Projekt beizutragen.
- Jemand müsste nur Ihr Repository klonen und die Anwendung mit Compose starten.
- Tatsächlich gibt es auf GitHub/GitLab eine ganze Reihe von Projekten, die genau das tun
- Vorteile
- Deklarative, versionskontrollierbare Konfiguration in compose.yaml.
- Start, Stopp und Bereinigung des gesamten Stacks mit einem Befehl.
- Isolierung und Service-Discovery über benannte Netzwerke und Volumes.
- Skalierung und gemeinsame Log-Sicht pro Dienst.
In diesem Abschnitt wird Docker Compose vorgestellt
- Definition und Freigabe von Multi-Service-Anwendungen
Erstellen Sie die Compose-Datei
Erstellen Sie im Verzeichnis getting-started-app eine Datei namens compose.yaml
├── getting-started-app/
│ ├── Dockerdatei
│ ├── compose.yaml
│ ├── node_modules/
│ ├── package.json
│ ├── spec/
│ ├── src/
│ └── yarn.lock
Definieren Sie den Anwendungsdienst
In Teil 6 haben Sie den folgenden Befehl verwendet, um den Anwendungsdienst zu starten
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:lts-alpine \
sh -c "yarn install && yarn run dev"
In YAML sieht diese Konfiguration wie folgt aus:
services:
app:
image: node:lts-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
Definieren Sie den MySQL-Dienst
Nun ist es an der Zeit, den MySQL-Dienst zu definieren.
- Der Befehl, den Sie für diesen Container verwendet haben, war der folgende:
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:8.0
Zu diesem Zeitpunkt sollte Ihre komplette compose.yaml wie folgt aussehen:
services:
app:
image: node:lts-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
Parameter
Entsprechung zwischen Parametern von docker run und YAML-Direktiven in compose.yaml
- So kann nachvollzogen werden, wie Docker Compose die Einstellungen automatisch umsetzt
| YAML | docker run-Parameter | Beschreibung |
|---|---|---|
| Dienst: app | ||
| image: node:lts-alpine | node:lts-alpine |
Basis-Image. |
| command: sh -c "yarn install && yarn run dev" | sh -c "yarn install && yarn run dev" |
Startkommando (überschreibt CMD). |
| ports: 3000:3000 |
-p 3000:3000 |
Port-Mapping Host->Container. |
| working_dir: /app | -w /app |
Arbeitsverzeichnis im Container. |
| volumes: ./:/app |
-v "$(pwd):/app" |
Bind-Mount des Projektverzeichnisses. |
| environment: MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB | -e MYSQL_HOST=mysql-e MYSQL_USER=root-e MYSQL_PASSWORD=secret-e MYSQL_DB=todos |
Umgebungsvariablen für die App. |
| Dienst: mysql | ||
| image: mysql:8.0 | mysql:8.0 |
MySQL-Server-Image. |
| volumes: todo-mysql-data:/var/lib/mysql |
-v todo-mysql-data:/var/lib/mysql |
Benanntes Volume für persistente Daten. |
| environment: MYSQL_ROOT_PASSWORD, MYSQL_DATABASE | -e MYSQL_ROOT_PASSWORD=secret-e MYSQL_DATABASE=todos |
Initiale Datenbankparameter. |
| Servicename: mysql | --network-alias mysql |
DNS-Name im Container-Netzwerk (automatisch durch Servicenamen). |
| Top-Level | ||
| volumes: todo-mysql-data: |
— | Definition des benannten Volumes. |
Anwendungsstack starten
Nun, da Sie Ihre compose.yaml-Datei haben, können Sie Ihre Anwendung starten.
- Vergewissern Sie sich zunächst, dass keine anderen Kopien der Container ausgeführt werden.
- Verwenden Sie docker ps, um die Container aufzulisten und docker rm -f <ids>, um sie zu entfernen
- Starten Sie den Anwendungsstapel mit dem Befehl docker compose up.
- Fügen Sie das Flag -d hinzu, um alles im Hintergrund laufen zu lassen
docker compose up -d
- Wenn Sie den vorherigen Befehl ausführen, sollten Sie eine Ausgabe wie die folgende sehen
✔ Network getting-started-app_default Created 0.1s
✔ Volume getting-started-app_todo-mysql-data Created 0.0s
✔ Container getting-started-app-mysql-1 Started 0.3s
✔ Container getting-started-app-app-1 Started
Sie werden feststellen, dass Docker Compose sowohl das Volume als auch ein Netzwerk erstellt hat.
- Standardmäßig erstellt Docker Compose automatisch ein Netzwerk speziell für den Anwendungsstapel (deshalb haben Sie kein Netzwerk in der Compose-Datei definiert).
- Sehen Sie sich die Protokolle mit dem Befehl docker compose logs -f an.
- Sie werden sehen, dass die Protokolle der einzelnen Dienste in einen einzigen Stream verschachtelt sind.
- Dies ist sehr nützlich, wenn Sie auf zeitliche Probleme achten wollen.
- Die Markierung -f folgt dem Protokoll, so dass Sie eine Live-Ausgabe erhalten, während es erzeugt wird
Wenn Sie den Befehl bereits ausgeführt haben, werden Sie eine Ausgabe sehen, die wie folgt aussieht:
mysql_1 | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
mysql_1 | Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
app_1 | Connected to mysql db at host mysql
app_1 | Listening on port 3000
- Der Name des Dienstes wird am Anfang der Zeile angezeigt (oft farbig), um die Unterscheidung der Meldungen zu erleichtern.
- Wenn Sie die Protokolle für einen bestimmten Dienst anzeigen möchten, können Sie den Namen des Dienstes an das Ende des Befehls logs anhängen (z. B. docker compose logs -f app).
- Zu diesem Zeitpunkt sollten Sie in der Lage sein, Ihre App in Ihrem Browser auf http://<server_ip>:3000/ zu öffnen und zu sehen, dass sie läuft
Sehen Sie den App-Stack im Docker Desktop Dashboard
Im Docker Desktop Dashboard sehen Sie, dass es eine Gruppe namens getting-started-app gibt.
- Dies ist der Projektname von Docker Compose und wird verwendet, um die Container zusammenzufassen.
- Standardmäßig ist der Projektname einfach der Name des Verzeichnisses, in dem sich die compose.yaml befand
Wenn Sie den Stack erweitern, sehen Sie die beiden Container, die Sie in der Compose-Datei definiert haben.
- Die Namen sind auch etwas aussagekräftiger, da sie dem Muster <Service-Name>-<Replikat-Nummer> folgen.
- So ist es sehr einfach, schnell zu erkennen, welcher Container Ihre Anwendung und welcher Container die mysql-Datenbank ist
Alles abreißen
Wenn Sie bereit sind, alles abzubauen, führen Sie einfach docker compose down aus oder drücken Sie den Mülleimer im Docker Desktop Dashboard für die gesamte Anwendung.
- Die Container werden gestoppt und das Netzwerk wird entfernt
- Warnung
Standardmäßig werden benannte Volumes in Ihrer Compose-Datei nicht entfernt, wenn Sie docker compose down ausführen.
- Wenn Sie die Volumes entfernen möchten, müssen Sie das Flag --volumes hinzufügen
Das Docker Desktop Dashboard entfernt die Volumes nicht, wenn Sie den Anwendungsstapel löschen
Nächste Schritte
Anhang
Siehe auch
Dokumentation
Links
Projekt
Weblinks
10 Image-Erstellung
Docker/Image-Erstellung Docker/Image-Erstellung
11 Docker-Swarm
12 Ausblick
Docker/Ausblick Docker/Ausblick - Weitere Schritte und Bereiche
Beschreibung
Container-Orchestrierung
- Betrieb von Containern in der Produktion ist schwierig
- Sie wollen sich nicht in einen Rechner einloggen und einfach einen Docker-Run oder Docker-Compose ausführen
- Und warum nicht? Was passiert, wenn die Container sterben? Wie skalieren Sie über mehrere Rechner hinweg? Die Container-Orchestrierung löst dieses Problem
- Tools wie Kubernetes, Swarm, Nomad und ECS helfen alle bei der Lösung dieses Problems, alle auf leicht unterschiedliche Weise
- Manager
Die allgemeine Idee ist, dass Sie Manager haben, die den erwarteten Zustand erhalten
- Dieser Zustand könnte lauten: "Ich möchte zwei Instanzen meiner Webanwendung ausführen und Port 80 freigeben"
- Die Manager sehen sich dann alle Maschinen im Cluster an und delegieren die Arbeit an Arbeitsknoten
- Die Manager achten auf Änderungen (z. B&.nbsp;das Beenden eines Containers) und sorgen dann dafür, dass der tatsächliche Zustand dem erwarteten Zustand entspricht
Cloud Native Computing Foundation
- Projekte
Die CNCF ist eine herstellerneutrale Heimat für verschiedene Open-Source-Projekte, darunter Kubernetes, Prometheus, Envoy, Linkerd, NATS und andere
- Sie können die graduierten und inkubierten Projekte hier und die gesamte CNCF-Landschaft hier einsehen
- Es gibt eine Vielzahl von Projekten, die bei der Lösung von Problemen in den Bereichen Überwachung, Protokollierung, Sicherheit, Image-Registrierung, Messaging und mehr helfen
Container von Grund auf erstellen
Wenn Sie sehen möchten, wie Container von Grund auf gebaut werden, hat Liz Rice von Aqua Security einen fantastischen Vortrag, in dem sie einen Container von Grund auf in Go erstellt
- Obwohl der Vortrag nicht auf Netzwerke, die Verwendung von Images für das Dateisystem und andere fortgeschrittene Themen eingeht, gibt er einen tiefen Einblick in die Funktionsweise