使用Docker容器作为网络网关

10

我想配置一个网关来连接两个容器。以下是一个创建三个容器的示例组合文件——test_client、test_server和proxy。代理服务器应该作为所有从test_client到test_server的流量的默认网关。我使用的是组合文件格式v2,因为IPAM网关配置在v3中不受支持。

version: "2"
services:
  proxy:
    build: .
    cap_add:
      - NET_ADMIN
    expose:
      - 8080
      - 80
      - 443
    networks:
      client_network:
          ipv4_address: '192.168.0.5'
      server_network: null
    stdin_open: true
    tty: true
  test_server:
    build: ./test_server
    expose:
      - 8000
    networks:
      - server_network
  test_client:
    build: ./test_client
    networks:
      - client_network
    stdin_open: true
    tty: true

networks:
  client_network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: "192.168.0.0/24"
          gateway: "192.168.0.5"
  server_network:
    driver: bridge

当我运行docker-compose up时,出现以下错误:
ERROR: for 28e458cec9ac_network_proxy_1  b'user specified IP address is supported only when connecting to networks with user configured subnets'

我阅读了以下资源: SO: docker container as gateway between two docker bridges Docker forums 但它们似乎不能帮助我回答如何设置这个问题。我没有承诺任何特定的网络结构 - 我想要的唯一是配置一个容器作为两个其他容器之间的网络级网关。

好的,我真的不确定这个问题,但考虑到你在docker-compose文件中唯一的网络是“用户指定”的意思是你明确定义了它,你的问题可能是你正在使用一个已经被主机网络使用的子网。也许换成192.168.5.0/24看看是否有所改变? - NicolasB
遇到了同样的问题。你的docker-compose文件看起来没问题。我猜你尝试创建了没有子网配置的东西,现在docker不会更新网络配置为指定子网的那个...用docker network inspect client_network检查一下。如果是这种情况,请勿使用“docker network rm”删除它,否则会破坏很多东西(我刚刚发现了这个问题),似乎应该通过docker-compose down删除网络...参见:https://github.com/docker/compose/issues/5745#issuecomment-370031631(我没有测试过,选择了错误的方法) - mozzbozz
1个回答

9

很遗憾,桥接网络(或任何其他类型的Docker网络)并不真正支持这种用例。问题在于桥接网络使用主机作为网关。它通过在桥接网络上为您的主机创建虚拟接口并执行一些主机配置来实现必要的路由。 gateway选项仅配置将分配给此虚拟接口的IP地址。

这似乎没有被很好地记录,我认为这是Docker网络的一个实现细节。我从几篇论坛帖子中发现了这个问题:来源1来源2

编辑:这是我的工作docker-compose文件,其中有两个私有网络,每个网络都有自己的网关,即 alice <-> moon <-> sun <-> bob。其中的魔法在于command:块内每个容器运行的ipiptables命令。忽略tail -f /dev/null,它只是一个永远不会完成的命令,这意味着容器一直运行,直到您杀死它。

version: "3.3"

services:

  alice:
    image: ubuntu-with-tools
    cap_add:
      - NET_ADMIN
    hostname: alice
    networks:
      moon-internal:
        ipv4_address: 172.28.0.3
    command: >-
      sh -c "ip route del default &&
      ip route add default via 172.28.0.2 &&
      tail -f /dev/null"

  moon:
    image: ubuntu-with-tools
    cap_add:
      - NET_ADMIN
    hostname: moon
    networks:
      moon-internal:
        ipv4_address: 172.28.0.2
      internet:
        ipv4_address: 172.30.0.2
    command: >-
      sh -c "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE &&
      iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE &&
      iptables -A FORWARD -i eth1 -j ACCEPT &&
      iptables -A FORWARD -i eth0 -j ACCEPT &&
      ip route add 172.29.0.0/16 via 172.30.0.4 &&
      tail -f /dev/null"


  sun:
    image: ubuntu-with-tools
    cap_add:
      - NET_ADMIN
    hostname: sun
    networks:
      sun-internal:
        ipv4_address: 172.29.0.4
      internet:
        ipv4_address: 172.30.0.4
    command: >-
      sh -c "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE &&
      iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE &&
      iptables -A FORWARD -i eth1 -j ACCEPT &&
      iptables -A FORWARD -i eth0 -j ACCEPT &&
      ip route add 172.28.0.0/16 via 172.30.0.2 &&
      tail -f /dev/null"

  bob:
    image: ubuntu-with-tools
    cap_add:
      - NET_ADMIN
    hostname: bob
    networks:
      sun-internal:
        ipv4_address: 172.29.0.5
    command: >-
      sh -c "ip route del default &&
      ip route add default via 172.29.0.4 &&
      tail -f /dev/null"


networks:
  moon-internal:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
  sun-internal:
    driver: bridge
    ipam:
      config:
        - subnet: 172.29.0.0/16
  internet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/16

要试一下,请运行docker exec -it ipsec-playground_bob_1 tcpdumpdocker exec -it ipsec-playground_alice_1 ping 172.29.0.5。你应该看到来自alice的ping请求到达了bob。

ubuntu-with-tools 是一个简单的Ubuntu镜像,其中安装了我想要的一些工具,以下是Dockerfile文件:

FROM ubuntu
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y iproute2 inetutils-ping curl host mtr-tiny tcpdump iptables \
    && rm -rf /var/lib/apt/lists/*

这看起来很棒!谢谢。我之前一直在做这个,但希望很快能有机会测试它。一旦我试过了,我会将其标记为被接受的答案。 - Orphid
1
它不能在“内部”网络中工作,为什么? - Taknok
@Taknok 我花了很多时间试图回答同样的问题,但一无所获。 - undefined
1
哦,奇怪,这可能是因为Docker在内部使用iptables来实现内部网络。无论它做了什么,都可能与这个设置不兼容。如果是这样的话,要使其正常工作,你需要使用不同的命令。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接