使 docker 使用 IPv4 进行端口绑定

Make docker use IPv4 for port binding

我有 docker 主机,里面有一个容器。

docker 主机仅在 IPv6 接口上绑定端口,而不是在 IPv4 上。

这是输出

tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:55082           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::40280                :::*                    LISTEN      -
tcp6       0      0 :::5432                 :::*                    LISTEN      -
tcp6       0      0 :::40122                :::*                    LISTEN      -
tcp6       0      0 :::36378                :::*                    LISTEN      -
tcp6       0      0 :::40543                :::*                    LISTEN      -
tcp6       0      0 :::111                  :::*                    LISTEN      -

现在我在主机上有 40122 端口到 link,在容器上有端口 22。

我想通过 SSH 连接到那个容器,但我不能,因为它只绑定到 IPv6

这是我的 docker 版本 Docker version 1.5.0, build a8a31ef

docker ps

201bde6c839a        myapp:latest   "supervisord -n"    3 weeks ago         Up 2 hours          0.0.0.0:40122->22/tcp, 0.0.0.0:40280->80/tcp, 0.0.0.0:40543->443/tcp   myapp

我 运行 使用 docker run -d -P -p 40122:22

netstat -tlna

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3031          0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::6379                 :::*                    LISTEN

ps辅助

root         1  0.0  0.8  52440 16668 ?        Ss   00:53   0:03 /usr/bin/python /usr/bin/supervisord -n
root        49  0.0  0.1  17980  3048 ?        S    01:32   0:00 bash
root        64  0.0  0.1  46632  2712 ?        S    01:32   0:00 su -l vagrant
vagrant     65  0.0  0.1  21308  3760 ?        S    01:32   0:00 -su
root       288  0.0  0.1  17980  3088 ?        S    02:01   0:00 bash
root       304  0.0  0.1  46632  2720 ?        S    02:01   0:00 su -l vagrant
vagrant    305  0.0  0.1  21304  3804 ?        S    02:01   0:00 -su
vagrant    308  0.0  3.7 429616 75840 ?        Sl+  02:01   0:05 python ./manage.py shell_plus
root       654  0.0  0.4  47596  9848 ?        S    03:12   0:01 /usr/local/bin/uwsgi --die-on-term --ini /var/www/conf/uwsgi.ini
root       655  0.0  0.3  90280  7732 ?        S    03:12   0:00 nginx: master process /usr/sbin/nginx
www-data   656  0.0  0.1  90600  3624 ?        S    03:12   0:00 nginx: worker process
www-data   657  0.0  0.1  90600  3624 ?        S    03:12   0:00 nginx: worker process
www-data   658  0.0  0.1  90600  3624 ?        S    03:12   0:00 nginx: worker process
www-data   659  0.0  0.2  90940  4500 ?        S    03:12   0:00 nginx: worker process
root       660  0.0  0.2  61372  5332 ?        S    03:12   0:00 /usr/sbin/sshd -D
root       669  0.0  0.4  37004  8892 ?        Sl   03:12   0:01 redis-server *:6379
root       856  8.0  2.8 388720 57792 ?        Sl   04:07   0:18 /usr/local/bin/uwsgi --die-on-term --ini /var/www/conf/uwsgi.ini
root       857  8.0  2.8 388720 57792 ?        Sl   04:07   0:18 /usr/local/bin/uwsgi --die-on-term --ini /var/www/conf/uwsgi.ini
root       858  8.0  2.8 388720 57792 ?        Sl   04:07   0:18 /usr/local/bin/uwsgi --die-on-term --ini /var/www/conf/uwsgi.ini
root       859  8.0  2.8 388720 57792 ?        Sl   04:07   0:18 /usr/local/bin/uwsgi --die-on-term --ini /var/www/conf/uwsgi.ini
vagrant    889  0.0  0.1  18692  2508 ?        R+   04:11   0:00 ps aux

正如@daniel-t 在评论中指出的那样:github.com/docker/docker/issues/2174 是关于在 netstat 中仅显示与 IPv6 的绑定,但这不是问题。正如 github 问题所述:

When setting up the proxy, Docker requests the loopback address '127.0.0.1', Linux realises this is an address that exists in IPv6 (as ::0) and opens on both (but it is formally an IPv6 socket). When you run netstat it sees this and tells you it is an IPv6 - but it is still listening on IPv4. If you have played with your settings a little, you may have disabled this trick Linux does - by setting net.ipv6.bindv6only = 1.

换句话说,仅仅因为您将其视为仅 IPv6,它仍然能够在 IPv4 上通信,除非您使用 net.ipv6.bindv6only 设置将 IPv6 设置为仅绑定到 IPv6。需要明确的是,net.ipv6.bindv6only 应该是 0 - 你可以 运行 sysctl net.ipv6.bindv6only 来验证。

如果您希望您的容器端口绑定到您的 ipv4 地址,只需:

  • 找到设置文件
    • /etc/sysconfig/docker-network 在 RedHat 上类似
    • /etc/default/docker-network 在 Debian 上类似
  • 编辑网络设置
    • 添加DOCKER_NETWORK_OPTIONS=-ip=xx.xx.xx.xx
    • xx.xx.xx.xx 是你真正的 ipv4(而不是 0.0.0.0)
  • 重启docker守护进程

适用于 docker 1.9.1

设置 net.ipv6.conf.all.forwarding=1 将解决问题。

这可以在实时系统上使用 sudo sysctl -w net.ipv6.conf.all.forwarding=1

默认情况下,docker 使用可用于 IPv4 和 IPv6 连接的 AF_INET6 套接字。这会导致 netstat 报告侦听地址的 IPv6 地址。

来自红帽 https://access.redhat.com/solutions/3114021

问题已解决

使用docker run -it -p 80:80 --name nginx --net=host -d nginx

这是我们有时使用 VM 而不是桥接网络时遇到的问题,请尝试使用适合您的主机

tcp     0    0 0.0.0.0:80            0.0.0.0:*             LISTEN      - 
tcp6    0    0 :::80                 :::*                  LISTEN      -  

对于 CentOS 用户,

我在 CentOS7 上遇到了同样的问题,将 net.ipv4.ip_forward 设置为 1 解决了这个问题。请参阅了解更多详情。

2021 年更新:

目前 docker 默认绑定到 IPv4 和 IPv6。

如果您想明确地“使docker使用IPv4进行端口绑定”(例如,只绑定到 IPv4 端口)在 -p/--publish 选项中的端口前添加 0.0.0.0:,如下所示:

$ docker run --publish "0.0.0.0:80:80" --publish "0.0.0.0:443:443" --detach nginx

完成后结果将如下所示:

$ docker ps

CONTAINER ID   IMAGE   COMMAND                  CREATED          STATUS         PORTS                                      NAMES
2459bd225751   nginx   "/docker-entrypoint.…"   4 seconds ago    Up 2 seconds   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   jovial_yonath

netstat 结果将如下所示:

$ sudo netstat -tulnp

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State    PID/Program name
tcp        0      0 0.0.0.0:443   0.0.0.0:*       LISTEN   22676/docker-proxy
tcp        0      0 0.0.0.0:80    0.0.0.0:*       LISTEN   22698/docker-proxy

当然,您可以浏览或 curl 到设备以确保其正常工作。

如果不添加“0.0.0.0”,它将绑定两个 IP 版本,PORTS 将显示为 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp,这可能不利于安全,控制台垃圾邮件或可预测性原因。

尝试删除已创建网络的 --可附加 标志

不起作用

docker network create --attachable --driver overlay --subnet=10.0.3.0/24 --gateway=10.0.3.1 dev

它可以工作,但是当您检查时仍然没有看到 listeness IPv4 端口 sudo netstat -tulnp4

docker network create --attachable --driver overlay --subnet=10.0.3.0/24 --gateway=10.0.3.1 dev