【问题标题】:Docker Network Host on UbuntuUbuntu 上的 Docker 网络主机
【发布时间】:2021-04-14 23:03:58
【问题描述】:

我有一个 Django REST 服务和另一个用作应用程序代理的 Flask 服务。两者都是使用自己的 Docker 容器运行的不同项目。 我可以在 Flask 服务使用的 Django 服务上发布产品,但是,我无法通过 Flask 访问 Django 服务。 这些容器在同一个网络上运行,我已经尝试过Thomasleveil's 的建议,包括docker-host by qoomon。 请求收到的错误与我尝试转发流量之前的错误相同。不同的是,现在当我发出请求时,它会一直挂起一段时间,直到失败。

错误如下: requests.exceptions.ConnectionError: HTTPConnectionPool(host='172.17.0.1', port=8000): Max retries exceeded with url: /api/user (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f0039388340>: Failed to establish a new connection: [Errno 110] Connection timed out'))

我试图发出的请求是 /api/products/1/like 的 POST。目前,不需要实体。

这是我使用 Flask 进行 POST 的方式,其中 IP 是 Docker IP:

@app.route("/api/products/<int:id>/like", methods=["POST"])
def like(id):
    req = requests.get("http://172.17.0.1:8000/api/user")
    json = req.json()

    try:
        product_user = ProductUser(user_id=json["id"], product=id)
        db.session.add(product_user)
        db.session.commit()

        publish("product_liked", id)
    except:
        abort(400, "You already liked this product")

    return jsonify({
        "message": "success"
    })

Django 的 docker compose 文件(请忽略服务 tcp_message_emitter):

version: '3.8'
services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python manage.py runserver 0.0.0.0:8000"
    ports:
      - 8000:8000
    volumes:
      - .:/app
    depends_on:
      - db

  queue:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python consumer.py"
    depends_on:
      - db

  db:
    image: mysql:5.7.22
    restart: always
    environment:
      MYSQL_DATABASE: admin
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33066:3306

  dockerhost:
    image: qoomon/docker-host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    restart: on-failure
    networks:
      - backend

  tcp_message_emitter:
    image: alpine
    depends_on:
      - dockerhost
    command: [ "sh", "-c", "while :; do date; sleep 1; done | nc 'dockerhost' 2323 -v"]
    networks:
      - backend

networks:
  backend:
    driver: bridge

Flask 的 docker compose 文件:

version: '3.8'
services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python main.py"
    ports:
      - 8001:5000
    volumes:
      - .:/app
    depends_on:
      - db

  queue:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python consumer.py"
    depends_on:
      - db

  db:
    image: mysql:5.7.22
    restart: always
    environment:
      MYSQL_DATABASE: main
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33067:3306

此时,我知道我遗漏了一些细节或配置错误。

您可以在这里查看 repo:https://github.com/lfbatista/ms-ecommerce

任何帮助将不胜感激。

【问题讨论】:

  • IP地址172.17.0.1从哪里来?你能像Communication between multiple docker-compose projects 中描述的那样在同一个网络上运行这两个 Compose 文件吗?
  • 172.17.0.1 是我在使用镜像 docker-host 时获得的 Django 的 Docker IP。您可以获得运行docker network inspect bridge --format='{{( index .IPAM.Config 0).Gateway}}' 的IP。我会试试你的建议。
  • 您可能需要查看 django_default 网络(即 Compose 为 Django-application Compose 文件创建的 default 网络)。它将不同于“默认桥接网络”(如果您拆除并重新创建这些容器集,它将不会保持不变)。
  • 您不应该在代码中硬编码容器 IP 地址。这就是名称解析的用途。如果您将所有容器放在同一个网络上,它们将能够通过名称相互引用。
  • @DavidMaze 如果我在我的 Django docker compose 文件上设置一个新网络,就像在 [多个 docker-compose 项目之间的通信](stackoverflow.com/questions/38088279/…) 中那样,我将失去与 MySQL 的连接。事实上,使用django_default 网络似乎是正确的道路。问题是我无法获取容器的 IP。我从上面的命令得到的 IP 是来自default 网络的 IP。

标签: python docker networking rabbitmq microservices


【解决方案1】:

这些容器实际上不在同一个网络上。要将来自不同docker-compose 项目的两个容器放入一个网络中,您需要在其中一个文件中“导入”现有网络。你可以这样做:

# first project
networks:
  internal:
  shared:
---
# second project
networks:
  internal:
  shared:
    # This is where all the magic happens:
    external: true  # Means do not create a network, import existing.
    name: admin_shared  # Name of the existing network. It's usually made of <folder_name>_<network_name> .

不要忘记将所有服务放入同一个internal 网络,否则它们将无法相互通信。如果您忘记这样做,Docker 将创建一个&lt;folder_name&gt;-default 网络并将任何没有明确分配网络的容器放在那里。您可以像这样分配网络:

services:
  backend:
    ...
    networks:
      internal:
      # Since this service needs access to the service in another project
      # you put here two networks.
      shared:
        # This part is relevant for this specific question because
        # both projects has services with identical names. To avoid
        # mess with DNS names you can add an additional name to the
        # service using 'alias'. This particular service will be
        # available in shared network as 'flask-backend'.
        aliases:
        - flask-backend

  db:
    ...
    # You can also assign networks as an array if you need no extra configuration:
    networks:
      - internal

这里是您存储库中的文件。除了 IP 地址,一项服务可以分别通过flask-backenddjango-backend 到达另一项服务。请注意,我删除了那些奇怪的“主机网络容器”。

admin/docker-compose.yml

version: '3.8'
services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python manage.py runserver 0.0.0.0:8000"
    ports:
      - 8000:8000
    volumes:
      - .:/app
    depends_on:
      - db
    networks:
      internal:
      shared:
        aliases:
        - django-backend

  queue:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python consumer.py"
    depends_on:
      - db
    networks:
      - internal

  db:
    image: mysql:5.7.22
    restart: always
    environment:
      MYSQL_DATABASE: admin
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33066:3306
    networks:
      - internal

networks:
  internal:
  shared:

ma​​in/docker-compose.yml

version: '3.8'
services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile
    command: "python main.py"
    networks:
      internal:
      shared:
        aliases:
        - flask-backend
    ports:
      - 8001:5000
    volumes:
      - .:/app
    depends_on:
      - db

  queue:
    networks:
      - internal
    build:
      context: .
      dockerfile: Dockerfile
    command: "python consumer.py"
    depends_on:
      - db

  db:
    image: mysql:5.7.22
    restart: always
    networks:
      - internal
    environment:
      MYSQL_DATABASE: main
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33067:3306

networks:
  internal:
  shared:
    external: true
    name: admin_shared

【讨论】:

  • 还是没有运气。你在 main.py 上设置了哪个 IP?
  • @LuisBatista 我使用了django-backend。 IP 地址对于 Docker 来说是非常不可靠的。尝试在后端容器中使用pingcurl - 你会看到它们可以相互访问。从带有docker-compose.yml 的目录:docker-compose exec backend ping &lt;target&gt; 替换为 django-backendflask-backend。对于 curl 将端口添加到目标:django-backend:8000flask-backend:5000
  • @LuisBatista 另请注意 django 容器输出中的行:backend_1 | Invalid HTTP_HOST header: 'django-backend:8000'. You may need to add 'django-backend' to ALLOWED_HOSTS.
  • 我确认每个容器都可以相互访问,但是在flask-backend 上向端口5000 发出请求我得到错误:sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2005, "Unknown MySQL server host 'db' (-3)")
  • @LuisBatista 我没有这样的错误,我有另一个错误:“表'main.product'不存在”所以连接对我有用。您没有忘记将db 放在internal 网络上并重新启动容器吧?
猜你喜欢
  • 2016-12-21
  • 1970-01-01
  • 2023-03-22
  • 2019-08-25
  • 1970-01-01
  • 2017-02-27
  • 2017-09-12
  • 1970-01-01
  • 2021-06-14
相关资源
最近更新 更多