Ich verwende Docker-Compose, um eine API mit einigen DBs und einem Seeder einzurichten. Bis vor ein paar Tagen hat alles einwandfrei funktioniert, aber jetzt kann ich die DB nicht mehr seeden.
Hier ist ein Beispiel für meinedocker-compose.ymlDatei:
version: '3'
services:
api:
image: <API image>
ports: {API_PORT}:5000 //Flask's default port
depends_on:
- db
db:
image: <DB image>
ports: {DB_PORT}:27017 //MongoDB Default port
db-seed:
image: <seeder image>
// pretty classic docker-compose file, nothing fancy
Die Sämaschine verwendet dieDocker-Netzwerk, um auf den API-Container zuzugreifen (http://api:80/) und säen Sie es. Das Skript des Seeders (in Python geschrieben) gibt jetzt jedoch einen Fehler zurück, wenn versucht wird, eine Verbindung zum API-Container herzustellen:
$> docker-compose up db-seed
<LOT OF ERRORS>...
requests.exceptions.ConnectionError: HTTPConnectionPool(host='api', port=80): Max retries exceeded with url: /ping (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f65e78a4310>: Failed to establish a new connection: [Errno 111] Connection refused'))
Es scheint, als könne der Seeder-Container nicht auf den DB-Container zugreifen. Was könnte die Ursache für diesen Fehler sein? Wie kann ich ihn beheben?
Hier ist dieDocker-Netzwerkinspektionmeines Netzwerks:
[{ "Name": "staging-sensei-api_default", "Id": "b5bd162d27f9a1addaacf1b0f2c09ad799d3ae195cc6e8c9cbb54bfffc27651c", "Created": "2019-07-22T14:18:05.080114521Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.26.0.0/16", "Gateway": "172.26.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "08672fe92d72b111f1a006a2ff20e885ef395a420525953b696672753cb73ff7": {
"Name": "com.frcyber.sensei.elasticsearch",
"EndpointID": "7ba9a1af1af5635d22c9cbd38fad8be222f351e5c0013f0280e2879cdd6e9e40",
"MacAddress": "02:42:ac:1a:00:03",
"IPv4Address": "172.26.0.3/16",
"IPv6Address": ""
},
"364f873d069e4ecd371cdd99ca952d1469ee875aacbf9ee2227bbf25ab65d841": {
"Name": "com.frcyber.sensei.api",
"EndpointID": "e5a3f4cd2099aff2a04efdeb7a5c5d0a8ade4248b76df048f20a8a75bf85ddba",
"MacAddress": "02:42:ac:1a:00:04",
"IPv4Address": "172.26.0.4/16",
"IPv6Address": ""
},
"f4bfaf323a8c8c6300156d3091ec70f091fc3492175bfa00faa1717e4f83d2a2": {
"Name": "com.frcyber.sensei.mongodb",
"EndpointID": "b5df4e0d3721ffe5cd28ce55f642e6a0bc7f5be1a12cc49bb2eb12a58eb82e7a",
"MacAddress": "02:42:ac:1a:00:02",
"IPv4Address": "172.26.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "staging-sensei-api",
"com.docker.compose.version": "1.24.0"
}
}
]
Außerdem habe ich herausgefunden, dass es funktioniert, wennAPI_PORTist auf 5000 eingestellt:
api:
ports: 5000:5000
Antwort1
In Anbetracht dessen, dass es in einem bestimmten Fall funktioniert, nämlich:
Außerdem habe ich herausgefunden, dass es funktioniert, wenn API_PORT auf 5000 eingestellt ist
api: ports: 5000:5000
Ich würde vorschlagen, dass das Problem nicht an Docker liegt, sondern daran, wie Sie Ihr Projekt einrichten. Dieser Vorschlag basiert auf einer Annahme meinerseits: Ihr DB-Seeder-Container verwendet den Wert in API_PORT
als Port, um eine Verbindung zum API-Container herzustellen (in Ihrem Beitrag nicht klar definiert, ich gehe davon aus, dass dies im Folgenden der Fall ist).
Da Ihr Python-Fehler "api"
als Host angezeigt wird, mit dem Sie eine Verbindung herstellen möchten, wäre dies DNS-mäßig gemäß Ihrer docker network inspect
Ausgabe gleichbedeutend mit IP 172.26.0.4. Auf dieser IP lauscht der Container auf Port 5000, unabhängig vom API_PORT
Wert (gemäß Ihrem Docker-Compose, da Sie den Port Ihres Hosts immer API_PORT
an den Port 5000 des Containers binden).
Das Merkwürdige ist, dass Sie sagten, es hätte vorher funktioniert, was aber nicht der Fall hätte sein dürfen, außer Sie hätten API_PORT
5000 gehabt.
Wenn Sie innerhalb des Docker-Netzwerks eine Verbindung über einen anderen Port herstellen möchten, müssen Sie entweder während der Build- oder Laufzeit etwas im Container ändern, und nicht nur den Port des Hosts, an den Sie die Bindung herstellen.
Ergänzung: Beispiel für „Konfigurierbarkeit“
Von deinerdocker-compose
version: '3'
services:
api:
image: <API image>
ports: "80:${API_PORT:-5000}" //Flask's default port
depends_on:
- db
environment:
- DB_PORT=${DB_PORT:-27017}
- API_PORT=${API_PORT:-5000}
db:
image: mongo:latest
command: --port ${DB_PORT:-27017}
db-seed:
image: <seeder image>
environment:
- API_PORT=${API_PORT:5000}
Dadurch wird Ihr DB-Port nicht für die Außenwelt Ihres Hosts sichtbar. Sie müssen sowohl API_PORT- als auch DB_PORT-Werte aus der Umgebung Ihrer Shell (oder .env-Datei) abrufen und sie wie folgt verwenden:
- Stellen Sie eine Verbindung zur API her mit
http(s)://api:$API_PORT
- Verbinden Sie sich mit dem Mongo über
db:$DB_PORT
- Starten Sie den CGI-Server, den Sie für Ihre API in der Produktion verwenden (Beispiel für
uwsgi
), mit API_PORT, beispielsweise am Ende desENTRYPOINT
Skripts Ihres API-Containers:
# Some other config / checks / setup at runtime
exec uwsgi --port "$API_PORT" [ OTHER_OPTIONS ... ] path/to/your/application.py