Mam aplikację, której jedyną zależnością jest flask, która działa dobrze poza dockerem i wiąże się z domyślnym portem 5000
. Oto pełne źródło:
from flask import Flask
app = Flask(__name__)
app.debug = True
@app.route('/')
def main():
return 'hi'
if __name__ == '__main__':
app.run()
Problem polega na tym, że kiedy wdrażam to w dockerze, serwer działa, ale jest nieosiągalny z zewnątrz kontenera.
Poniżej znajduje się mój plik Dockerfile. Obraz jest ubuntu z zainstalowaną kolbą. Smoła zawiera tylko index.py
wymienione powyżej;
# Dockerfile
FROM dreen/flask
MAINTAINER dreen
WORKDIR /srv
# Get source
RUN mkdir -p /srv
COPY perfektimprezy.tar.gz /srv/perfektimprezy.tar.gz
RUN tar x -f perfektimprezy.tar.gz
RUN rm perfektimprezy.tar.gz
# Run server
EXPOSE 5000
CMD ["python", "index.py"]
Oto kroki, które robię, aby wdrożyć
$> sudo docker build -t perfektimprezy .
O ile wiem, powyższe działa dobrze, obraz zawiera zawartość smoły /srv
. Teraz uruchommy serwer w kontenerze:
$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769
Czy to faktycznie działa?
$> sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c50b67d45b1 perfektimprezy:latest "python index.py" 5 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp loving_wozniak
$> sudo docker logs 1c50b67d45b1
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
Tak, wygląda na to, że serwer Flask działa. Tutaj robi się dziwnie. Wyślijmy żądanie do serwera:
$> curl 127.0.0.1:5000 -v
* Rebuilt URL to: 127.0.0.1:5000/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:5000
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
Pusta odpowiedź ... Ale czy proces jest uruchomiony?
$> sudo docker top 1c50b67d45b1
UID PID PPID C STIME TTY TIME CMD
root 2084 812 0 10:26 ? 00:00:00 python index.py
root 2117 2084 0 10:26 ? 00:00:00 /usr/bin/python index.py
Teraz wejdźmy na serwer ssh i sprawdźmy ...
$> sudo docker exec -it 1c50b67d45b1 bash
root@1c50b67d45b1:/srv# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:47677 127.0.0.1:5000 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
root@1c50b67d45b1:/srv# curl -I 127.0.0.1:5000
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5447
Server: Werkzeug/0.10.4 Python/2.7.6
Date: Tue, 19 May 2015 12:18:14 GMT
Jest dobrze ... ale nie z zewnątrz :( Co ja robię źle?
źródło
docker exec -it 1c50b67d45b1 bash
a następnie zwykłenetstat -an
lub dowolne polecenie, które wykonasz podczas debugowania Flaska (tail, cat ...)Connected to 127.0.0.1
)Odpowiedzi:
Problem polega na tym, że jesteś powiązany tylko z interfejsem localhost, powinieneś być powiązany z nim,
0.0.0.0
jeśli chcesz, aby kontener był dostępny z zewnątrz. Jeśli zmienisz:do
Powinno działać.
źródło
-p 5000:5000
flagą za pomocądocker run
polecenia.Używając
flask
polecenia zamiastapp.run
, możesz przekazać--host
opcję zmiany hosta. Linia w Dockerze wyglądałaby następująco:lub
źródło
app.run(host="0.0.0.0")
nie działa? Zrobiłem również post na to pytanie: stackoverflow.com/q/53133350/3279996python run.py --host=0.0.0.0
. To mnie od czasu do czasu dopada ze względu na moje nazewnictwo. Ten kod wydaje się działać, ale serwer będzie działał na hoście lokalnym.app.run(host="0.0.0.0")
porażką iCMD ["flask", "run", "--host", "0.0.0.0" ]
działaniem jak mistrz.Twój kontener Docker ma więcej niż jeden interfejs sieciowy. Na przykład mój kontener ma następujące elementy:
jeśli uruchomisz
docker network inspect bridge
, możesz zobaczyć, że twój kontener jest podłączony do tego mostu z drugim interfejsem w powyższym wyjściu. Ten domyślny most jest również połączony z procesem Docker na hoście.Dlatego musiałbyś uruchomić polecenie:
Aby uzyskać dostęp do aplikacji Flask działającej w kontenerze Docker z komputera hosta. Zastąp
172.17.0.2
dowolny adres IP kontenera.źródło
Aby skorzystać z innych odpowiedzi:
Wyobraź sobie, że masz dwa komputery. Każdy komputer ma interfejs sieciowy (powiedzmy WiFi), który jest jego publicznym adresem IP. Każdy komputer ma interfejs loopback / localhost pod adresem 127.0.0.1. To znaczy „tylko ten komputer”.
Jeśli podałeś adres 127.0.0.1 na komputerze A, nie spodziewasz się, że będziesz w stanie połączyć się z nim przez 127.0.0.1 na komputerze B. W końcu poprosiłeś o nasłuchiwanie na lokalnym , prywatnym adresie komputera A.
Docker ma podobną konfigurację; technicznie jest to ten sam komputer, ale jądro Linuksa pozwala każdemu kontenerowi działać z własnym izolowanym stosem sieciowym. Zatem 127.0.0.1 w kontenerze to to samo, co 127.0.0.1 na innym komputerze niż twój host - nie możesz się z nim połączyć.
Dłuższa wersja, ze schematami: https://pythonspeed.com/articles/docker-connection-refused/
źródło
Przede wszystkim w swoim skrypcie Pythona musisz zmienić kod z
do
Po drugie, w twoim pliku docker ostatnia linia powinna wyglądać jak
A na komputerze hosta, jeśli
0.0.0.0:5000
nie działa, powinieneś spróbowaćlocalhost:5000
Uwaga - polecenie CMD musi być poprawne. Ponieważ polecenie CMD zapewnia wartości domyślne do wykonywania kontenera.
źródło