如何访问 docker 容器内的内部服务器?
How to access an internal server within a docker container?
所以我正在尝试对执行以下操作的 Flask 应用程序进行 docker 化:
- 在容器的 127.0.0.1:5006 内部运行 Bokeh 服务器
地址。
- 运行地址为0.0.0.0:5000的Flask应用程序
它可以从容器外部访问。
- 建立连接后,Flask 会尝试从 Bokeh 服务器获取数据
(用容器实例化)。但是当 运行 作为容器时,它永远不会访问容器自己的本地主机(甚至不将其设置为 --net=host)。
我设法让它工作的唯一方法是也在 0.0.0.0 中创建 Bokeh 服务器并传递容器的主机 IP(我在 Windows) 到 Flask 尝试从中获取它的地址(参见 autoload_server 中的 url 字段)。但这显然不适用于其他机器。
以下是相关的代码块:
server = Server({'/datavisualization': bokeh_app}, io_loop=io_loop, address="127.0.0.1",
allow_websocket_origin=["*"], host=["*"])
@app.route('/')
def bokeh_server():
# Fetch Running Bokeh Server
bokeh_embed = autoload_server(model=None,
app_path="/datavisualization",
url="http://127.0.0.1:5006")
html = render_template('index.html', bokeh_embed=Markup(bokeh_embed))
return html
if __name__ == '__main__':
from tornado.httpserver import HTTPServer
from tornado.wsgi import WSGIContainer
from bokeh.util.browser import view
# Serve the Flask app
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000, address='0.0.0.0')
io_loop.add_callback(view, "http://0.0.0.0:5000/")
io_loop.start()
也许在 Docker 方面有更多背景的人可以帮助我了解这里发生了什么?我假设从容器的角度来看,在本地主机上发布的任何内容都可以被同一容器内发布的其他服务看到。
提前致谢
我将根据我的评论回答我怀疑的问题。
在我对 Bokeh 和 server_document
(来自 https://docs.bokeh.org/en/latest/docs/user_guide/embed.html#bokeh-applications)的非常简短的回顾中,似乎这个函数实际上生成了一些 JavaScript。它实际上并没有从 Python 或 Flask 本身连接到 Bokeh 服务器。连接来自浏览器。
鉴于此信息,侦听 http://127.0.0.1:5006
将不允许浏览器连接。即使容器 运行ning 在 Windows 或 Mac 上处于 --net=host
模式,也会让容器监听 Docker 虚拟机网络而不是实际主机,仍然导致连接失败。
Bokeh 服务器需要监听 0.0.0.0,这样通过 Docker NAT 的任何 IP 都可以连接。此外,你需要告诉你的浏览器如何到达这个容器。这意味着使用 VM 的 IP 地址或暴露 Docker 容器端口的计算机的 IP。
在生产设置中,您可能 运行 负载均衡器或其他反向代理后面的 Flask 和 Bokeh 服务器端口,然后可以公开单个 IP / DNS 名称以连接到它们。然后,您将使用该 DNS 名称或 IP 作为您的 url
参数。
如果您 运行 在 Linux 机器上进行此设置,那么 --net=host
将允许您的容器与主机的环回接口进行通信;该标志只是指定容器不应使用自己的网络命名空间,而只是 运行 可以访问主机的所有网络适配器。
但是,如果您在 Windows 或 MacOS 中 运行ning Docker,--net=host
的工作方式就不一样了——这是因为 docker 客户端 运行ning 在您的 Windows 机器上,容器实际上 运行ning 在单独 VM 中的 docker 守护程序上。如果你 运行 --net=host
并将你的 Flask 服务器指向 localhost
,你实际上是从 docker 虚拟机访问本地主机,而不是 Windows 机器的本地主机,其中 Bokeh 运行宁.
当您需要处理多个相互通信的容器时,Docker 中的网络可能会很棘手。您正在处理的问题是如何在您的应用程序中发现服务。有几种方法可以解决这个问题:
最简单的可能是将您的 Bokeh 服务器的 IP 作为配置注入到您的 Flask 应用程序中;通常这是使用环境变量完成的,当 运行 带有 -e BOKEH_IP=1.2.3.4
标志的 docker 容器时可以传递环境变量。您将在生产环境中配置不同的 IP。
您还可以将 Bokeh 服务器容器化,然后使用 Docker Compose、Docker Swarm 或 Kubernetes 之类的东西来处理服务之间的通信。 Docker Compose 在单台机器上工作,Docker Swarm 非常适合跨多台机器轻松调度容器,而 Kubernetes 是用于编排大量交互服务的更复杂且功能更全的选项。
所以我正在尝试对执行以下操作的 Flask 应用程序进行 docker 化:
- 在容器的 127.0.0.1:5006 内部运行 Bokeh 服务器 地址。
- 运行地址为0.0.0.0:5000的Flask应用程序 它可以从容器外部访问。
- 建立连接后,Flask 会尝试从 Bokeh 服务器获取数据 (用容器实例化)。但是当 运行 作为容器时,它永远不会访问容器自己的本地主机(甚至不将其设置为 --net=host)。
我设法让它工作的唯一方法是也在 0.0.0.0 中创建 Bokeh 服务器并传递容器的主机 IP(我在 Windows) 到 Flask 尝试从中获取它的地址(参见 autoload_server 中的 url 字段)。但这显然不适用于其他机器。
以下是相关的代码块:
server = Server({'/datavisualization': bokeh_app}, io_loop=io_loop, address="127.0.0.1",
allow_websocket_origin=["*"], host=["*"])
@app.route('/')
def bokeh_server():
# Fetch Running Bokeh Server
bokeh_embed = autoload_server(model=None,
app_path="/datavisualization",
url="http://127.0.0.1:5006")
html = render_template('index.html', bokeh_embed=Markup(bokeh_embed))
return html
if __name__ == '__main__':
from tornado.httpserver import HTTPServer
from tornado.wsgi import WSGIContainer
from bokeh.util.browser import view
# Serve the Flask app
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000, address='0.0.0.0')
io_loop.add_callback(view, "http://0.0.0.0:5000/")
io_loop.start()
也许在 Docker 方面有更多背景的人可以帮助我了解这里发生了什么?我假设从容器的角度来看,在本地主机上发布的任何内容都可以被同一容器内发布的其他服务看到。
提前致谢
我将根据我的评论回答我怀疑的问题。
在我对 Bokeh 和 server_document
(来自 https://docs.bokeh.org/en/latest/docs/user_guide/embed.html#bokeh-applications)的非常简短的回顾中,似乎这个函数实际上生成了一些 JavaScript。它实际上并没有从 Python 或 Flask 本身连接到 Bokeh 服务器。连接来自浏览器。
鉴于此信息,侦听 http://127.0.0.1:5006
将不允许浏览器连接。即使容器 运行ning 在 Windows 或 Mac 上处于 --net=host
模式,也会让容器监听 Docker 虚拟机网络而不是实际主机,仍然导致连接失败。
Bokeh 服务器需要监听 0.0.0.0,这样通过 Docker NAT 的任何 IP 都可以连接。此外,你需要告诉你的浏览器如何到达这个容器。这意味着使用 VM 的 IP 地址或暴露 Docker 容器端口的计算机的 IP。
在生产设置中,您可能 运行 负载均衡器或其他反向代理后面的 Flask 和 Bokeh 服务器端口,然后可以公开单个 IP / DNS 名称以连接到它们。然后,您将使用该 DNS 名称或 IP 作为您的 url
参数。
如果您 运行 在 Linux 机器上进行此设置,那么 --net=host
将允许您的容器与主机的环回接口进行通信;该标志只是指定容器不应使用自己的网络命名空间,而只是 运行 可以访问主机的所有网络适配器。
但是,如果您在 Windows 或 MacOS 中 运行ning Docker,--net=host
的工作方式就不一样了——这是因为 docker 客户端 运行ning 在您的 Windows 机器上,容器实际上 运行ning 在单独 VM 中的 docker 守护程序上。如果你 运行 --net=host
并将你的 Flask 服务器指向 localhost
,你实际上是从 docker 虚拟机访问本地主机,而不是 Windows 机器的本地主机,其中 Bokeh 运行宁.
当您需要处理多个相互通信的容器时,Docker 中的网络可能会很棘手。您正在处理的问题是如何在您的应用程序中发现服务。有几种方法可以解决这个问题:
最简单的可能是将您的 Bokeh 服务器的 IP 作为配置注入到您的 Flask 应用程序中;通常这是使用环境变量完成的,当 运行 带有 -e BOKEH_IP=1.2.3.4
标志的 docker 容器时可以传递环境变量。您将在生产环境中配置不同的 IP。
您还可以将 Bokeh 服务器容器化,然后使用 Docker Compose、Docker Swarm 或 Kubernetes 之类的东西来处理服务之间的通信。 Docker Compose 在单台机器上工作,Docker Swarm 非常适合跨多台机器轻松调度容器,而 Kubernetes 是用于编排大量交互服务的更复杂且功能更全的选项。