Debuggen und Beheben allgemeiner Docker-Probleme

Einführung

Mit Docker können Sie Ihre Anwendungen und Dienste ganz einfach in Container packen, sodass Sie sie überall ausführen können. Leider können Probleme auftreten, wenn Sie Ihr Image erstellen und alle Ebenen integrieren, die Ihre App benötigt, insbesondere, wenn Sie Docker-Bilder und -Container noch nicht kennen. Bei der Kommunikation mit anderen Containern können Tippfehler, Probleme mit Laufzeitbibliotheken und -modulen, Namenskollisionen oder Probleme auftreten.

In diesem Handbuch zur Fehlerbehebung für Docker-Neulinge werden Sie Probleme beim Erstellen von Docker-Images beheben, Namenskollisionen beim Ausführen von Containern beheben und Probleme beheben, die bei der Kommunikation zwischen Containern auftreten.

Voraussetzungen

Um dieses Tutorial abzuschließen, benötigen Sie

  • Docker auf einem Server oder Ihrem lokalen Computer installiert.

Um Docker auf einem Server zu installieren, folgen Sie den Anleitungen unter für CentOS 7 oder für Ubuntu 16.04.

Sie können die Docker-Website besuchen oder die offizielle Installationsdokumentation befolgen, um Docker auf Ihrem lokalen Computer zu installieren Maschine.

Schritt 1 - Beheben von Problemen mit der Docker-Datei

Am häufigsten treten Probleme auf, wenn Sie ein Docker-Image aus einer Docker-Datei erstellen. Klären wir vor dem Eintauchen den Unterschied zwischen Bildern und Containern.

  • Ein image ist eine schreibgeschützte Ressource, die Sie mit einer Konfigurationsdatei namens + Dockerfile + erstellen. Es ist das, was Sie über http://dockerhub.com [Docker Hub] oder Ihre private Registrierung versenden und freigeben.

  • Ein container ist eine Lese- und Schreibinstanz, die Sie aus dem von Ihnen erstellten Image erstellen.

Weitere Informationen zu diesen Konzepten finden Sie im Tutorial Docker Explained: Verwenden von Dockerfiles zum Automatisieren der Erstellung von Bildern.

Wenn Sie sich ein "+ Dockerfile " ansehen, können Sie den schrittweisen Prozess, den Docker verwendet, um das Bild zu erstellen, deutlich sehen, da jede Zeile im " Dockerfile +" einem Schritt im Prozess entspricht. Dies bedeutet im Allgemeinen, dass, wenn Sie einen bestimmten Schritt erreicht haben, alle vorherigen Schritte erfolgreich abgeschlossen wurden.

Lassen Sie uns ein kleines Projekt erstellen, um einige Probleme zu untersuchen, die bei einem Dockerfile auftreten können. Erstellen Sie ein "+ docker_image " - Verzeichnis in Ihrem Ausgangsverzeichnis und verwenden Sie " nano " oder Ihren bevorzugten Editor, um ein " Dockerfile +" in diesem Ordner zu erstellen

mkdir ~/docker_image
nano ~/docker_image/Dockerfile

Fügen Sie dieser neuen Datei den folgenden Inhalt hinzu:

~ / docker_image / Dockerfile

# base image
FROM debian:latest

# install basic apps
RUN aapt-get install -qy nano

In diesem Code ist ein absichtlicher Tippfehler. Kannst du es erkennen? Versuchen Sie, aus dieser Datei ein Image zu erstellen, um zu sehen, wie Docker mit einem fehlerhaften Befehl umgeht. Erstellen Sie das Image mit dem folgenden Befehl:

docker build -t my_image ~/docker_image

Diese Meldung wird in Ihrem Terminal angezeigt und weist auf einen Fehler hin:

OutputStep 2 : RUN aapt-get install -qy nano
 ---> Running in 085fa10ffcc2

Die Fehlermeldung am Ende bedeutet, dass ein Problem mit dem Befehl in Schritt 2 aufgetreten ist. In diesem Fall war es unser absichtlicher Tippfehler: Wir haben "+ aapt-get " anstelle von " apt-get +". Das bedeutete aber auch, dass der vorherige Schritt korrekt ausgeführt wurde.

Ändern Sie das + Dockerfile + und nehmen Sie die Korrektur vor:

Dockerfile

# install basic apps
RUN  install -qy nano

Führen Sie nun den Befehl + docker build erneut aus:

docker build -t my_image ~/docker_image

Und jetzt sehen Sie die folgende Ausgabe:

OutputSending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:latest
---> ddf73f48a05d
Step 2 : RUN apt-get install -qy nano
---> Running in 9679323b942f
Reading package lists...
Building dependency tree...

Nachdem der Tippfehler korrigiert wurde, wurde der Vorgang etwas beschleunigt, da Docker den ersten Schritt zwischengespeichert hat, anstatt das Basisimage erneut herunterzuladen. Aber wie Sie an der Ausgabe sehen können, haben wir einen neuen Fehler.

Die Debian-Distribution, die wir als Grundlage für unser Image verwendet haben, konnte den Texteditor "+ nano +" nicht finden, obwohl wir wissen, dass er in den Debian-Paket-Repositories verfügbar ist. Das Basisimage wird mit zwischengespeicherten Metadaten geliefert, z. B. Repositorys und Listen der verfügbaren Pakete. Es kann gelegentlich zu Cache-Problemen kommen, wenn sich die Live-Repositorys, aus denen Sie Daten abrufen, geändert haben.

Um dies zu beheben, ändern Sie die Docker-Datei, um eine Bereinigung und Aktualisierung der Quellen durchzuführen, _ bevor_ Sie neue Pakete installieren. Öffnen Sie die Konfigurationsdatei erneut:

nano ~/docker_image/Dockerfile

Fügen Sie der Datei die folgende hervorgehobene Zeile hinzu, über dem Befehl zum Installieren von + nano +:

~ / docker_image / Dockerfile

# base image
FROM debian:latest

# clean and update sources


# install basic apps
RUN apt-get install -qy nano

Speichern Sie die Datei und führen Sie den Befehl + docker build erneut aus:

docker build -t my_image ~/docker_image

Diesmal wird der Vorgang erfolgreich abgeschlossen.

OutputSending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:latest
---> a24c3183e910
Step 2 : RUN apt-get install -qy nano
---> Running in 2237d254f172
Reading package lists...
Building dependency tree...
Reading state information...
Suggested packages:
 spell
The following NEW packages will be installed:
 nano
...

---> 64ff1d3d71d6
Removing intermediate container 2237d254f172
Successfully built 64ff1d3d71d6

Mal sehen, was passiert, wenn wir Python 3 und den PostgreSQL-Treiber zu unserem Image hinzufügen. Öffnen Sie die + Dockerfile + erneut.

nano ~/docker_image/Dockerfile

Fügen Sie zwei neue Schritte hinzu, um Python 3 und den Python PostgreSQL-Treiber zu installieren:

~ / docker_image / Dockerfile

# base image
FROM debian:latest

# clean and update sources
RUN apt-get clean && apt-get update

# install basic apps
RUN apt-get install -qy nano

# install Python and modules

Speichern Sie die Datei, beenden Sie den Editor und erstellen Sie das Image erneut:

docker build -t my_image ~/docker_image

Wie Sie der Ausgabe entnehmen können, werden die Pakete korrekt installiert. Der Vorgang wird auch viel schneller abgeschlossen, da die vorherigen Schritte zwischengespeichert wurden.

OutputSending build context to Docker daemon 2.048 kB
Step 1 : FROM debian:latest
---> ddf73f48a05d
Step 2 : RUN apt-get clean && apt-get update
---> Using cache
---> 2c5013476fbf
Step 3 : RUN apt-get install -qy nano
---> Using cache
---> 4b77ac535cca
Step 4 : RUN apt-get install -qy python3
---> Running in 93f2d795fefc
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:
 krb5-locales libgmp10 libgnutls-deb0-28 libgssapi-krb5-2 libhogweed2
 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.4-2 libnettle4
 libp11-kit0 libpq5 libsasl2-2 libsasl2-modules libsasl2-modules-db
 libtasn1-6
Suggested packages:
 gnutls-bin krb5-doc krb5-user libsasl2-modules-otp libsasl2-modules-ldap
 libsasl2-modules-sql libsasl2-modules-gssapi-mit
 libsasl2-modules-gssapi-heimdal python-psycopg2-doc
The following NEW packages will be installed:
 krb5-locales libgmp10 libgnutls-deb0-28 libgssapi-krb5-2 libhogweed2
 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-2.4-2 libnettle4
 libp11-kit0 libpq5 libsasl2-2 libsasl2-modules libsasl2-modules-db
 libtasn1-6 python3-psycopg2
0 upgraded, 18 newly installed, 0 to remove and 0 not upgraded.
Need to get 5416 kB of archives.
After this operation, 10.4 MB of additional disk space will be used.

...

Processing triggers for libc-bin (2.19-18+deb8u6) ...
---> 978e0fa7afa7

Achten Sie genau auf die Docker-Ausgabe, um festzustellen, wo sich die Tippfehler befinden, und führen Sie Aktualisierungen zum Zeitpunkt der Erstellung und im Container durch, um sicherzustellen, dass Sie nicht durch zwischengespeicherte Paketlisten behindert werden.

Syntaxfehler und Caching-Probleme sind die häufigsten Probleme, die beim Erstellen eines Images in Docker auftreten können. Betrachten wir nun die Probleme, die beim Ausführen von Containern aus diesen Images auftreten können.

Schritt 2 - Beheben von Problemen mit der Container-Benennung

Wenn Sie mehr Container starten, werden Sie schließlich auf Namenskollisionen stoßen. Bei einer Namenskollision wird versucht, einen Container zu erstellen, der denselben Namen hat wie ein Container, der bereits auf Ihrem System vorhanden ist. Im Folgenden erfahren Sie, wie Sie mit dem Benennen, Umbenennen und Löschen von Containern richtig umgehen, um Kollisionen zu vermeiden.

Starten wir einen Container aus dem Image, das wir im vorherigen Abschnitt erstellt haben. In diesem Container wird ein interaktiver Bash-Interpreter ausgeführt, um die Dinge zu testen. Führen Sie den folgenden Befehl aus:

docker run -ti my_image bash

Wenn der Container gestartet wird, wird eine Root-Eingabeaufforderung angezeigt, die auf Anweisungen wartet:

Nachdem Sie einen laufenden Container haben, schauen wir uns an, auf welche Probleme Sie stoßen könnten.

Wenn Sie einen Container so ausführen, wie Sie es gerade getan haben, ohne explizit einen Namen festzulegen, weist Docker dem Container einen zufälligen Namen zu. Sie können alle ausgeführten Container und ihre entsprechenden Namen anzeigen, indem Sie den Befehl + docker ps + auf dem Docker-Host außerhalb des ausgeführten Containers ausführen.

Öffnen Sie ein neues Terminal auf dem Docker-Host und führen Sie den folgenden Befehl aus:

docker ps

Dieser Befehl gibt die Liste der ausgeführten Container mit ihren Namen aus, wie im folgenden Beispiel gezeigt:

OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
80a0ca58d6ec        my_image            "bash"              22 seconds ago      Up 28 seconds

Der Name "+ loving_brahmagupta +" in der vorherigen Ausgabe ist der Name, den Docker dem Container im vorherigen Beispiel automatisch zugewiesen hat. deine wird einen anderen Namen haben. Es ist in sehr einfachen Fällen in Ordnung, Docker einen Namen für Ihren Container zuweisen zu lassen, kann jedoch erhebliche Probleme bereiten. Bei der Bereitstellung müssen wir die Container konsistent benennen, damit wir sie referenzieren und einfach automatisieren können.

Um einen Namen für einen Container anzugeben, können wir entweder das Argument "+ - name +" verwenden, wenn wir den Container starten, oder wir können einen laufenden Container in einen aussagekräftigeren Container umbenennen.

Führen Sie den folgenden Befehl vom Docker-Host-Terminal aus:

docker rename  python_box

Dann listen Sie Ihre Container auf:

docker ps

Sie werden den Container "+ python_box +" in der Ausgabe sehen, was bestätigt, dass Sie den Container erfolgreich umbenannt haben:

OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
80a0ca58d6ec        my_image            "bash"              24 minutes ago      Up 24 minutes                           python_box

Um den Container zu schließen, geben Sie an der Eingabeaufforderung im Terminal, das den laufenden Container enthält, "+ exit +" ein:

exit

Wenn dies keine Option ist, können Sie den Container mit dem folgenden Befehl von einem anderen Terminal auf dem Docker-Host aus beenden:

docker kill python_box

Wenn Sie den Container auf diese Weise beenden, gibt Docker den Namen des Containers zurück, der gerade beendet wurde:

Outputpython_box

Um sicherzustellen, dass + python_box + nicht mehr existiert, listen Sie alle laufenden Container erneut auf:

docker ps

Wie erwartet ist der Container nicht mehr aufgeführt:

OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Sie könnten jetzt denken, Sie könnten einen anderen Container mit dem Namen "+ python_box +" starten, aber wir werden sehen, was passiert, wenn wir es versuchen.

Wir verwenden dieses Mal das Argument "+ - name +", um den Namen des Containers festzulegen:

docker run  -ti my_image bash
Outputdocker: Error response from daemon: Conflict. The name "/python_box" is already in use by container 80a0ca58d6ecc80b305463aff2a68c4cbe36f7bda15e680651830fc5f9dda772. You have to remove (or rename) that container to be able to reuse that name..
See 'docker run --help'.

Wenn Sie ein Image erstellen und den Namen eines vorhandenen Images wiederverwenden, wird das vorhandene Image überschrieben, wie Sie bereits gesehen haben. Container sind etwas komplizierter, da Sie einen bereits vorhandenen Container nicht überschreiben können.

Docker sagt, dass "+ python_box " bereits existiert, obwohl wir es gerade beendet haben und es nicht einmal mit " docker ps " aufgelistet ist. Es wird nicht ausgeführt, ist jedoch weiterhin verfügbar, falls Sie es erneut starten möchten. Wir haben es gestoppt, aber nicht entfernt. Der Befehl ` docker ps +` zeigt nur laufende Container an, nicht alle Container.

Um alle Docker-Container aufzulisten, die ausgeführt werden und andernfalls übergeben Sie das Flag + -a + (Alias ​​für + - all +) an + docker ps +:

docker ps -a

Nun erscheint unser + python_box + Container in der Ausgabe:

OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
80a0ca58d6ec        my_image            "bash"              12 minutes ago      Exited (137) 6 minutes ago

Der Container hat den Status "+ Exited (137) +". Aus diesem Grund sind wir auf das Namensproblem gestoßen, als wir versucht haben, einen neuen Container mit demselben Namen zu erstellen.

Wenn Sie einen Container vollständig entfernen möchten, verwenden Sie den Befehl + docker rm +. Führen Sie diesen Befehl in Ihrem Terminal aus:

docker rm python_box

Docker gibt erneut den Namen des gerade entfernten Containers aus:

Outputpython_box

Erstellen wir einen neuen Container mit dem Namen "+ python_box +", nachdem wir den vorherigen entfernt haben:

docker run --name python_box -ti my_image bash

Der Vorgang ist abgeschlossen und es wird erneut eine Root-Shell angezeigt:

Lassen Sie uns jetzt den Container töten und entfernen, damit wir in Zukunft keine Probleme mehr haben. Beenden Sie in einer anderen Terminal-Sitzung auf dem Docker-Host den Container und entfernen Sie ihn mit dem folgenden Befehl:

docker kill python_box && docker rm python_box

Wir haben zwei Befehle miteinander verkettet, sodass die Ausgabe den Containernamen zweimal anzeigt. Die erste Ausgabe bestätigt, dass wir den Container getötet haben, und die andere bestätigt, dass wir ihn entfernt haben.

Outputpython_box
python_box

Denken Sie bei Problemen mit Namen an + docker ps -a + und stellen Sie sicher, dass Ihre Container angehalten und entfernt werden, bevor Sie versuchen, sie mit demselben Namen neu zu erstellen.

Durch die Benennung von Containern können Sie Ihre Infrastruktur einfacher verwalten. Namen erleichtern auch die Kommunikation zwischen Containern, wie Sie als Nächstes sehen werden.

Schritt 3 - Beheben von Problemen mit der Containerkommunikation

Mit Docker können Sie auf einfache Weise mehrere Container instanziieren, sodass Sie in jedem Container unterschiedliche oder sogar redundante Dienste ausführen können. Wenn ein Dienst ausfällt oder beeinträchtigt wird, können Sie ihn einfach durch einen neuen ersetzen, während der Rest der Infrastruktur intakt bleibt. Möglicherweise treten jedoch Probleme auf, die dazu führen, dass diese Container miteinander kommunizieren.

Erstellen wir zwei Container, die kommunizieren, damit wir mögliche Kommunikationsprobleme untersuchen können. Wir erstellen einen Container, in dem Python mit unserem vorhandenen Image ausgeführt wird, und einen weiteren Container, in dem eine Instanz von PostgreSQL ausgeführt wird. Für diesen Container verwenden wir das offizielle PostgreSQL-Image von http://dockerhub.com [Docker Hub].

Erstellen wir zuerst den PostgreSQL-Container. Wir geben diesem Container einen Namen, indem wir das Flag "+ - name " verwenden, damit wir ihn beim Verknüpfen mit anderen Containern leicht identifizieren können. Wir nennen es " postgres_box +".

Zuvor, als wir einen Container starteten, lief er im Vordergrund und übernahm unser Terminal. Wir wollen den PostgreSQL Datenbank Container im Hintergrund starten, was wir mit dem + - detach + Flag machen können.

Schließlich führen wir anstelle von "+ bash " den Befehl " postgres +" aus, mit dem der PostgreSQL-Datenbankserver im Container gestartet wird.

Führen Sie den folgenden Befehl aus, um den Container zu starten:

docker run --name postgres_box --detach postgres

Docker lädt das Image von Docker Hub herunter und erstellt den Container. Anschließend wird die vollständige ID des Containers zurückgegeben, der im Hintergrund ausgeführt wird:

OutputUnable to find image 'postgres:latest' locally
latest: Pulling from library/postgres
6a5a5368e0c2: Already exists
193f770cec44: Pull complete
...
484ac0d6f901: Pull complete
Digest: sha256:924650288891ce2e603c4bbe8491e7fa28d43a3fc792e302222a938ff4e6a349
Status: Downloaded newer image for postgres:latest

Listen Sie die Container auf, um sicherzustellen, dass dieser neue Container ausgeführt wird:

docker ps

Die Ausgabe bestätigt, dass der Container "+ postgres_box " im Hintergrund ausgeführt wird, wodurch der Port " 5432 +", der PostgreSQL-Datenbankport, verfügbar gemacht wird:

OutputCONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS               NAMES
7a230b56cd64                    "/docker-entrypoint.s"   Less than a second ago   Up 2 seconds

Starten wir nun den Python-Container. Damit die Programme, die im Python-Container ausgeführt werden, die Dienste im Container "+ postgres_box " "sehen" können, müssen wir unseren Python-Container manuell mit dem Container " postgres_box " verknüpfen, indem wir das Argument " - link " verwenden. Um den Link zu erstellen, geben wir den Namen des Containers gefolgt vom Namen des Links an. Wir werden den Linknamen verwenden, um auf den Container " postgres_box +" innerhalb des Python-Containers zu verweisen.

Setzen Sie den folgenden Befehl ab, um den Python-Container zu starten:

docker run --name python_box --link  -ti my_image bash

Versuchen wir nun, eine Verbindung zu PostgreSQL über den Container "+ python_box +" herzustellen.

Wir haben zuvor "+ nano " im Container " python_box " installiert. Verwenden wir ihn also, um ein einfaches Python-Skript zum Testen der Verbindung zu PostgreSQL zu erstellen. Führen Sie im Terminal für den Container " python_box +" den folgenden Befehl aus:

nano pg_test.py

Fügen Sie der Datei dann das folgende Python-Skript hinzu:

pg_test.py

"""Test PostgreSQL connection."""
import psycopg2

conn = psycopg2.connect(user='postgres')
print(conn)

Speichern Sie die Datei und beenden Sie den Editor. Mal sehen, was passiert, wenn wir versuchen, über unser Skript eine Verbindung zur Datenbank herzustellen. Führen Sie das Skript in Ihrem Container aus:

python3 pg_test.py

Die angezeigte Ausgabe weist auf ein Problem bei der Verbindung mit der Datenbank hin:

OutputTraceback (most recent call last):
 File "pg_test.py", line 5, in <module>
   conn = psycopg2.connect(database="test", user="postgres", password="secret")
 File "/usr/lib/python3/dist-packages/psycopg2/__init__.py", line 164, in connect
   conn = _connect(dsn, connection_factory=connection_factory, async=async)
psycopg2.OperationalError:

Wir haben sichergestellt, dass der Container "+ postgres_box " ausgeführt wird, und wir haben ihn mit dem Container " python_box +" verknüpft. Was ist dann passiert? Nun, wir haben den Datenbankhost nie angegeben, als wir versuchten, eine Verbindung herzustellen, daher versucht Python, eine Verbindung zu einer lokal ausgeführten Datenbank herzustellen. Dies funktioniert nicht, da der Dienst nicht lokal ausgeführt wird, sondern in einem anderen Container, als ob Es war auf einem anderen Computer.

Sie können auf den verknüpften Container unter dem Namen zugreifen, den Sie beim Erstellen des Links festgelegt haben. In unserem Fall verwenden wir "+ postgres ", um auf den Container " postgres_box " zu verweisen, in dem unser Datenbankserver ausgeführt wird. Sie können dies überprüfen, indem Sie die Datei " / etc / hosts " im Container " python_box +" anzeigen:

cat /etc/hosts

Sie sehen alle verfügbaren Hosts mit ihren Namen und IP-Adressen. Unser + postgres + Server ist gut sichtbar.

Output127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

172.17.0.3      3053f74c8c13

Ändern wir also unser Python-Skript und fügen den Hostnamen hinzu. Öffne die Datei.

nano pg_test.py

Geben Sie dann den Host in der Verbindungszeichenfolge an:

/pg_test.py

"""Test PostgreSQL connection."""
import psycopg2

conn = psycopg2.connect( user='postgres')
print(conn)

Speichern Sie die Datei und führen Sie das Skript erneut aus.

python3 pg_test.py

Diesmal wird das Skript ohne Fehler abgeschlossen:

Output<connection object at 0x7f64caec69d8; dsn: 'user=postgres host=7a230b56cd64', closed: 0>

Denken Sie an die Containernamen, wenn Sie versuchen, eine Verbindung zu Diensten in anderen Containern herzustellen, und bearbeiten Sie Ihre Anmeldeinformationen, um auf die verknüpften Namen dieser Container zu verweisen.

Fazit

Wir haben nur die häufigsten Probleme behandelt, die bei der Arbeit mit Docker-Containern auftreten können, vom Erstellen von Images bis zum Bereitstellen eines Netzwerks von Containern.

Docker hat ein "+ - debug +" - Flag, das hauptsächlich für Docker-Entwickler gedacht ist. Wenn Sie jedoch mehr über Docker-Interna erfahren möchten, versuchen Sie, Docker-Befehle im Debug-Modus auszuführen, um eine ausführlichere Ausgabe zu erhalten:

docker -D [command] [arguments]

Während Container in Software schon länger existieren, existiert Docker selbst erst seit drei Jahren und kann recht komplex sein. Nehmen Sie sich Zeit, um sich mit den Begriffen und the ecosystem vertraut zu machen, und Sie werden sehen, wie einige Konzepte, die anfangs etwas fremd waren, funktionieren bald viel sinn machen.