我目前已经在几个 OpenStack 托管的虚拟机上运行了 Docker。
当尝试从这些机器上的容器内发出 HTTP 请求时,请求几乎总是会挂起等待响应。当发出 HTTPS 请求时,请求总是会超时,因为它无法完成 TLS 握手。无论哪种情况,请求似乎在仅收到几百字节的响应数据(如果有的话)后就失败了。相同的请求在主机上没有任何问题地完成(即问题不是主机级防火墙)。
我遇到过这(以及一些相关的博客文章)表明这可能是由于 Docker 网桥与主机网络接口的 MTU 不同,但我已经验证了两个 MTU 是相同的(每种情况下都是 1500 字节)。我还尝试过切换--mtu
到 Docker 守护程序,看看是否可以让它工作,但没有成功。
我还遇到过一些类似的情况,这些情况表明这可能是由于 TCP 校验和和/或分段卸载造成的(例如这里),但无论怎么玩弄ethtool -K {interface} tx off rx off
或类似的东西都不会产生任何积极的结果。
这种行为似乎特定于网桥 ---net=host
在运行容器时使用确实可以解决问题。但是,出于安全原因,我希望避免在我们的生产系统中使用此解决方法。
还要注意,完全相同的设置(相同的 Docker 版本、相同的配置参数)在我的开发机器上或在 AWS 托管的实例上运行时运行良好 - 无论问题是什么,它似乎只有在 OpenStack 下运行时才会显现出来。
作为参考,我使用以下命令进行测试:
docker run -it alpine:3.3 wget http://ipv4.download.thinkbroadband.com/5MB.zip
理论上,运行时该命令应该会下载一个 5MB 的测试文件。但是,wget
命令只是挂起。可能还值得注意的是,问题不在于客户操作系统 - 使用 Ubuntu 映像(例如)仍然会出现相同的行为。
我和一位同事还使用 netcat 进行了一些文件传输测试。在这些测试中,我们能够成功地将文件从容器传输到我们的测试服务器,但尝试反向传输失败。我们还曾tcpdump
在这些测试期间捕获网络活动 - 在失败的测试期间,日志显示收到了一些数据包,但数量明显少于预期。
docker version
此外,如果相关的话,这里是相关系统的输出:
Client:
Version: 1.12.1
API version: 1.24
Go version: go1.6.3
Git commit: 23cf638
Built: Thu Aug 18 05:22:43 2016
OS/Arch: linux/amd64
Server:
Version: 1.12.1
API version: 1.24
Go version: go1.6.3
Git commit: 23cf638
Built: Thu Aug 18 05:22:43 2016
OS/Arch: linux/amd64
主机上的输出uname -a
如下:
Linux docker-builder-1 4.4.0-38-generic #57~14.04.1-Ubuntu SMP Tue Sep 6 17:20:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
更新
事实证明,如果 Docker 托管在 Ubuntu 16.04 镜像下,一切都会按预期工作。
此时,我可以继续重建所有虚拟机以使用 Ubuntu 16.04 映像,但我仍然不知道原始问题是什么。我仍然有兴趣听取有关原始问题的原因以及如何修复它的任何建议。
答案1
总结
将 dockerd MTU 标志适配到您的 VM 的 MTU。
例子
我的一个OpenStack实例的操作系统是ubuntu16.04。
- 检查虚拟机的 MTU
ifconfig
(我的情况是 1450) cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
vi /etc/systemd/system/docker.service
ExecStart=/usr/bin/docker daemon -H fd:// --mtu 1450
systemctl daemon-reload
service docker restart