我有一个具有默认网络配置和如下定义的组合:
services:
myservice:
image: someimage
restart: always
ports:
- 80:80
- 443:443
该服务正确绑定到 IPv4,可以按预期访问。一两周以来,该服务不再绑定到 IPv6,而之前运行没有问题。运行netstat -plnt
显示 docker-proxy 未监听 IPv6 端口:
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:6379 0.0.0.0:* LISTEN 1936/docker-proxy
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1898/docker-proxy
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 811/systemd-resolve
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 1883/docker-proxy
tcp6 0 0 :::2377 :::* LISTEN 1283/dockerd
tcp6 0 0 :::7946 :::* LISTEN 1283/dockerd
因此,您可以看到端口 80 和 443 暴露在 上,tcp
但没有tcp6
。搜索此问题,我只能找到相反的问题(docker 正在监听 IPv6 而不是 IPv4)。
当尝试绑定端口时,socat
会报告端口正在使用(而 则netstat
表示未使用)。将端口 81 绑定到端口 80 上的 IPv4 地址允许我通过 IPv6 访问服务器,因此其他地方不会出现路由问题。
sudo socat TCP6-LISTEN:80,fork TCP4:127.0.0.1:80
2021/01/13 16:08:50 socat[26572] E bind(5, {AF=10 [0000:0000:0000:0000:0000:0000:0000:0000]:80}, 28): Address already in use
docker inspect
显示以下信息:
"NetworkSettings": {
"Bridge": "",
"SandboxID": "d5fdebb4de954a4d7c1800490e44d0f53c4ee827775edb8ba286583e888eaa07",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"443/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "443"
}
],
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "80"
}
]
},
"SandboxKey": "/var/run/docker/netns/d5fdebb4de95",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"docker_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"d8acfbf724cf"
],
"NetworkID": "87b6b52c779252614553040f217f9f2310ee3cce5f1a450f6a8210e8ea411b5a",
"EndpointID": "a6bdf4d85641a043c25812ac0759a7ad872a3ee15ff7ea0e3ddf6b2405967737",
"Gateway": "172.20.0.1",
"IPAddress": "172.20.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:14:00:02",
"DriverOpts": null
}
}
}
答案1
这似乎是 Docker 20.10.2 中的半故意的1更改,请参阅此处的相关讨论:https://github.com/moby/libnetwork/issues/2607.看起来像使固定是进行。
与此同时,降级到 20.10.1 对我来说是可行的:
sudo apt install docker-ce=5:20.10.1~3-0~ubuntu-focal \
docker-ce-cli=5:20.10.1~3-0~ubuntu-focal
sudo apt-mark hold docker-ce docker-ce-cli
1半故意的,因为显然,这个功能从未打算以这种方式使用。我和你一样惊讶……
答案2
通过移动 Docker 端口并创建socat
代理解决了此问题systemd
,具体方法如下此 GitHub 讨论.步骤如下:
移动容器的端口,8080:80
例如8443:443
安装索卡特
apt-get install socat
创建两个systemd
用于socat
监听 IPv4 和 IPv6 的服务,并将流量转发到服务的 IPv4 端点:
nano /etc/systemd/system/socat-tcp-80.service
[Unit]
Description=Socat TCP:80
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/bin/socat TCP6-LISTEN:80,,su=nobody,fork,reuseaddr TCP4:127.0.0.1:8080
Restart=on-failure
[Install]
WantedBy=multi-user.target
保存该文件并为端口创建另一个文件443
。
启动服务并在启动时启用它们:
systemctl start socat-tcp-80
systemctl start socat-tcp-443
systemctl enable socat-tcp-80
systemctl enable socat-tcp-443
您可以使用它journalctl -feu socat-tcp-80
来获取您的服务的日志。
我不知道为什么 docker 的行为最近发生了变化,但是这种解决方法仍然允许我们支持 IPv6。