如何访问docker容器中的内部服务器?

时间:2018-01-07 17:49:43

标签: python docker networking flask bokeh

所以我试图将Flask应用程序停靠,它执行以下操作:

  1. 在容器内部运行Bokeh服务器127.0.0.1:5006 地址。
  2. 在地址0.0.0.0:5000中运行Flask应用程序     它可以从集装箱外面进入。
  3. 当建立连接时,Flask会尝试从Bokeh服务器获取数据 (用容器实例化)。但是当作为容器运行时,它永远不会碰到容器自己的localhost(甚至没有将它设置为--net = host)。
  4. 我设法让它运行的唯一方法是在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背景的人可以帮我理解这里发生了什么?我假设从容器的角度来看,在localhost上发布的任何内容都可以从同一容器中发布的其他服务中看到。

    提前致谢

2 个答案:

答案 0 :(得分:2)

根据我的评论,我将根据我怀疑的情况回答这个问题。

在我对Bokeh和autoload_server(来自https://bokeh.pydata.org/en/latest/docs/user_guide/embed.html)的简短回顾中,看来这个函数实际上生成了一些JavaScript。它实际上并没有从Python或Flask本身连接到Bokeh服务器。连接来自浏览器。

根据这些信息,监听http://127.0.0.1:5006将不允许浏览器连接。即使容器在Windows或Mac上以--net=host模式运行,也会使容器在Docker虚拟机网络而不是实际主机上进行监听,但仍会导致连接失败。

Bokeh服务器需要监听0.0.0.0,以便通过Docker NAT传输的任何IP都能够连接。此外,您需要告诉浏览器如何访问此容器。这意味着使用VM的IP地址或露出Docker容器端口的计算机的IP。

在生产设置中,您可能会在负载均衡器或其他反向代理后面运行Flask和Bokeh服务器端口,然后可以公开单个IP / DNS名称以连接到它们。然后,您将使用该DNS名称或IP作为url参数。

答案 1 :(得分:1)

如果您在Linux计算机上运行此设置,则--net=host将允许您的容器与主机的环回接口通信;该标志只是指定容器不应该使用自己的网络命名空间,而只是运行时可以访问所有主机的网络适配器。

但是,如果您在Windows或MacOS中运行Docker,--net=host不起作用 - 这是因为当Docker客户端在Windows计算机上运行时,容器实际上是在docker上运行守护程序在一个单独的VM中。如果您运行localhost并将Flask服务器指向-e BOKEH_IP=1.2.3.4,那么您实际上是从docker VM访问本地主机,而不是运行Bokeh的Windows机器的本地主机。

当您需要处理多个容器相互交谈时,Docker中的网络可能会非常棘手。您正在处理的问题是如何在您的应用程序中发现服务。有几种方法可以解决这个问题:

最简单的可能是将你的Bokeh服务器的IP注入你的Flask应用程序作为配置;通常这是使用环境变量完成的,可以在运行带有$mydata = $data['device'][$id]['state']['1']; 标志的docker容器时传递。您可以在生产中配置不同的IP。

您还可以对Bokeh服务器进行容器化,然后使用Docker Compose,Docker Swarm或Kubernetes之类的东西来处理服务之间的通信。 Docker Compose可以在一台机器上运行,Docker Swarm非常适合在多台机器上轻松调度容器,而Kubernetes是一个更复杂,功能更全的选项,用于编排大量的交互服务。