为 Docker 容器分配静态 IP

Posted

技术标签:

【中文标题】为 Docker 容器分配静态 IP【英文标题】:Assign static IP to Docker container 【发布时间】:2015-03-12 07:07:31 【问题描述】:

我现在尝试在启动 Docker 容器时分配静态 IP 172.17.0.1。

我使用 2122 端口作为这个容器的 ssh 端口,以便让这个容器监听 2122 端口。

sudo docker run -i -t -p 2122:2122 ubuntu

这个命令将运行一个带有随机 IP 的 Docker 容器,比如 172.17.0.5,但是我需要为容器分配一个特定的 IP。

以下shell脚本是我在高级网络设置中参考的Docker文档。

pid=$(sudo docker inspect -f '.State.Pid' <container_name> 2>/dev/null)
sudo rm -rf /var/run/netns/*
sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
sudo ip link add A type veth peer name B
sudo brctl addif docker0 A
sudo ip link set A up
sudo ip link set B netns $pid
sudo ip netns exec $pid ip link set eth0 down
sudo ip netns exec $pid ip link delete eth0
sudo ip netns exec $pid ip link set dev B name eth0
sudo ip netns exec $pid ip link set eth0 address 12:34:56:78:9a:bc
sudo ip netns exec $pid ip link set eth0 down
sudo ip netns exec $pid ip link set eth0 up
sudo ip netns exec $pid ip addr add 172.17.0.1/16 dev eth0
sudo ip netns exec $pid ip route add default via 172.17.42.1

这个 shell 脚本将分配一个静态 IP 172.17.0.1 并链接到世界。但是每当我尝试从本地 ssh 到这个容器时,它都不起作用。我可能遇到了什么问题?

【问题讨论】:

这个问题恐怕没有简单的答案,见github.com/docker/docker/issues/6743和github.com/docker/docker/issues/1179,读github.com/jpetazzo/pipework @larrylo 你能确认你在容器内启动了一个 sshd 吗? 您正在撤消 docker 守护进程为您执行的所有路由。容器不是虚拟机。 是的,我确认我可以在容器内启动 sshd How can I set a static IP address in a Docker container?的可能重复 【参考方案1】:

轻松使用 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/

【讨论】:

很好的答案 - 只需添加一些附加信息:blog.jessfraz.com/post/ips-for-all-the-things @cantSleepNow 出于某种原因,我只需要使用我自己默认创建的网桥 br0,它是在系统启动期间在接口文件中创建的(因此它不是使用 docker network create 创建的),你能建议我如何我可以在不使用 docker 创建网桥的情况下获得与 --ip 参数相同的效果(获取容器的固定 IP 地址)吗? @MohammedNoureldin 我不完全理解 - 听起来也是一个新问题,我认为你应该这样问。 @cantSleepNow 我的意思是我需要修复容器的 IP 地址,尽管我没有使用自定义网桥(所以不能使用 --ip 参数),您有什么方法可以解决这个问题吗? @MohammedNoureldin 我不确定。正如我所说,将您的问题作为问题而不是评论发布 - 也许有人知道答案。【参考方案2】:

对于docker-compose,您可以使用以下docker-compose.yml

version: '2'
services:
  nginx:
    image: nginx
    container_name: nginx-container
    networks:
      static-network:
        ipv4_address: 172.20.128.2
networks:
  static-network:
    ipam:
      config:
        - subnet: 172.20.0.0/16
          #docker-compose v3+ do not use ip_range
          ip_range: 172.28.5.0/24

您可以使用以下主机进行测试:

docker-compose up -d
curl 172.20.128.2

现代docker-compose 不会那么频繁地更改 IP 地址。

要在一行中查找docker-compose 中所有容器的 ip,请使用:

for s in `docker-compose ps -q`; do echo ip of `docker inspect -f ".Name" $s` is `docker inspect -f 'range .NetworkSettings.Networks.IPAddressend' $s`; done

如果你想自动化,你可以使用类似example gist的东西

【讨论】:

看起来这只适用于 docker-compose v2,v3 破坏了兼容性。 使用docker-compose v3+时删除ip_range 我没有得到 ip_range。这不是被子网覆盖吗?无论如何,谢谢你!这解决了我的“我必须再次查找我的 mongo 容器的 ip” - 问题 有没有办法在compose版本3中指定ip地址? 如果没有ip_range,该解决方案对我来说效果很好。我正在使用版本:'3.4'。【参考方案3】:

不是直接的答案,但它可以提供帮助。

我使用下一种方法运行与自己的静态 ips 绑定的大部分 dockerized 服务:

    我为 docker 主机上的所有服务创建 ip 别名 然后我运行每个服务,将端口从这个 ip 重定向到容器中,这样每个服务都有自己的静态 ip,可供外部用户和其他容器使用。

示例:

docker run --name dns --restart=always -d -p 172.16.177.20:53:53/udp dns
docker run --name registry --restart=always -d -p 172.16.177.12:80:5000 registry
docker run --name cache --restart=always -d -p 172.16.177.13:80:3142 -v /data/cache:/var/cache/apt-cacher-ng cache
docker run --name mirror --restart=always -d -p 172.16.177.19:80:80 -v /data/mirror:/usr/share/nginx/html:ro mirror
...

【讨论】:

谢谢~我知道了。就像github.com/brandon-rhodes/fopnp/tree/m/playground 一样。我会试试的。 这是一个很好的解决方案,我只是附上这个链接让新用户了解别名cyberciti.biz/faq/… 感谢您的出色解决方案。 我不清楚这个答案在 OP 的上下文中如何有用。问题是关于为容器分配一个静态 IP 地址,即172.16.177.20dns 容器,但除非dns 容器已经分配了172.16.177.20,否则此处的命令将不起作用。确保 dns 容器实际获取 IP 地址172.16.177.20 的部分在哪里?我错过了什么?【参考方案4】:

我在尝试 dockerise Avahi 时偶然发现了这个问题,它需要知道其公共 IP 才能正常运行。由于 Docker 中的 lack of support for static IP assignment,为容器分配静态 IP 很棘手。

This article 描述了如何将静态 IP 分配给Debian 上的容器的技术:

    Docker 服务应该以DOCKER_OPTS="--bridge=br0 --ip-masq=false --iptables=false" 启动。我假设 br0 网桥已经配置好了。

    容器应该以--cap-add=NET_ADMIN --net=bridge开始

    /etc/network/interfaces 中的容器 pre-up ip addr flush dev eth0 可用于关闭 Docker 分配的 IP 地址,如下例所示:


auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    pre-up ip addr flush dev eth0
    address 192.168.0.249
    netmask 255.255.255.0
    gateway 192.168.0.1
    容器的入口脚本应该以/etc/init.d/networking start开头。此外,入口脚本需要编辑或填充 /etc/hosts 文件,以删除对 Docker 分配的 IP 的引用。

【讨论】:

【参考方案5】:

这对我有用。

创建一个网络 docker network create --subnet=172.17.0.0/16 selnet

运行 docker 镜像 docker run --net selnet --ip 172.18.0.2 hub

一开始,我明白了

docker: Error response from daemon: Invalid address 172.17.0.2: It does not belong to any of this network's subnets.
ERRO[0000] error waiting for container: context canceled

解决方案:增加第二个四倍的 IP [.18.而不是 .17.]

【讨论】:

本页其他地方有 2 岁以上类似/相同的答案:***.com/a/35359185/694469【参考方案6】:

你可以在运行的时候设置IP。

docker run --cap-add=NET_ADMIN -dit imagename /bin/sh -c "/sbin/ip addr add 172.17.0.12 dev eth0; bash"

在https://github.com/RvdGijp/mariadb-10.1-galera查看我的示例

【讨论】:

不幸的是这增加了一个IP地址,如果在之前的过程中分配了一个IP地址,这将导致有两个IP地址【参考方案7】:

您可以通过名称访问其他容器的服务(ping apache 将获得 ip 或 curl http://apache 将访问 http 服务)这可以替代静态 ip。

【讨论】:

在 1.8 的 docker 版本中可以直接使用。在较新的版本中,您必须首先链接这些容器。【参考方案8】:

如果您希望您的容器拥有自己的虚拟以太网套接字(具有自己的 MAC 地址)、iptables,则使用 Macvlan 驱动程序。这可能需要将流量路由到您的/ISP 路由器。

https://docs.docker.com/engine/userguide/networking/get-started-macvlan

【讨论】:

以上是关于为 Docker 容器分配静态 IP的主要内容,如果未能解决你的问题,请参考以下文章

FW Docker为容器分配指定物理网段的静态IP

是否可以将静态公共 IP 分配给 Docker 容器?

OVS+Docker网络打通

Docker 容器的多个静态 IP

Docker部署ewomail邮件服务器

docker实现跨主机通信(使用静态路由方式)