Webinar-Reihe: Erstellen containerisierter Anwendungen

Einführung

Im letzten Tutorial, How to Install and Configure Docker, haben wir eine Methode zum Konvertieren von https: // www untersucht .digitalocean.com / community / tutorials / Wie installiere und konfiguriere ich Docker? # step-2-% E2% 80% 94-launching-containers [Docker containers] in https://www.digitalocean.com/ community / tutorials / installiere-und-konfiguriere-docker # step-4-% E2% 80% 94-building-images [Docker images]. Obwohl die von uns verwendete Methode funktioniert hat, ist sie nicht immer die optimale Methode zum Erstellen von Bildern.

In vielen Fällen möchten Sie vorhandenen Code in Container-Images einfügen und möchten einen wiederholbaren, konsistenten Mechanismus zum Erstellen von Docker-Images, die mit der neuesten Version Ihrer Codebasis synchronisiert sind.

Eine Dockerfile adressiert diese Anforderungen, indem eine deklarative und konsistente Methode zum Erstellen von Docker-Images bereitgestellt wird.

Außerdem möchten Sie manchmal ganze Anwendungen containerisieren, die aus mehreren heterogenen Containern bestehen, die gemeinsam bereitgestellt und verwaltet werden.

Docker Compose verwendet wie eine Docker-Datei einen deklarativen Ansatz, um eine Methode zum Definieren eines gesamten Technologie-Stacks einschließlich Netzwerk- und Speicheranforderungen bereitzustellen. Dies erleichtert nicht nur die Erstellung von Anwendungen in Containern, sondern auch deren Verwaltung und Skalierung.

In diesem Tutorial verwenden Sie eine Beispiel-Webanwendung, die auf Node.js und MongoDB basiert, um ein Docker-Image aus einer Docker-Datei zu erstellen erstellt ein benutzerdefiniertes Netzwerk, über das Ihre Docker-Container kommunizieren können, und Sie verwenden Docker Compose, um eine containerisierte Anwendung zu starten und zu skalieren.

Voraussetzungen

Um diesem Tutorial zu folgen, benötigen Sie:

Schritt 1 - Erstellen eines Images mit einer Docker-Datei

Wechseln Sie zunächst in Ihr Ausgangsverzeichnis und klonen Sie die Beispielwebanwendung dieses Lernprogramms mit official repository auf GitHub.

cd ~
git clone https://github.com/janakiramm/todo-app.git

Dadurch wird die Beispielanwendung in ein neues Verzeichnis mit dem Namen "+ todo-app +" kopiert.

Wechseln Sie zu "+ todo-app " und verwenden Sie " ls +", um den Inhalt des Verzeichnisses anzuzeigen.

cd todo-app
ls

Das neue Verzeichnis enthält zwei Unterverzeichnisse und zwei Dateien:

  • + app + - das Verzeichnis, in dem der Quellcode der Beispielanwendung gespeichert ist

  • + compose + - das Verzeichnis, in dem die Docker Compose-Konfigurationsdatei gespeichert ist

  • + Dockerfile + - Eine Datei, die Anweisungen zum Erstellen des Docker-Images enthält

  • + README.md + - Eine Datei, die eine einsatzige Zusammenfassung der Beispielanwendung enthält

Das Ausführen von + cat Dockerfile + zeigt uns Folgendes:

~ / todo-app / Dockerfile

FROM node:slim
LABEL maintainer = "[email protected]"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ./app/ ./
RUN npm install
CMD ["node", "app.js"]

Schauen wir uns den Inhalt dieser Datei genauer an:

  • + FROM + gibt das Basis-Image an, aus dem Sie das benutzerdefinierte Image erstellen. In diesem Beispiel basiert das Image auf + node: slim +, einem public Node.js image, das nur die minimalen Pakete enthält, die zum Ausführen von `+ node + erforderlich sind `.

  • + LABEL + ist ein Schlüsselwertpaar, das normalerweise zum Hinzufügen von beschreibenden Informationen verwendet wird. In diesem Fall enthält es die E-Mail-Adresse des Betreuers.

  • + RUN + führt Befehle innerhalb des Containers aus. Dazu gehören Aufgaben wie das Erstellen von Verzeichnissen und das Initialisieren des Containers durch Ausführen grundlegender Linux-Befehle. Der erste Befehl "+ RUN " in dieser Datei wird verwendet, um das Verzeichnis " / usr / src / app +" zu erstellen, das den Quellcode enthält.

  • + WORKDIR + definiert das Verzeichnis, in dem alle Befehle ausgeführt werden. Dies ist normalerweise das Verzeichnis, in das der Code kopiert wird.

  • + COPY + kopiert die Dateien vom Host-Computer in das Container-Image. In diesem Fall kopieren Sie das gesamte Verzeichnis "+ app +" in das Bild.

  • Der zweite Befehl + RUN + führt + npm install + aus, um die Abhängigkeiten der Anwendung zu installieren, wie in + package.json + definiert.

  • + CMD + führt den Prozess aus, der den Container am Laufen hält. In diesem Beispiel führen Sie "+ node " mit dem Parameter " app.js +" aus.

Jetzt ist es an der Zeit, das Image aus dem + Dockerfile zu ​​erstellen. Verwenden Sie den Schalter "+ -t +", um das Bild mit dem Registrierungsbenutzernamen, dem Bildnamen und einem optionalen Tag zu versehen.

docker build -t /todo-web .

Die Ausgabe bestätigt, dass das Bild "+ Erfolgreich erstellt +" und entsprechend gekennzeichnet ist.

Output from docker build -tSending build context to Docker daemon  8.238MB
Step 1/7 : FROM node:slim
---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "[email protected]"
---> Using cache
---> ab0e049cf6f8
Step 3/7 : RUN mkdir -p /usr/src/app
---> Using cache
---> 897176832f4d
Step 4/7 : WORKDIR /usr/src/app
---> Using cache
---> 3670f0147bed
Step 5/7 : COPY ./app/ ./
---> Using cache
---> e28c7c1be1a0
Step 6/7 : RUN npm install
---> Using cache
---> 7ce5b1d0aa65
Step 7/7 : CMD node app.js
---> Using cache
---> 2cef2238de24
2cef2238de24
/todo-web:latest

Wir können überprüfen, ob das Image erstellt wurde, indem wir den Befehl + docker images + ausführen.

docker images

Hier sehen wir die Größe des Bildes zusammen mit der Zeit, die seit seiner Erstellung vergangen ist.

Output from docker imagesREPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
/todo-web                                   latest              81f5f605d1ca        9 minutes ago       236MB

Da wir auch einen MongoDB-Container benötigen, um die Beispielwebanwendung auszuführen, lasst uns das auf unseren Computer übertragen.

docker pull mongo:latest

In der Ausgabe wird genau angegeben, welches Bild zusammen mit dem Download-Status abgerufen wurde.

Output from docker pulllatest: Pulling from library/mongo
Digest: sha256:18b239b996e0d10f4ce2b0f64db6f410c17ad337e2cecb6210a3dcf2f732ed82
Status: Downloaded newer image for mongo:latest

Wir haben jetzt alles, was wir zum Ausführen der Beispielanwendung benötigen. Erstellen wir also ein benutzerdefiniertes Netzwerk, über das unsere Container miteinander kommunizieren können.

Schritt 2 - Erstellen eines Netzwerks zum Verknüpfen von Containern

Wenn wir die Webanwendung und die Datenbankcontainer unabhängig voneinander mit dem Befehl + docker run + starten würden, könnten sie sich nicht finden.

Zeigen Sie den Inhalt der Datenbankkonfigurationsdatei der Webanwendung an, um zu sehen, warum.

cat app/db.js

Nach dem Import von Mongoose - einer MongoDB-Objektmodellierungsbibliothek für Node.js - und dem Definieren einer neuen https://www.digitalocean.com/community/tutorials/understanding-sql-and-nosql -Datenbanken-und-verschiedene-Datenbankmodelle [Datenbankschema] versucht die Webanwendung, unter dem Hostnamen + db + eine Verbindung zur Datenbank herzustellen, der noch nicht existiert.

~ / todo-app / app / db.js

var mongoose = require( 'mongoose' );
var Schema   = mongoose.Schema;

var Todo = new Schema({
   user_id    : String,
   content    : String,
   updated_at : Date
});

mongoose.model( 'Todo', Todo );

mongoose.connect( 'mongodb:///express-todo' );

Um sicherzustellen, dass Container, die zur selben Anwendung gehören, sich gegenseitig erkennen, müssen sie im selben Netzwerk gestartet werden.

Docker bietet die Möglichkeit, zusätzlich zu den während der Installation erstellten default networks benutzerdefinierte Netzwerke zu erstellen.

Sie können Ihre aktuell verfügbaren Netzwerke mit dem folgenden Befehl überprüfen:

docker network ls

Jedes von Docker erstellte Netzwerk basiert auf einem driver. In der folgenden Ausgabe sehen wir, dass das Netzwerk mit dem Namen "+ bridge " auf dem Treiber " bridge " basiert. Der Bereich " local +" gibt an, dass das Netzwerk nur auf diesem Host verfügbar ist.

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
5029df19d0cf
367330960d5c        host                host                local
f280c1593b89        none                null                local

Wir erstellen jetzt ein benutzerdefiniertes Netzwerk mit dem Namen "+ todo_net +" für unsere Anwendung und starten dann Container in diesem Netzwerk.

docker network create todo_net

Die Ausgabe gibt den Hash des erstellten Netzwerks an.

Output from docker network createC09f199809ccb9928dd9a93408612bb99ae08bb5a65833fefd6db2181bfe17ac

Listen Sie nun die verfügbaren Netzwerke erneut auf.

docker network ls

Hier sehen wir, dass + todo_net + einsatzbereit ist.

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
c51377a045ff        bridge              bridge              local
2e4106b07544        host                host                local
7a8b4801a712        none                null                local

Wenn Sie den Befehl + docker run + verwenden, können Sie jetzt mit dem Schalter + - network + auf dieses Netzwerk verweisen. Lassen Sie uns sowohl den Web- als auch den Datenbankcontainer mit bestimmten Hostnamen starten. Dadurch wird sichergestellt, dass die Container über diese Hostnamen miteinander verbunden werden können.

Starten Sie zunächst den MongoDB-Datenbankcontainer.

docker run -d \
--name=db \
--hostname=db \
--network=todo_net \
mongo

Bei näherer Betrachtung dieses Befehls sehen wir:

  • Der Schalter "+ -d +" führt den Container im Modus "https://docs.docker.com/engine/reference/run/#detached—​d[detached" aus.

  • Die Schalter "+ - name " und " - hostname " weisen dem Container einen benutzerdefinierten Namen zu. Der Schalter " - Hostname +" fügt auch einen Eintrag zum Dienst "https://docs.docker.com/engine/userguide/networking/configure-dns/[DNS" hinzu, der von Docker verwaltet wird. Dies hilft beim Auflösen des Containers nach Hostnamen.

  • Der Schalter "+ - network +" weist Docker Engine an, den Container in einem benutzerdefinierten Netzwerk anstelle des Standardbrückennetzwerks zu starten.

Wenn wir eine lange Zeichenfolge als Ausgabe des Befehls + docker run + sehen, können wir davon ausgehen, dass der Container erfolgreich gestartet wurde. Dies kann jedoch nicht garantieren, dass der Container tatsächlich ausgeführt wird.

Output docker runaa56250f2421c5112cf8e383b68faefea91cd4b6da846cbc56cf3a0f04ff4295

Stellen Sie mit dem Befehl + docker logs + sicher, dass der Container + db + aktiv ist.

docker logs db

Dies druckt die Containerprotokolle nach + stdout. Die letzte Zeile des Protokolls zeigt an, dass MongoDB bereit ist und auf Verbindungen wartet.

Output from docker logs2017-12-10T02:55:08.284+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=db
. . . .
2017-12-10T02:55:08.366+0000 I NETWORK  [initandlisten]  on port 27017

Starten Sie nun den Webcontainer und überprüfen Sie ihn. Dieses Mal schließen wir auch "+ - publish = 3000: 3000 " ein, wodurch der Host-Port " 3000 " in den Container-Port " 3000 +" veröffentlicht wird.

docker run -d \
--name=web \
--publish=3000:3000 \
--hostname=web \
--network=todo_net \
/todo-web

Sie erhalten wie zuvor eine lange Zeichenfolge als Ausgabe.

Stellen Sie außerdem sicher, dass dieser Container aktiv ist.

docker logs web

Die Ausgabe bestätigt, dass Express - das Node.js-Framework, auf dem unsere Testanwendung basiert - auf Port 3000 abhört.

Output from docker logsExpress server listening on port 3000

Stellen Sie sicher, dass der Webcontainer mit einem Befehl + ping + mit dem Datenbankcontainer kommunizieren kann. Dazu führen wir den Befehl + docker exec + in einem interaktiven (+ -i +) Modus aus, der an ein Pseudo-TTY (+ -t +) angehängt ist.

docker exec -it web ping db

Der Befehl erzeugt die Standardausgabe "+ ping +" und lässt uns wissen, dass die beiden Container miteinander kommunizieren können.

Output from docker exec -it web ping dbPING db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.210 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
...

Drücken Sie + STRG + C +, um den Befehl + ping + zu beenden.

Greifen Sie abschließend auf die Beispielanwendung zu, indem Sie Ihren Webbrowser auf "+ http: // your_server_ip: 3000 +" zeigen. Sie sehen eine Webseite mit einem Label, das * Containers Todo Example * enthält, sowie ein Textfeld, das eine Aufgabe zum Erledigen als Eingabe akzeptiert.

Um Namenskonflikte zu vermeiden, können Sie jetzt die Container stoppen und die Ressourcen mit den Befehlen + docker rm + und + docker network remove + bereinigen.

docker rm -f db
docker rm -f web
docker network remove todo_net

Derzeit verfügen wir über eine containerisierte Webanwendung, die aus zwei separaten Containern besteht. Im nächsten Schritt werden wir einen robusteren Ansatz untersuchen.

Schritt 3 - Bereitstellen einer Multi-Container-Anwendung

Obwohl wir verknüpfte Container starten konnten, ist dies nicht die eleganteste Art, mit Anwendungen mit mehreren Containern umzugehen. Wir brauchen eine bessere Möglichkeit, alle zugehörigen Container zu deklarieren und als eine logische Einheit zu verwalten.

Docker Compose ist ein Framework, das Entwicklern für den Umgang mit Anwendungen mit mehreren Containern zur Verfügung steht. Wie Dockefile ist es ein deklarativer Mechanismus, um den gesamten Stapel zu definieren. Wir werden jetzt unsere Anwendung Node.js und MongoDB in eine Docker Compose-basierte Anwendung konvertieren.

Beginnen Sie mit der Installation von Docker Compose.

sudo apt-get install -y docker-compose

Sehen wir uns die Datei "+ docker-compose.yaml " an, die sich im Verzeichnis " compose +" der Beispielwebanwendung befindet.

cat compose/docker-compose.yaml

Die Datei + docker-compose.yaml + fasst alles zusammen. Es definiert den MongoDB-Container im Block "+ db: ", den Node.js-Webcontainer im Block " web: " und das benutzerdefinierte Netzwerk im Block " networks: +".

Beachten Sie, dass wir mit der Direktive + build: ../.+ Compose auf + Dockerfile + im Verzeichnis + app + verweisen. Dadurch wird Compose angewiesen, das Image zu erstellen, bevor der Webcontainer gestartet wird.

~ / todo-app / compose / docker-compose.yml

version: '2'
services:
 db:
   image: mongo:latest
   container_name: db
   networks:
     - todonet
 web:
   build: ../.
   networks:
     - todonet
   ports:
    - "3000"
networks:
 todonet:
   driver: bridge

Wechseln Sie nun in das Verzeichnis "+ composer" und starten Sie die Anwendung mit dem Befehl "+ docker-compose up". Wie bei + docker run + startet der Schalter + -d + den Container im getrennten Modus.

cd compose
docker-compose up -d

In der Ausgabe wird berichtet, dass Docker Compose ein Netzwerk mit dem Namen "+ compose_todonet +" erstellt und beide Container darauf gestartet hat.

Output from docker-compose up -dCreating network "compose_todonet" with driver "bridge"
Creating db
Creating compose_web_1

Beachten Sie, dass wir die explizite Host-Port-Zuordnung nicht bereitgestellt haben. Dadurch wird Docker Compose gezwungen, einen zufälligen Port zuzuweisen, um die Webanwendung auf dem Host verfügbar zu machen. Wir können diesen Port finden, indem wir den folgenden Befehl ausführen:

docker ps

Wir sehen, dass die Webanwendung auf dem Host-Port "+ 32782 +" verfügbar ist.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
6700761c0a1e        compose_web         "node app.js"            2 minutes ago       Up 2 minutes        0.0.0.0:->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   2 minutes ago       Up 2 minutes        27017/tcp                 db

Überprüfen Sie dies, indem Sie in Ihrem Webbrowser zu "+ http: // your_server_ip: 32782 +" navigieren. Dadurch wird die Webanwendung so angezeigt, wie Sie sie am Ende des Links gesehen haben: # step-2-% E2% 80% 94-erstelle-ein-Netzwerk-zu-Link-Container [Schritt 2].

Schauen wir uns die Verwaltung und Skalierung unserer Anwendung an, während unsere Anwendung für mehrere Container in Docker Compose ausgeführt wird.

Schritt 4 - Verwalten und Skalieren der Anwendung

Mit Docker Compose können Sie auf einfache Weise zustandslose Webanwendungen skalieren. Wir können 10 Instanzen unseres "+ web +" - Containers mit einem einzigen Befehl starten.

docker-compose scale web=10

Mit der Ausgabe können wir beobachten, wie Instanzen in Echtzeit erstellt und gestartet werden.

Output from docker-compose scaleCreating and starting compose_web_2 ... done
Creating and starting compose_web_3 ... done
Creating and starting compose_web_4 ... done
Creating and starting compose_web_5 ... done
Creating and starting compose_web_6 ... done
Creating and starting compose_web_7 ... done
Creating and starting compose_web_8 ... done
Creating and starting compose_web_9 ... done
Creating and starting compose_web_10 ... done

Stellen Sie sicher, dass die Webanwendung auf 10 Instanzen skaliert ist, indem Sie "+ docker ps +" ausführen.

docker ps

Beachten Sie, dass Docker einen zufälligen Port zugewiesen hat, um jeden "+ web +" - Container auf dem Host freizulegen. Über jeden dieser Ports kann auf die Anwendung zugegriffen werden.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                     NAMES
cec405db568d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_9
56adb12640bb        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_10
4a1005d1356a        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_7
869077de9cb1        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_8
eef86c56d16f        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_4
26dbce7f6dab        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_5
0b3abd8eee84        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_3
8f867f60d11d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_6
36b817c6110b        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            7 minutes ago        Up 7 minutes        0.0.0.0:->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   7 minutes ago        Up 7 minutes        27017/tcp                 db

Mit demselben Befehl können Sie auch den Webcontainer skalieren.

docker-compose scale web=2

Dieses Mal werden die zusätzlichen Instanzen in Echtzeit entfernt.

Output from docker-composeStopping and removing compose_web_3 ... done
Stopping and removing compose_web_4 ... done
Stopping and removing compose_web_5 ... done
Stopping and removing compose_web_6 ... done
Stopping and removing compose_web_7 ... done
Stopping and removing compose_web_8 ... done
Stopping and removing compose_web_9 ... done
Stopping and removing compose_web_10 ... done

Überprüfen Sie abschließend die Instanzen erneut.

docker ps

Die Ausgabe bestätigt, dass nur noch zwei Instanzen vorhanden sind.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
36b817c6110b        compose_web         "node app.js"            3 minutes ago       Up 3 minutes        0.0.0.0:32787->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            9 minutes ago       Up 9 minutes        0.0.0.0:32782->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   9 minutes ago       Up 9 minutes        27017/tcp                 db

Sie können die Anwendung jetzt beenden und wie zuvor auch die Ressourcen bereinigen, um Namenskonflikte zu vermeiden.

docker-compose stop
docker-compose rm -f
docker network remove compose_todonet

Fazit

Dieses Tutorial führte Sie in Dockerfiles und Docker Compose ein. Wir haben mit einer Docker-Datei als deklarativem Mechanismus zum Erstellen von Images begonnen und uns dann mit den Grundlagen der Docker-Vernetzung befasst. Schließlich haben wir Multi-Container-Anwendungen mit Docker Compose skaliert und verwaltet.

Um Ihr neues Setup zu erweitern, können Sie einen Nginx-Reverse-Proxy hinzufügen, der in einem anderen Container ausgeführt wird um Anforderungen an einen der verfügbaren Webanwendungscontainer weiterzuleiten. Alternativ können Sie DigitalOcean’s Block Storage und https://www.digitalocean.com/ nutzen. community / tutorials / eine-einführung-in-digitalocean-load-balancer [Load-Balancer], um den containerisierten Anwendungen Haltbarkeit und Skalierbarkeit zu verleihen.