Docker - Zusammenstellen von Projekten mit identischen Dienstnamen
Verwenden Sie den Docker-Compose Servicenamen nur, wenn sich der Service nur im internen Netzwerk des Docker-Compose Projekts befindet.
Wenn wir identische Docker-Compose Projekte mit identischen Servicenamen haben, die durch ein Docker Netzwerk verbunden sind, müssen wir sicherstellen, dass wir auf den richtigen Service zugreifen. In einem Docker -Netzwerk gibt es zwei Möglichkeiten für den Zugriff auf einen Dienst:
- Über den Dienstnamen
- Über den Containernamen
Ich habe mehrere Docker-Compose Projekte, die fast identisch sind, jedes Projekt befindet sich in seinem eigenen Verzeichnis und hat seine eigene Umgebung.
Ich nahm an, dass ein Service innerhalb eines Docker-Compose Projekts immer einen anderen Service innerhalb desselben Docker-Compose Projekts verwenden würde, wenn der Servicename (nicht der Containername) verwendet wird. Und dass er einen Fehler produzieren würde, wenn er nicht verfügbar wäre. Ich habe mich geirrt. Was tatsächlich passieren wird, ist, dass Sie auf den Dienst mit dem gleichen Namen in einem anderen Docker-Compose Projekt zugreifen können.
Wie immer habe ich dies auf Ubuntu 22.04 laufen lassen.
Projekt-Einrichtung
Wir haben zwei Verzeichnisse mit unseren (fast) identischen Projekten.
├── my_app1
│ ├── docker-compose.yml
│ └── .env
├── my_app2
│ ├── docker-compose.yml
│ └── .env
Die beiden 'docker-compose.yml'-Dateien sind identisch. Die '.env' Dateien sind anders, sie enthalten nur eine Umgebungsvariable, die 'COMPOSE_PROJECT_NAME'. Diese Variable wird nicht nur zur Erstellung der Containernamen verwendet, sondern auch innerhalb unserer Container, um das Projekt Docker-Compose zu identifizieren.
Wir verwenden hier die 'nicolaka/netshoot' Docker image . Es enthält viele nützliche Dienstprogramme, einschließlich eines funktionierenden 'netcat', 'nc', das wir zum Erstellen von Listener daemons verwenden.
Hier sind die Dateien:
# my_app1/.env
COMPOSE_PROJECT_NAME=my_app1
und
# my_app2/.env
COMPOSE_PROJECT_NAME=my_app2
und
# docker-compose.yml
version: '3.7'
x-service_defaults: &service_defaults
env_file:
- ./.env
restart: always
services:
app:
<< : *service_defaults
image: nicolaka/netshoot
command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - app:\" | /usr/bin/nc -l 80"
networks:
- internal_network
- app_network
web:
<< : *service_defaults
image: nicolaka/netshoot
command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"
networks:
- internal_network
- app_network
networks:
internal_network:
app_network:
external:
name: my_app_network
Bevor wir beginnen, erstellen wir das externe Docker -Netzwerk:
docker network create my_app_network
Durchführung einiger Prüfungen
Öffnen Sie einige Terminals und starten Sie beide Projekte, indem Sie diesen Befehl in jedem Verzeichnis ausführen:
docker-compose up
Überprüfen Sie, ob die folgenden Container erstellt wurden und ausgeführt werden:
my_app1_app_1
my_app1_web_1
my_app2_app_1
my_app2_web_1
Führen Sie nun in einem anderen Terminal aus:
docker run -it --network=my_app_network --rm busybox
Greifen Sie auf einen Dienst in unseren Containern zu, indem Sie den Containernamen verwenden:
telnet my_app_1_app_1 80
Die Antwort wird sein:
Connected to my_app1_app_1
From my_app1 - app:
Dies funktioniert wie erwartet. Geben Sie etwas Text ein. Dieser wird als Echo ausgegeben. Sie können dies auch im Terminal des Projekts 'my_app1' Docker-Compose überprüfen.
Generierung des Fehlers
Zunächst betreten wir den 'app' -Dienst des 'my_app1' -Projekts:
docker exec -it my_app1_app_1 bash
Nun greifen wir auf den Dienst 'web' im gleichen Projekt Docker-Compose zu, indem wir den Dienstnamen verwenden:
telnet web 81
Die Antwort lautet:
Connected to web
From my_app1 - web:
Perfekt, das ist das, was wir erwartet haben.
Lassen Sie uns nun den Dienst 'web' im Projekt 'my_app1' (vorübergehend) verschwinden. Dazu nehmen wir ihn herunter.
In einem anderen Terminal wechseln wir in das Verzeichnis 'my_app1' und geben ein:
docker-compose stop web
Jetzt greifen wir wieder auf den Dienst 'web' im selben Projekt zu:
telnet web 81
Die Antwort lautet:
Connected to web
From my_app2 - web:
Oh, oh. Jetzt greifen wir auf den Dienst 'web' in 'my_app2' zu, während wir auf den Dienst 'web' in 'my_app1' zugreifen wollten. Beachten Sie, dass es (viel) bessere, aber auch viel komplexere Möglichkeiten gibt, dies zu simulieren.
Lösungen
Hier gibt es zwei mögliche Lösungen, je nach Situation:
Lösung 1. Wenn der Dienst 'web' nicht extern sein muss, entfernen wir ihn aus dem externen Netz
Wir tun dies für beide Projekte (denken Sie daran, dass die Dateien "docker-compose.yml" identisch sind):
web:
<< : *service_defaults
image: nicolaka/netshoot
command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"
networks:
- internal_network
#- app_network
Fahren Sie die Container herunter und wieder hoch und stoppen Sie den Dienst 'web' des Projekts 'my_app1' wieder.
Wenn Sie nun versuchen, auf den Dienst 'web' zuzugreifen, siehe oben:
telnet web 81
Die Antwort wird nach einiger Zeit lauten:
telnet: bad address 'web'
Gut. Wir erhalten eine Fehlermeldung, wenn der Dienst nicht verfügbar ist.
Lösung 2. Wenn der 'web' -Dienst auch extern sein muss, verwenden wir immer den Containernamen des 'web' -Dienstes, wenn wir uns auf ihn beziehen, auch wenn wir uns im selben Docker-Compose-Projekt befinden.
Das ist nicht wirklich eine schöne Lösung, aber es gibt keine andere Möglichkeit. Wenn der 'app' -Dienst auf den 'web' -Dienst im selben Docker-Compose-Projekt zugreifen möchte, können wir den Containernamen mit Hilfe der Variable 'COMPOSE_PROJECT_NAME' konstruieren:
container_name = <COMPOSE_PROJECT_NAME>_<service name>_1
Für den Dienst 'web' in 'my_app1':
web_container_name = my_app1_web_1
Zusammenfassung
Ich bin auf dieses Problem gestoßen, als ich von einem Container auf zwei Container umstieg. Seltsame Dinge begannen zu passieren, und Daten wurden zwischen den Containern vermischt. Nachdem ich das Problem gefunden hatte, simulierte ich es mit dem obigen Code. Dann habe ich es für mein Projekt behoben. Lektion gelernt: Niemals etwas annehmen.
Links / Impressum
Docker - Change pre-defined environment variables in Docker Compose
https://docs.docker.com/compose/environment-variables/envvars
nicolaka / netshoot
https://github.com/nicolaka/netshoot
Mehr erfahren
Docker Docker-compose
Neueste
- Ausblenden der Primärschlüssel der Datenbank UUID Ihrer Webanwendung
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas