如何使docker-compose仅在定义的网络上绑定容器而不是0.0.0.0?

时间:2017-07-14 18:18:36

标签: docker docker-compose

在最近的版本中,docker-compose会自动为其创建的服务创建新网络。基本上,每个docker-compose设置都有自己的IP范围,因此理论上我可以使用预定义的端口在网络的IP地址上调用我的服务。这在同时开发多个项目时非常好,因为无需更改docker-compose.yml中的端口(即我可以在不同接口上的端口8080上同时运行多个nginx项目)

但是,这不能按预期工作:每个公开的端口仍然在0.0.0.0上公开,因此与多个项目存在端口冲突。可以将绑定IP放入docker-compose.yml,但这是可移植性的杀手 - 并非团队中的每个开发人员都使用相同的操作系统或在同一个项目上工作,因此不清楚哪个要配置的IP。

根据为此特定项目创建的网络,定义用于绑定容器的IP非常棒。 docker-compose应该知道它创建了哪个网络以及它的IP,所以这不应该是一个问题,但是我找不到一个简单的方法。有没有办法或是否有待实施?

编辑:端口冲突的一个例子:想象两个项目,每个项目都有一个在端口8080上运行的应用服务器和一个在端口3306上运行的MySQL数据库,两个项目分别暴露为" 8080:8080"和" 3306:3306"。使用docker-compose运行第一个网络会创建一个名为app1_network的网络,其IP范围为172.18.0.0/16。每个公开的端口在广域网(172.17.0.0/16)和172.18.0.0 / 16上的0.0.0.0(即127.0.0.1)上公开。在这种情况下,我可以访问我的应用程序服务器127.0.0.1:8080,172.17.0.1:8080,172.18.0.1:8080以及$WAN_IP:8080上的als。如果我现在启动第二个应用程序,它会启动第二个网络app2_network 172.19.0.0/16,但仍尝试绑定所有接口上的每个公开端口。当然已经采用了这些端口(172.19.0.1除外)。如果有可能将每个应用程序限制在其网络中,则应用程序1将在172.18.0.1:8080处可用,第二个应用程序在172.19.0.1:8080处可用,并且我不需要将端口映射更改为8081和3307分别同时运行两个应用程序。

3 个答案:

答案 0 :(得分:12)

在您的服务配置中,在docker-compose.yml:

ports:
 - "127.0.0.1:8001:8001"

参考:https://docs.docker.com/compose/compose-file/#ports

答案 1 :(得分:3)

您可以通过在端口之前包含IP来将端口发布到主机上的单个IP地址:

docker run -p 127.0.0.1:80:80 -d nginx

以上在loopback接口上运行nginx。您可以在docker-compose.yml文件中使用类似的端口映射。 e.g:

ports:
  - "127.0.0.1:80:80"

docker-compose没有任何特殊能力来推断基于docker网络使用哪个网络接口。您需要指定要在每个撰写文件中使用的唯一IP地址,并且该IP需要用于主机上的网络接口。对于开发人员机器,当IP为笔记本电脑/工作站提供新地址时,该IP可能会发生变化。

由于难以实现您的目标,大多数会将主机上的不同端口映射到不同的容器,因此容器a为13307:3307,容器b为23307:3307,容器c为33307:3307,或者是任何数字方案对你有意义。在处理HTTP流量时,使用像traefik这样的反向代理通常是最有意义的。

答案 2 :(得分:1)

可以通过在docker-compose文件中配置网络来实现。

请在下面考虑两个docker-compose文件。仍然存在需要在您同时处理的所有项目中指定唯一的子网的缺点。另一方面,您还需要知道连接的是哪个服务-这就是为什么它不能动态分配它的原因。

my-project.yaml:

    static void Main(string[] args)
    {
        bool keepPlaying = true;
        int wins = 0, losses = 0, ties = 0;
        do
        {
            Console.WriteLine();
            Console.WriteLine($"Win={wins}, Loss={losses}, Tie={ties}");
            Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
            var input = Console.ReadLine();                   
            var computer = (Move)rng.Next(0, 3);
            // Parse input and decide if the user made a move
            // or wants to quit (invalid input or none).
            if (PlayerMove(input, out Move player))
            {
                Console.Write($"Player: {player}, Computer: {computer} => ");
                // Decide the outcome of the game here
                Outcome game = DecideGame(player, computer);
                switch (game)
                {
                    case Outcome.Tie:
                        ties++;
                        Console.WriteLine("Tie");
                        break;
                    case Outcome.Loss:
                        losses++;
                        Console.WriteLine("loss");
                        break;
                    case Outcome.Win:
                        wins++;
                        Console.WriteLine("Win");
                        break;
                    default:
                        throw new NotSupportedException();
                }
            }
            else
            {
                // stop when user just pressed enter.
                keepPlaying = input.Length>0;
            }
        } while (keepPlaying);
    }

my-other-project.yaml

services:
nginx:
    networks:
      - my-project-network
    image: nginx
    ports:
      - 80:80

networks:
  my-project-network:
    driver_opts:
      com.docker.network.bridge.host_binding_ipv4: "172.20.0.1"
    ipam:
      config:
        - subnet: "172.20.0.0/16"

注意:如果您将其他服务绑定到*:80,例如在主机上运行的即时apache -它也将绑定在docker-compose网络的接口上,因此您将无法使用此端口。

要运行以上两项服务:

services:
  nginx:
    networks:
      - my-other-project-network
    image: nginx
    ports:
      - 80:80

networks:
  my-other-project-network:
    driver_opts:
      com.docker.network.bridge.host_binding_ipv4: "172.21.0.1"
    ipam:
      config:
        - subnet: "172.21.0.0/16"