在docker中部署最小的flask应用程序-服务器连接问题

2024-11-21 08:33:00
admin
原创
5
摘要:问题描述:我有一个应用程序,其唯一依赖项是 flask,它在 docker 之外运行良好并绑定到默认端口5000。以下是完整源代码:from flask import Flask app = Flask(__name__) app.debug = True @app.route('/') def main...

问题描述:

我有一个应用程序,其唯一依赖项是 flask,它在 docker 之外运行良好并绑定到默认端口5000。以下是完整源代码:

from flask import Flask

app = Flask(__name__)
app.debug = True

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

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

问题是,当我在 docker 中部署它时,服务器正在运行,但从容器外部无法访问。

下面是我的Dockerfile。图像是安装了 flask 的 ubuntu。tar 仅包含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 .

据我所知,上述操作运行良好,该镜像包含 tar 的内容/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

是的,看来 Flask 服务器正在运行。这就是奇怪的地方。让我们向服务器发出请求:

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

没事……但从外面看不行。

我做错了什么?


解决方案 1:

问题是您只绑定到 localhost 接口,0.0.0.0如果您希望容器可从外部访问,则应该绑定到。如果您更改:

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

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

它应该可以工作。

请注意,这将绑定到主机上的所有接口,在某些情况下可能会存在安全风险 -有关绑定到特定接口的更多信息,请参阅https://stackoverflow.com/a/58138250/4332

解决方案 2:

当使用flask命令而不是时app.run,您可以传递--host选项来更改主机。Docker 中的行将是:

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

或者

CMD flask run --host 0.0.0.0

解决方案 3:

您的 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,你会看到你的容器通过上面输出中的第二个接口连接到了那个网桥。这个默认网桥也连接到了你主机上的 Docker 进程。

因此您必须运行以下命令:

CMD flask run --host 172.17.0.2

从主机访问在 Docker 容器中运行的 Flask 应用。将其替换172.17.0.2为容器的特定 IP 地址。

解决方案 4:

0.0.0.0您需要在 docker file 中修改主机。这是一个最小示例

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

并且该文件app.py

# app.py
from flask import Flask

app = Flask(__name__)

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


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

然后编译

docker build . -t deploy_flask

并运行

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

您可以使用以下方式检查响应curl http://127.0.0.1:5000/ -v

解决方案 5:

首先,你需要在你的 Python 脚本中将代码从

app.run()

app.run(host="0.0.0.0")

其次,在你的docker文件中,最后一行应该是这样的

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

如果在主机0.0.0.0:5000上不起作用,那么你应该尝试localhost:5000

注意 - CMD 命令必须正确。因为 CMD 命令为执行容器提供了默认值。

解决方案 6:

基于其他答案:

假设您有两台计算机。每台计算机都有一个网络接口(例如 WiFi),即其公共 IP。每台计算机都有一个环回/本地主机接口,地址为 127.0.0.1。这意味着“仅限这台计算机”。

如果您在计算机 A 上列出 127.0.0.1,则您不会期望在计算机 B 上运行时能够通过 127.0.0.1 连接到该地址。毕竟,您要求监听计算机 A 的本地私有地址。

Docker 的设置类似;从技术上讲,它们是同一台计算机,但 Linux 内核允许每个容器使用自己的独立网络堆栈运行。因此,容器中的 127.0.0.1 与主机之外的其他计算机上的 127.0.0.1 相同 — 您无法连接到它。

更长的版本,带有图表:https://pythonspeed.com/articles/docker-connection-refused/

解决方案 7:

对于快速阅读者来说,需要检查三件事情:

  1. 确保您已在 Dockerfile 中公开端口。

  2. 使用以下方式在容器中运行命令flask run --host=0.0.0.0

  3. 在 docker run 命令中指定端口docker run -it -p5000:5000 yourImageName

解决方案 8:

就我而言,绑定主机0.0.0.0仅在我的本地环境中有效,并且在服务器上部署时失败。

然后当我用以下代码替换端口时它就开始工作了--network=host

前:

docker run -d -p 5000:5000 <docker_image>

后:

docker run -d --network=host <docker_image>

附言:0.0.0.0:5000运行 Flask 应用程序时我仍然使用了容器内部。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用