Implementación de una aplicación de matraz mínima en la ventana acoplable: problemas de conexión del servidor

Resuelto Dreen asked hace 9 años • 8 respuestas

Tengo una aplicación cuya única dependencia es flask, que funciona bien fuera de la ventana acoplable y se vincula al puerto predeterminado 5000. Aquí está la fuente completa:

from flask import Flask

app = Flask(__name__)
app.debug = True

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

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

El problema es que cuando implemento esto en la ventana acoplable, el servidor se está ejecutando pero no se puede acceder a él desde fuera del contenedor.

A continuación se muestra mi Dockerfile. La imagen es ubuntu con flask instalado. El alquitrán sólo contiene lo index.pymencionado anteriormente;

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

Estos son los pasos que estoy siguiendo para implementar

$> sudo docker build -t perfektimprezy .

Hasta donde yo sé, lo anterior funciona bien, la imagen tiene el contenido del tar en formato /srv. Ahora, iniciemos el servidor en un contenedor:

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

¿Está realmente funcionando?

$> 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í, parece que el servidor flask se está ejecutando. Aquí es donde se pone raro. Hagamos una solicitud al servidor:

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

Respuesta vacía... ¿Pero se está ejecutando el proceso?

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

Ahora ingresemos al servidor y verifiquemos...

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

Está bien... Pero no desde fuera.
¿Qué estoy haciendo mal?

Dreen avatar May 19 '15 17:05 Dreen
Aceptado

El problema es que solo está vinculado a la interfaz localhost, a la que debe vincularse 0.0.0.0si desea que se pueda acceder al contenedor desde el exterior. Si cambias:

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

a

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

Deberia de funcionar.

Tenga en cuenta que esto se vinculará a todas las interfaces del host, lo que en algunas circunstancias puede representar un riesgo para la seguridad; consulte https://stackoverflow.com/a/58138250/4332 para obtener más información sobre cómo vincularse a una interfaz específica.

Adrian Mouat avatar May 19 '2015 15:05 Adrian Mouat

Al usar el flaskcomando en lugar de app.run, puede pasar la --hostopción para cambiar el host. La línea en Docker sería:

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

o

CMD flask run --host 0.0.0.0
Marku avatar Mar 25 '2017 10:03 Marku

Su contenedor Docker tiene más de una interfaz de red. Por ejemplo, mi contenedor tiene lo siguiente:

$ 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

Si ejecuta docker network inspect bridge, puede ver que su contenedor está conectado a ese puente con la segunda interfaz en el resultado anterior. Este puente predeterminado también está conectado al proceso Docker en su host.

Por lo tanto tendrías que ejecutar el comando:

CMD flask run --host 172.17.0.2

Para acceder a su aplicación Flask que se ejecuta en un contenedor Docker desde su máquina host. Reemplace 172.17.0.2con cualquiera que sea la dirección IP particular de su contenedor.

Bert avatar Sep 27 '2019 16:09 Bert

Debe modificar el host 0.0.0.0en el archivo acoplable. Este es un ejemplo mínimo.

# Example of Dockerfile

FROM python:3.8.5-alpine3.12

WORKDIR /app

EXPOSE 5000
ENV FLASK_APP=app.py

COPY . /app
RUN pip install -r requirements.txt

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

y el archivo app.pyes

# app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello world"


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

Luego compila con

docker build . -t deploy_flask

y correr con

docker run -p 5000:5000 -t -i deploy_flask:latest

Puedes comprobar la respuesta concurl http://127.0.0.1:5000/ -v

Galuoises avatar Sep 14 '2020 20:09 Galuoises

En primer lugar, en su script de Python necesita cambiar el código de

app.run()

a

app.run(host="0.0.0.0")

En segundo lugar, en su archivo acoplable, la última línea debería ser como

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

Y en la máquina host , si 0.0.0.0:5000no funciona, deberías intentarlo conlocalhost:5000

Nota: el comando CMD debe ser correcto. Porque el comando CMD proporciona valores predeterminados para ejecutar el contenedor.

Nivedita Shah avatar Jun 02 '2020 10:06 Nivedita Shah