Distribuzione di un'app flask minima nella finestra mobile: problemi di connessione al server


108

Ho un'app la cui unica dipendenza è flask, che funziona bene fuori dalla finestra mobile e si collega alla porta predefinita 5000. Ecco la fonte completa:

from flask import Flask

app = Flask(__name__)
app.debug = True

@app.route('/')
def main():
    return 'hi'

if __name__ == '__main__':
    app.run()

Il problema è che quando lo distribuisco nella finestra mobile, il server è in esecuzione ma non è raggiungibile dall'esterno del contenitore.

Di seguito è riportato il mio Dockerfile. L'immagine è ubuntu con il pallone installato. Il tar contiene solo quanto index.pysopra elencato;

# 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"]

Ecco i passaggi che sto eseguendo per distribuire

$> sudo docker build -t perfektimprezy .

Per quanto ne so quanto sopra funziona bene, l'immagine ha il contenuto del tar in /srv. Ora, iniziamo il server in un contenitore:

$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769

È effettivamente in esecuzione?

$> 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

Sì, sembra che il server flask sia in esecuzione. Qui è dove diventa strano. Facciamo una richiesta al server:

 $> 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

Risposta vuota ... Ma il processo è in esecuzione?

$> 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

Ora inseriamo ssh nel server e controlliamo ...

$> 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

Va bene ... ma non dall'esterno :( Cosa sto facendo di sbagliato?


la cosa rilevante è "causato dalla <classe 'httplib.BadStatusLine'>", vedi stackoverflow.com/questions/16592568/...
user2915097

Sto provando a connettermi solo una volta e sono abbastanza certo che questo non sia un bug in httpie (ho cambiato l'esempio in curl ora), né nel server poiché funziona bene fuori da finestra mobile. Ho la forte sensazione che si tratti di un problema di
passi falsi di

Controlla il container con docker exec -it 1c50b67d45b1 bashe poi il solito netstat -ano qualsiasi comando che faresti quando
esegui

@ user2915097: ive ha aggiunto alcuni output dall'interno del server
Dreen

'Can't connect ...' @Dreen, puoi connetterti , ricevi solo una risposta vuota ( Connected to 127.0.0.1)
ForceBru

Risposte:


179

Il problema è che ti stai collegando solo all'interfaccia localhost, dovresti collegarti a 0.0.0.0se vuoi che il contenitore sia accessibile dall'esterno. Se cambi:

if __name__ == '__main__':
    app.run()

per

if __name__ == '__main__':
    app.run(host='0.0.0.0')

Dovrebbe funzionare.


Questa soluzione funziona. Si può vedere il risultato usando un Dockerfile completo e uno script python qui come descritto da questa soluzione.

qual è la differenza?
Jwan622

1
@ Jwan622 L'interfaccia localhost è disponibile solo all'interno del contenitore. 0.0.0.0 si lega a tutte le interfacce. Le interfacce si connettono a varie reti (quindi potresti averne una per wifi, lan ecc.)
Adrian Mouat

Assicurati di ricordarti di associare la porta 5000 al tuo contenitore con il -p 5000:5000flag con il tuo docker runcomando.
T Loch.

40

Quando si utilizza il flaskcomando invece di app.run, è possibile passare l' --hostopzione per modificare l'host. La riga in Docker sarebbe:

CMD ["flask", "run", "--host", "0.0.0.0"]

o

CMD flask run --host 0.0.0.0

2
Grazie mille per questa soluzione, ho lo stesso problema, sai qual è il motivo per cui app.run(host="0.0.0.0") non funziona? Ho anche fatto un post per questa domanda: stackoverflow.com/q/53133350/3279996
xirururu

1
In questa nota, assicurati di non usare python run.py --host=0.0.0.0 . Questo mi prende ogni tanto a causa delle mie convenzioni di denominazione. Il codice sembrerà funzionare ma il server verrà eseguito sull'host locale.
Braden Holt

1
Questo non esegue il server flask integrato, che non è pensato per gli ambienti di produzione?
code_dredd

Questo è ottimo, per qualsiasi motivo quasi tutte le informazioni di Flask-with-Docker non riescono a utilizzare Flask CLI, che è il modo Flask 1.0 per avviare un'app.
Zach Valenta

3
Qui nel 2020 con Flask 1.1.1 app.run(host="0.0.0.0")fallendo e CMD ["flask", "run", "--host", "0.0.0.0" ]lavorando come un campione.
Joe

2

Il tuo contenitore Docker ha più di un'interfaccia di rete. Ad esempio, il mio contenitore ha quanto segue:

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

se esegui docker network inspect bridge, puoi vedere che il tuo contenitore è connesso a quel bridge con la seconda interfaccia nell'output sopra. Questo bridge predefinito è anche connesso al processo Docker sul tuo host.

Pertanto dovresti eseguire il comando:

CMD flask run --host 172.17.0.2

Per accedere alla tua app Flask in esecuzione in un contenitore Docker dal tuo computer host. Sostituisci 172.17.0.2con qualunque sia il particolare indirizzo IP del tuo contenitore.


2

Per costruire su altre risposte:

Immagina di avere due computer. Ogni computer ha un'interfaccia di rete (WiFi, diciamo), che è il suo IP pubblico. Ogni computer ha un'interfaccia loopback / localhost, in 127.0.0.1. Significa "solo questo computer".

Se sei elencato su 127.0.0.1 sul computer A, non ti aspetteresti di essere in grado di connetterti a quello tramite 127.0.0.1 durante l'esecuzione sul computer B. Dopo tutto, hai chiesto di ascoltare l' indirizzo privato e locale del computer A.

Docker è una configurazione simile; tecnicamente è lo stesso computer, ma il kernel Linux consente a ciascun contenitore di funzionare con il proprio stack di rete isolato. Quindi 127.0.0.1 in un contenitore è uguale a 127.0.0.1 su un computer diverso dal tuo host: non puoi connetterti ad esso.

Versione più lunga, con diagrammi: https://pythonspeed.com/articles/docker-connection-refused/


0

Prima di tutto nel tuo script Python devi cambiare il codice da

app.run()

per

app.run(host="0.0.0.0")

Secondo, nel tuo file Docker, l'ultima riga dovrebbe essere come

CMD ["flask", "run", "-h", "0.0.0.0", "-p", "5000"]

E avanti macchina host se 0.0.0.0:5000non funziona, dovresti provare conlocalhost:5000

Nota: il comando CMD deve essere corretto. Poiché il comando CMD fornisce i valori predefiniti per l'esecuzione di container.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.