【问题标题】:How can I set a static IP address in a Docker container?如何在 Docker 容器中设置静态 IP 地址?
【发布时间】:2014-10-21 04:04:36
【问题描述】:

我对 docker 默认给我的 IP 范围 176.17.x.x 非常满意,所以我不需要创建新的网桥,我只想给我的容器一个静态地址 within 该范围,因此我可以将客户端浏览器直接指向它。 我尝试使用

RUN echo "auto eth0" >> /etc/network/interfaces
RUN echo "iface eth0 inet static" >> /etc/network/interfaces
RUN echo "address 176.17.0.250" >> /etc/network/interfaces
RUN echo "netmask 255.255.0.0" >> /etc/network/interfaces
RUN ifdown eth0
RUN ifup eth0

来自 Dockerfile,它正确地填充了接口文件,但接口本身并没有改变。事实上,在容器内运行 ifup eth0 会得到这个错误:

RTNETLINK 回答:Operation not allowed 无法启动 eth0

【问题讨论】:

  • 您可以尝试使用 --net=host 选项。然后容器将在主机的 IP 地址上可用。
  • 谢谢马克。我重新编写了 Dockerfile 以使用我的静态 IP 设置一个名为 docker0(这是 --net=host 将创建的接口)的接口,构建映像并使用 --net=host 加载它。但是 docker0 仍然从 DHCP 获取它的 IP,并且 ifup docker0 仍然不起作用。

标签: linux networking docker


【解决方案1】:

我已经在这里回答过了 https://stackoverflow.com/a/35359185/4094678 但我现在看到这个问题实际上比上述问题更老,所以我也会复制答案:

轻松使用 Docker 版本 1.10.1,构建 9e83765。

首先您需要创建自己的 docker 网络 (mynet123)

docker network create --subnet=172.18.0.0/16 mynet123

而不是简单地运行图像(我将以 ubuntu 为例)

docker run --net mynet123 --ip 172.18.0.22 -it ubuntu bash

然后在 ubuntu shell 中

ip addr

此外,您可以使用
--hostname 指定主机名
--add-host/etc/hosts 添加更多条目

文档(以及为什么需要创建网络)https://docs.docker.com/engine/reference/commandline/network_create/

【讨论】:

    【解决方案2】:

    我正在使用官方 Docker 文档中编写的 here 方法,并且我已经确认它有效:

    # At one shell, start a container and
    # leave its shell idle and running
    
    $ sudo docker run -i -t --rm --net=none base /bin/bash
    root@63f36fc01b5f:/#
    
    # At another shell, learn the container process ID
    # and create its namespace entry in /var/run/netns/
    # for the "ip netns" command we will be using below
    
    $ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
    2778
    $ pid=2778
    $ sudo mkdir -p /var/run/netns
    $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
    
    # Check the bridge's IP address and netmask
    
    $ ip addr show docker0
    21: docker0: ...
    inet 172.17.42.1/16 scope global docker0
    ...
    
    # Create a pair of "peer" interfaces A and B,
    # bind the A end to the bridge, and bring it up
    
    $ sudo ip link add A type veth peer name B
    $ sudo brctl addif docker0 A
    $ sudo ip link set A up
    
    # Place B inside the container's network namespace,
    # rename to eth0, and activate it with a free IP
    
    $ sudo ip link set B netns $pid
    $ sudo ip netns exec $pid ip link set dev B name eth0
    $ sudo ip netns exec $pid ip link set eth0 up
    $ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
    $ sudo ip netns exec $pid ip route add default via 172.17.42.1
    

    使用这种方法,我总是使用 net=none 运行我的容器,并使用外部脚本设置 IP 地址。

    【讨论】:

    • 只是尝试这个建议,但我遇到了一个问题:设置--net=none 似乎无法使用--link 容器。这是正确的吗?
    • 抱歉,我从来没有使用过 --link 命令(因为我的容器不互相通信)
    • 没有问题。发表评论后,我想了更多,它不起作用是有道理的。但是,您可以配置多个容器以通过您展示的方法相互通信,这也是有意义的。这似乎是pipework 的方法(我现在正在尝试使用)
    • 我得到了对象“netns”未知,尝试“ip help”。
    【解决方案3】:

    实际上,尽管我最初失败了,@MarkO'Connor 的回答是正确的。我在主机 /etc/network/interfaces 文件中创建了一个新接口 (docker0),在主机上运行 sudo ifup docker0,然后 然后 运行

    docker run --net=host -i -t ... 
    

    它获取了静态 IP 并将其分配给容器中的 docker0。

    谢谢!

    【讨论】:

      【解决方案4】:

      这对我有用:

      docker run --cap-add=NET_ADMIN -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"
      

      解释:

      • --cap-add=NET_ADMIN 拥有管理网络的权限(即对于/sbin/ip 命令)

      • myimages/image1 容器的图像

      • /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0 ; bash" 在容器内运行 ip addr add 172.17.0.8 dev eth0 以向该容器添加一个新的 IP 地址 172.17.0.8(注意:请务必使用免费的 IP 地址现在将来)。然后运行 ​​bash,只是为了不让容器自动停止。

      奖金

      我的目标场景:设置一个分布式应用程序,其中容器在 dist-app 中扮演不同的角色。 “导体容器”能够自行(在内部)运行 docker 命令,以便根据需要启动和停止容器。 每个容器都被配置为知道在哪里连接以访问 dist-app 中的特定角色/容器(因此每个角色的 ip 集必须由每个合作伙伴知道)。

      为此:

      1. “导体容器”

      使用此 Dockerfile 创建的映像

      FROM pin3da/docker-zeromq-node
      MAINTAINER Foobar
      
      # install docker software  
      RUN apt-get -yqq update && apt-get -yqq install docker.io 
      
      # export /var/run/docker.sock  so we can connect it in the host
      VOLUME /var/run/docker.sock
      

      镜像构建命令:

      docker build --tag=myimages/conductor --file=Dockerfile .
      

      容器运行命令:

      docker run -v /var/run/docker.sock:/var/run/docker.sock --name=conductor1 -d -it myimages/conductor  bash
      
      1. 运行具有不同角色的容器。

      首先(不是绝对必要)将条目添加到 /etc/hosts 以通过 ip 或名称查找合作伙伴(选项 --add-host

      第二个(显然是必需的)为正在运行的容器分配一个 ip(使用 /sbin/ip在里面)

      docker run --cap-add=NET_ADMIN --add-host worker1:172.17.0.8 --add-host worker2:172.17.0.9 --name=worker1 -h worker1.example.com -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"
      

      【讨论】:

        【解决方案5】:

        默认情况下,Docker 容器没有足够的权限来操作网络堆栈。您可以尝试将--cap-add=NET_ADMIN 添加到运行命令以启用此特定功能。或者您可以尝试--privileged=true(授予所有权利)进行测试。

        另一种选择是使用主机的pipework

        【讨论】:

          【解决方案6】:

          & 与pipework192.168.1.1 下面是default gateway ip 地址):

          pipework br0 container-name 192.168.1.10/24@192.168.1.1
          

          编辑:不要以 --net=none 开头:这会关闭容器端口。

          further notes

          【讨论】:

            【解决方案7】:

            我知道您现阶段并没有考虑容器的多主机网络,但我相信您可能很快就会需要它。 Weave 将允许您首先在一个主机上定义多个容器网络,然后可能将一些容器移动到另一台主机,而不会丢失您分配给它的静态 IP。

            【讨论】:

            • 用 Wea​​ve 解释静态 IP?在文档中找不到它(这并不是不正确解释答案的借口)。
            • 您可以使用-e WEAVE_CIDR=ip:192.168.1.2/24 启动一个容器,并且假设您在shell (weave launch; eval $(weave env)) 中运行了Weave Net 和代理环境设置,该容器应该获得您指定的IP 地址。
            【解决方案8】:

            pipework 也很棒,但是如果您可以使用 ip 以外的主机名,那么您可以试试这个脚本

            #!/bin/bash
            # This function will list all ip of running containers
            function listip {
                for vm in `docker ps|tail -n +2|awk '{print $NF}'`; 
                    do
                        ip=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $vm`;
                        echo "$ip  $vm";
                    done    
            }
            
            # This function will copy hosts file to all running container /etc/hosts
            function updateip {
                    for vm in `docker ps|tail -n +2|awk '{print $NF}'`;
                            do
                                    echo "copy hosts file to  $vm";
                                    docker exec -i $vm sh -c 'cat > /etc/hosts' < /tmp/hosts
                            done
            }
            
            listip > /tmp/hosts
            updateip
            

            您只需在每次启动 docker labs 时运行此命令 你可以在这里找到我的脚本dockerip

            【讨论】:

              【解决方案9】:

              为了完整起见:Docker 论坛上建议了另一种方法。 (编辑:并顺便提到了来自 Андрей Сердюк 的答案)。

              host 系统上添加静态 IP 地址,然后将端口发布到该 ip,例如docker run -p 192.0.2.1:80:80 -d mywebserver.

              当然,该语法不适用于 IPv6,文档也没有提到...

              对我来说这听起来不对:主机上通常的通配符绑定 (*:80) 理论上与容器冲突。在实践中,Docker 端口优先且不冲突,因为它是如何使用 iptables 实现的。但是您的公共容器 IP 仍将响应所有 冲突端口,例如ssh。

              【讨论】:

                【解决方案10】:

                我发现--net=host 可能并不总是最好的选择,因为它可能允许用户从容器中关闭主机!无论如何,事实证明我无法从内部正确执行此操作的原因是因为网络配置被设计为仅限于以 --privileged=true 参数开头的会话。

                【讨论】:

                  【解决方案11】:

                  您可以使用服务发现工具设置 SkyDns - https://github.com/crosbymichael/skydock

                  或者:只需创建网络接口并在其中发布 docker 容器端口,就像这里 https://gist.github.com/andreyserdjuk/bd92b5beba2719054dfe

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2022-11-27
                    • 1970-01-01
                    • 2020-09-25
                    • 2021-01-04
                    • 1970-01-01
                    • 2016-12-02
                    • 2022-11-22
                    • 1970-01-01
                    相关资源
                    最近更新 更多