Розгортання програми з мінімальною колбою в проблемах з підключенням сервера


108

У мене є додаток, у якого лише залежність - колба, яка працює нормально за межами докера та прив'язується до порту за замовчуванням 5000. Ось повне джерело:

from flask import Flask

app = Flask(__name__)
app.debug = True

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

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

Проблема полягає в тому, що коли я розгортаю це в docker, сервер працює, але недоступний за межами контейнера.

Нижче мій Dockerfile. Зображення ubuntu із встановленою колбою. Дьоготь просто містить index.pyперераховане вище;

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

Ось такі кроки, які я роблю для розгортання

$> sudo docker build -t perfektimprezy .

Наскільки мені відомо, вище працює нормально, зображення містить вміст дьогтю /srv. Тепер давайте запустимо сервер у контейнер:

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

Це насправді працює?

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

Так, здається, що флеш-сервер працює. Ось де це стає дивно. Дозволяє зробити запит на сервер:

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

Порожня відповідь ... Але процес запущений?

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

Тепер давайте ssh на сервер і перевіримо ...

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

Це добре ... але не ззовні :( Що я роблю неправильно?


відповідна річ «Викликаний <клас" httplib.BadStatusLine ">», див stackoverflow.com/questions/16592568 / ...
user2915097

Я намагаюся лише один раз підключитися, і я впевнений, що це не помилка в httpie (я змінив приклад, щоб згорнутися зараз), ні на сервері, оскільки він працює добре за межами докера. У мене є сильне відчуття, що це проблема помилки кроку з налаштуванням / розгортанням докерів
Dreen,

Перевірте в контейнері, docker exec -it 1c50b67d45b1 bashа потім звичайну netstat -anабо будь-яку команду, яку ви виконували б при налагодженні колби (хвіст, кішка ...)
user2915097

@ user2915097: ive додав деякий вихід зсередини сервера
Dreen

"Не вдається підключитися ..." @Дерейн, ви можете підключитися , ви просто отримаєте порожню відповідь ( Connected to 127.0.0.1)
ForceBru

Відповіді:


179

Проблема полягає в тому, що ви прив'язуєте лише інтерфейс localhost, ви повинні бути прив'язуючим до нього, 0.0.0.0якщо хочете, щоб контейнер був доступний зовні. Якщо ви зміните:

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

до

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

Це має працювати.


Це рішення працює. Можна бачити результат , використовуючи повний Dockerfile і пітон скрипт тут , так як це рішення описує.

яка різниця?
Jwan622

1
@ Jwan622 Інтерфейс localhost доступний лише всередині контейнера. 0,0.0,0 прив'язується до всіх інтерфейсів. Інтерфейси підключаються до різних мереж (щоб у вас був доступ до Wi-Fi, пробігів тощо)
Adrian

Переконайтеся, що ви пам’ятаєте прив’язати порт 5000 до контейнера із -p 5000:5000прапором із вашою docker runкомандою.
Т Лох.

39

Використовуючи flaskкоманду замість app.run, ви можете передати --hostопцію зміни хоста. Рядок у Docker буде таким:

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

або

CMD flask run --host 0.0.0.0

2
Дуже дякую за це рішення, у мене така ж проблема, чи знаєте ви, чому причина app.run(host="0.0.0.0") не працює? Я також зробив повідомлення з цього питання: stackoverflow.com/q/53133350/3279996
xirururu

1
На цій примітці переконайтеся, що не використовуйте python run.py --host=0.0.0.0 . Це отримує мене раз у раз завдяки моїм умовам іменування. Цей код, здається, працює, але сервер працює на локальному хості.
Бреден Холт

1
Чи не працює цей вбудований колбу-сервер, який не призначений для виробничих середовищ?
code_dredd

Це чудово, з будь-якої причини майже вся інформація Flask-with-Docker не вдається використати Flask CLI, що afaik - це спосіб Flask 1.0 для запуску програми.
Zach Valenta

3
Ось у 2020 році з колбою 1.1.1 з app.run(host="0.0.0.0")відмовою і CMD ["flask", "run", "--host", "0.0.0.0" ]працює, як чемпіон.
Джо

2

Ваш контейнер Docker має більше ніж один мережевий інтерфейс. Наприклад, мій контейнер має таке:

$ 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

якщо ви запустите docker network inspect bridge, ви можете бачити, що ваш контейнер підключений до цього мосту з другим інтерфейсом у наведеному вище висновку. Цей міст за замовчуванням також підключений до процесу Докер вашого хоста.

Тому вам доведеться запустити команду:

CMD flask run --host 172.17.0.2

Щоб отримати доступ до програми Flask, що працює в контейнері Docker, з вашого хост-машини. Замініть 172.17.0.2будь-якою конкретною IP-адресою вашого контейнера.


2

На основі інших відповідей:

Уявіть, у вас два комп’ютери. Кожен комп'ютер має мережевий інтерфейс (скажімо, WiFi), який є його загальнодоступним IP. Кожен комп'ютер має інтерфейс зворотного зв'язку / localhost, розміром 127.0.0.1. Це означає "просто цей комп'ютер".

Якщо ви вказали на 127.0.0.1 на комп'ютері A, ви не очікували, що зможете підключитися до цього через 127.0.0.1 під час роботи на комп’ютері B. Зрештою, ви попросили прослухати локальну приватну адресу комп'ютера A.

Docker - аналогічна установка; технічно це той самий комп’ютер, але ядро ​​Linux дозволяє кожному контейнеру працювати з власним ізольованим мережевим стеком. Отже 127.0.0.1 в контейнері такий же, як 127.0.0.1 на іншому комп’ютері, ніж ваш хост - ви не можете підключитися до нього.

Більш довга версія, із схемами: https://pythonspeed.com/articles/docker-connection-refused/


0

Перш за все, у вашому сценарії python потрібно змінити код

app.run()

до

app.run(host="0.0.0.0")

По-друге, у вашому докерному файлі має бути такий останній рядок

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

І на хост-машині, якщо 0.0.0.0:5000вона не працює, то слід спробуватиlocalhost:5000

Примітка. Команда CMD повинна бути належною. Оскільки команда CMD надає за замовчуванням виконання контейнера.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.