使 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 地址。
问题已解决:
使用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
我有 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 地址。
问题已解决:
使用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