Tutorial: Persistentes Speichern von Daten in einer Container-App mithilfe von Volumes in VS Code
In diesem Tutorial erfahren Sie, wie Sie Daten in einer Containeranwendung persistent speichern. Wenn Sie sie ausführen oder aktualisieren, sind die Daten weiterhin verfügbar. Es gibt zwei Haupttypen von Volumes, die zum persistenten Speichern von Daten verwendet werden. Dieses Tutorial konzentriert sich auf benannte Volumes.
Außerdem erfahren Sie mehr über Bindungsbereitstellungen, die den genauen Bereitstellungspunkt auf dem Host steuern. Sie können Bindungsbereitstellungen verwenden, um Daten persistent zu speichern, aber es können auch weitere Daten in Containern hinzugefügt werden. Wenn Sie an einer Anwendung arbeiten, können Sie eine Bindungsbereitstellung verwenden, um Quellcode in Container einzubinden, damit Codeänderungen erkannt werden können und darauf reagiert werden kann und damit Sie die Änderungen sofort sehen.
In diesem Tutorial werden auch das Schichten von Images, das Zwischenspeichern von Schichten und mehrstufige Builds eingeführt.
In diesem Tutorial lernen Sie Folgendes:
- Verstehen von Daten in mehreren Containern
- Persistentes Speichern von Daten mithilfe benannter Volumes
- Verwenden von Bindungsbereitstellungen
- Anzeigen der Imageschicht
- Cacheabhängigkeiten
- Informationen zu mehrstufigen Builds
Voraussetzungen
Dieses Tutorial stellt eine Fortsetzung des vorherigen Tutorials Erstellen und Freigeben einer Docker-App mit Visual Studio Code dar. Beginnen Sie mit diesem Tutorial, da dies die Voraussetzungen enthält.
Verstehen von containerübergreifenden Daten
In diesem Abschnitt starten Sie zwei Container und erstellen jeweils eine Datei pro Container. Die in einem Container erstellten Dateien sind in einem anderen Container nicht verfügbar.
Starten Sie einen
ubuntu
-Container mithilfe des folgenden Befehls:docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
Dieser Befehl ruft zwei Befehle mithilfe von
&&
auf. Im ersten Abschnitt wird eine einzelne zufällige Zahl ausgewählt und in/data.txt
geschrieben. Mit dem zweiten Befehl wird eine Datei überwacht, damit der Container weiter ausgeführt wird.Klicken Sie in VS Code im Bereich Docker mit der rechten Maustaste auf den Ubuntu-Container, und wählen Sie Attach Shell (Shell anfügen) aus.
Ein Terminal wird geöffnet, das eine Shell im Ubuntu-Container ausführt.
Führen Sie den folgenden Befehl aus, um den Inhalt der
/data.txt
-Datei anzuzeigen.cat /data.txt
Auf dem Terminal wird eine Zahl zwischen 1 und 10000 angezeigt.
Um dieses Ergebnis über die Befehlszeile anzuzeigen, rufen Sie die Container-ID mit dem Befehl
docker ps
ab, und führen Sie den folgenden Befehl aus.docker exec <container-id> cat /data.txt
Starten Sie einen weiteren
ubuntu
-Container.docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
Verwenden Sie diesen Befehl, um den Inhalt des Ordners anzuzeigen.
docker run -it ubuntu ls /
Es sollte hier keine
data.txt
-Datei vorhanden sein, da sie nur für den ersten Container in den temporären Speicher geschrieben wurde.Wählen Sie diese beiden Ubuntu-Container aus. Klicken Sie mit der rechten Maustaste, und wählen Sie Entfernen aus. Über die Befehlszeile können Sie sie mit dem Befehl
docker rm -f
entfernen.
Persistentes Speichern Ihrer To-do-Daten mit benannten Volumes
Die Aufgabenlisten-App speichert Daten standardmäßig in einer SQLite-Datenbank unter /etc/todos/todo.db
.
SQLite Database ist eine relationale Datenbank, die Daten in einer einzelnen Datei speichert.
Dieser Ansatz funktioniert für kleine Projekte.
Sie können die einzelne Datei auf dem Host persistent speichern. Wenn Sie sie für den nächsten Container verfügbar machen, kann die Anwendung dort weitermachen, wo sie zuvor aufgehört hat. Indem Sie ein Volume erstellen und an den Ordner anfügen oder einbinden, in dem die Daten gespeichert sind, können Sie die Daten persistent speichern. Der Container schreibt in die Datei todo.db, und diese Daten verbleiben auf dem Host im Volume.
Verwenden Sie für diesen Abschnitt ein benanntes Volume. Docker verwaltet den physischen Speicherort des Volumes auf dem Datenträger. Verweisen Sie auf den Namen des Volumes, und Docker stellt die richtigen Daten bereit.
Erstellen Sie mithilfe des Befehls
docker volume create
ein Volume.docker volume create todo-db
Wählen Sie getting-started unter CONTAINER aus, und klicken Sie mit der rechten Maustaste darauf. Wählen Sie Beenden aus, um den App-Container zu beenden.
Verwenden Sie den Befehl
docker stop
, um den Container über die Befehlszeile zu beenden.Starten Sie den Container getting-started, indem Sie den folgenden Befehl verwenden.
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
Der Volume-Parameter gibt einzubindende Volume und den Speicherort
/etc/todos
an.Aktualisieren Sie Ihren Browser, um die App erneut zu laden. Wenn Sie das Browserfenster geschlossen haben, wechseln Sie zu
http://localhost:3000/
. Fügen Sie Ihrer Aufgabenliste einige Elemente hinzu.Entfernen Sie den Container getting-started für die To-do-App. Klicken Sie entweder im Docker-Bereich mit der rechten Maustaste auf den Container, und wählen Sie Entfernen aus, oder verwenden Sie die Befehle
docker stop
unddocker rm
.Starten Sie mithilfe desselben Befehls einen neuen Container:
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
Dieser Befehl bindet dasselbe Laufwerk wir zuvor ein. Aktualisieren Sie Ihren Browser. Die Elemente, die Sie hinzugefügt haben, befinden sich noch auf Ihrer Liste.
Entfernen Sie den Container getting-started erneut.
Benannte Volumes und Bindungsbereitstellungen, die unten erläutert werden, sind die Haupttypen von Volumes, die von einer Standardinstallation der Docker-Engine unterstützt werden.
Eigenschaft | Benannte Volumes | Binden von Bereitstellungen |
---|---|---|
Hoststandort | Wird von Docker ausgewählt | Wird von Ihnen bestimmt |
Beispiel für Volumebereitstellung (mithilfe von -v ) |
my-volume:/usr/local/data | /path/to/data:/usr/local/data |
Auffüllen des neuen Volumes mit Containerinhalten | Ja | Nein |
Unterstützung für Volumetreiber | Ja | Nein |
Es gibt viele Volumetreiber-Plug-Ins zur Unterstützung von NFS, SFTP, NetApp und mehr. Diese Plug-Ins sind besonders wichtig, um Container auf mehreren Hosts in einer Clusterumgebung wie Swarm oder Kubernetes ausführen zu können.
Wenn Sie sich fragen, wo Docker Ihre Daten tatsächlich speichert, führen Sie den folgenden Befehl aus.
docker volume inspect todo-db
Sehen Sie sich die Ausgabe an, die diesem Ergebnis ähnelt.
[
{
"CreatedAt": "2019-09-26T02:18:36Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": {},
"Scope": "local"
}
]
Mountpoint
entspricht dem tatsächlichen Speicherort, an dem die Daten gespeichert werden.
Auf den meisten Computern benötigen Sie Stammzugriff, um vom Host aus auf dieses Verzeichnis zugreifen zu können.
Verwenden von Bindungsbereitstellungen
Mithilfe von Bindungsbereitstellungen können Sie den exakten Bereitstellungspunkt auf dem Host bestimmen. Bei diesem Ansatz werden Daten persistent gespeichert, er wird aber häufig verwendet, um mehr Daten in Containern zur Verfügung zu stellen. Sie können eine Bindungsbereitstellung verwenden, um Quellcode in Container einzubinden, damit Codeänderungen erkannt werden können und darauf reagiert werden kann und damit Sie die Änderungen sofort sehen.
Wenn Sie einen Container so ausführen möchten, dass ein Entwicklungsworkflow unterstützt wird, müssen Sie die folgenden Schritte ausführen:
Entfernen Sie alle
getting-started
-Container.Führen Sie im
app
-Ordner den folgenden Befehl aus.docker run -dp 3000:3000 -w /app -v ${PWD}:/app node:20-alpine sh -c "yarn install && yarn run dev"
Dieser Befehl enthält die folgenden Parameter.
-dp 3000:3000
: Wie zuvor. Führen Sie ihn im getrennten Modus aus, und erstellen Sie eine Portzuordnung.-w /app
: Arbeitsverzeichnis im Container.-v ${PWD}:/app"
: Hier wird eine Bindungsbereitstellung für das aktuelle Verzeichnis vom Host im Container in das/app
-Verzeichnis durchgeführt.node:20-alpine
: Dies ist das zu verwendende Image. Bei diesem Image handelt es sich um das Basisimage für Ihre App aus dem Dockerfile.sh -c "yarn install && yarn run dev"
: Dies ist ein Befehl. Er startet eine Shellsh
mit und führtyarn install
aus, um alle Abhängigkeiten zu installieren. Anschließend wirdyarn run dev
ausgeführt. Wenn Sie diepackage.json
-Datei genauer ansehen, wirdnodemon
vom Skriptdev
gestartet.
Mithilfe von
docker logs
können Sie sich die Protokolle ansehen.docker logs -f <container-id>
$ nodemon 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
Wenn der endgültige Eintrag in dieser Liste angezeigt wird, wird die App ausgeführt.
Wenn Sie sich die Protokolle angesehen haben, wählen Sie einen beliebigen Schlüssel im Terminalfenster aus, oder drücken Sie STRG+C in einem externen Fenster.
Öffnen Sie in VS Code src/static/js/app.js. Ändern Sie den Text der Schaltfläche Element hinzufügen in Zeile 109.
- {submitting ? 'Adding...' : 'Add Item'} + {submitting ? 'Adding...' : 'Add'}
Speichern Sie die Änderung.
Aktualisieren Sie Ihren Browser. Daraufhin sollte die Änderung angezeigt werden.
Anzeigen von Imageschichten
Sie können sich die Schichten ansehen, die ein Image bilden.
Führen Sie den docker image history
-Befehl aus, um den Befehl anzuzeigen, der verwendet wurde, um die einzelnen Schichten eines Images zu erstellen.
Verwenden Sie
docker image history
, um die Schichten im Image getting-started anzuzeigen, das Sie zuvor im Tutorial erstellt haben.docker image history getting-started
Das Ergebnis sollte folgender Ausgabe ähneln.
IMAGE CREATED CREATED BY SIZE COMMENT a78a40cbf866 18 seconds ago /bin/sh -c #(nop) CMD ["node" "/app/src/ind… 0B f1d1808565d6 19 seconds ago /bin/sh -c yarn install --production 85.4MB a2c054d14948 36 seconds ago /bin/sh -c #(nop) COPY dir:5dc710ad87c789593… 198kB 9577ae713121 37 seconds ago /bin/sh -c #(nop) WORKDIR /app 0B b95baba1cfdb 13 days ago /bin/sh -c #(nop) CMD ["node"] 0B <missing> 13 days ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B <missing> 13 days ago /bin/sh -c #(nop) COPY file:238737301d473041… 116B <missing> 13 days ago /bin/sh -c apk add --no-cache --virtual .bui… 5.35MB <missing> 13 days ago /bin/sh -c #(nop) ENV YARN_VERSION=1.21.1 0B <missing> 13 days ago /bin/sh -c addgroup -g 1000 node && addu… 74.3MB <missing> 13 days ago /bin/sh -c #(nop) ENV NODE_VERSION=12.14.1 0B <missing> 13 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 13 days ago /bin/sh -c #(nop) ADD file:e69d441d729412d24… 5.59MB
Jede der Zeilen steht für eine Schicht des Images. Die Ausgabe hier zeigt die Basis ganz unten, die neueste Schicht wird ganz oben angezeigt. Mithilfe dieser Informationen können Sie sich auch die Größe der einzelnen Schichten ansehen, was bei der Diagnose großer Images hilft.
Einige der Zeilen werden abgeschnitten. Wenn Sie den
--no-trunc
-Parameter hinzufügen, erhalten Sie die vollständige Ausgabe.docker image history --no-trunc getting-started
Cacheabhängigkeiten
Sobald eine Schicht geändert wird, müssen alle Schichten, die sich unter dieser befinden, ebenfalls neu erstellt werden. Hier sehen Sie erneut das Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "/app/src/index.js"]
Jeder Befehl im Dockerfile wird zu einer neuen Schicht im Image.
Um die Anzahl der Schichten zu minimieren, können Sie Ihren Dockerfile neu strukturieren, um das Zwischenspeichern von Abhängigkeiten zu unterstützen.
Bei Node-basierten Anwendungen sind diese Abhängigkeiten in der package.json
-Datei definiert.
Der Ansatz sieht so aus, dass Sie zuerst nur diese Datei kopieren, die Abhängigkeiten installieren und dann den Rest kopieren.
In diesem Prozess werden die YARN-Abhängigkeiten nur erneut erstellt, wenn eine Änderung an package.json
vorgenommen wurde.
Aktualisieren Sie das Dockerfile, damit zuerst
package.json
kopiert wird, installieren Sie dann die Abhängigkeiten, und kopieren Sie dann den Rest. Dies ist die neue Datei:FROM node:20-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --production COPY . . CMD ["node", "/app/src/index.js"]
Erstellen Sie mithilfe von
docker build
ein neues Image.docker build -t getting-started .
Die Ausgabe sollte wie die folgenden Ergebnisse aussehen:
Sending build context to Docker daemon 219.1kB Step 1/6 : FROM node:12-alpine ---> b0dc3a5e5e9e Step 2/6 : WORKDIR /app ---> Using cache ---> 9577ae713121 Step 3/6 : COPY package* yarn.lock ./ ---> bd5306f49fc8 Step 4/6 : RUN yarn install --production ---> Running in d53a06c9e4c2 yarn install v1.17.3 [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@1.2.9: The platform "linux" is incompatible with this module. info "fsevents@1.2.9" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... [4/4] Building fresh packages... Done in 10.89s. Removing intermediate container d53a06c9e4c2 ---> 4e68fbc2d704 Step 5/6 : COPY . . ---> a239a11f68d8 Step 6/6 : CMD ["node", "/app/src/index.js"] ---> Running in 49999f68df8f Removing intermediate container 49999f68df8f ---> e709c03bc597 Successfully built e709c03bc597 Successfully tagged getting-started:latest
Alle Schichten wurden neu erstellt. Dieses Ergebnis wird erwartet, da Sie das Dockerfile geändert haben.
Nehmen Sie eine Änderung an src/static/index.html vor. Ändern Sie beispielsweise den Titel in „The Awesome Todo App“.
Erstellen Sie nun mithilfe von
docker build
das Docker-Image noch mal. Dieses Mal sollte Ihre Ausgabe etwas anders aussehen.Sending build context to Docker daemon 219.1kB Step 1/6 : FROM node:12-alpine ---> b0dc3a5e5e9e Step 2/6 : WORKDIR /app ---> Using cache ---> 9577ae713121 Step 3/6 : COPY package* yarn.lock ./ ---> Using cache ---> bd5306f49fc8 Step 4/6 : RUN yarn install --production ---> Using cache ---> 4e68fbc2d704 Step 5/6 : COPY . . ---> cccde25a3d9a Step 6/6 : CMD ["node", "/app/src/index.js"] ---> Running in 2be75662c150 Removing intermediate container 2be75662c150 ---> 458e5c6f080c Successfully built 458e5c6f080c Successfully tagged getting-started:latest
Da Sie den Buildcache verwenden, sollte der Vorgang viel schneller gehen.
Mehrstufige Builds
Mehrstufige Builds sind eine äußerst effiziente Methode, mit der Sie mehrere Stufen zum Erstellen eines Images verwenden können. Daraus entstehen mehrere Vorteile:
- Abgrenzen von Abhängigkeiten zur Buildzeit von Laufzeitabhängigkeiten
- Reduzieren der Imagegesamtgröße, indem nur geliefert wird, was die App für ihre Ausführung benötigt
Dieser Abschnitt enthält kurze Beispiele.
Maven/Tomcat-Beispiel
Wenn Sie Java-basierte Anwendungen erstellen, ist ein JDK erforderlich, um den Quellcode in Java-Bytecode zu kompilieren. Dieses JDK ist nicht für die Produktion erforderlich. Sie verwenden möglicherweise Tools wie Maven oder Gradle für die Erstellung der App. Diese Tools sind aber ebenfalls nicht für Ihr endgültiges Image erforderlich.
FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package
FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps
In diesem Beispiel wird eine Stufe namens build
verwendet, um den tatsächlichen Java-Buildvorgang mithilfe von Maven durchzuführen.
Die zweite Stufe (ab „FROM tomcat“) kopiert Dateien aus der build
-Stufe.
Beim endgültigen Image handelt es sich nur um die letzte Stufe, die erstellt wird. Diese kann jedoch mithilfe des --target
-Parameters überschrieben werden.
React-Beispiel
Für die Erstellung von React-Anwendungen benötigen Sie eine Node-Umgebung, um z. B. den JavaScript-Code und SASS-Stylesheets in statische HTML-, JavaScript- und CSS-Sprache zu kompilieren. Wenn Sie kein serverseitiges Rendering vornehmen, benötigen Sie auch keine Node-Umgebung für den Produktionsbuild.
FROM node:20-alpine AS build
WORKDIR /app
COPY package* yarn.lock ./
RUN yarn install
COPY public ./public
COPY src ./src
RUN yarn run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
In diesem Beispiel wird ein node:20
-Image verwendet, um den Build auszuführen, wodurch die Zwischenspeicherung von Schichten maximiert und anschließend die Ausgabe in einen nginx-Container kopiert wird.
Bereinigen von Ressourcen
Behalten Sie alles, was Sie bereits erarbeitet haben, so bei, um mit dieser Tutorialreihe fortzufahren.
Nächste Schritte
Sie haben die Optionen zum persistenten Speichern von Daten für Container-Apps kennengelernt.
Was möchten Sie als Nächstes tun?
Arbeiten mit mehreren Container mithilfe von Docker Compose:
Erstellen von Apps mit mehreren Containern mit MySQL und Docker Compose
Bereitstellen in Azure Container Apps:
Bereitstellen in Azure App Service
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für