我们有一个集成测试套件,可以在开始任何测试用例之前启动容器。我们曾经在执行任何测试之前等待端口可用,这表明应用程序已准备好接收请求。但是,在应用程序甚至在容器内部启动之前,1.7.1版本的端口立即可用。
是否可以选择推迟停靠端口转发,直到容器内的端口打开?
或者是否有其他可靠的方法来检查应用程序是否已在容器内启动?
答案 0 :(得分:7)
但是,在应用程序甚至在容器内启动之前,1.7.1版本的端口立即可用。
我不认为这是真的 - 也就是说,我认为这取决于你如何尝试联系港口。例如,考虑一个像这样的容器:
$ docker run -it -p 8888:80 alpine sh
这里我们设置了从主机端口8888到容器端口80的端口转发,但是我们还没有设置任何内容来监听容器内部。尝试连接到localhost
上的端口8888会导致连接成功立即关闭:
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.
这正是您所遇到的。但是,如果我们使用主机的IP地址代替localhost
,我们会看到不同的行为:
$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
telnet: connect to address 192.168.1.55: Connection refused
如果在容器内我启动了一个Web服务器:
/ # apk add mini_httpd
[...]
/ # mini_httpd
mini_httpd: started as root without requesting chroot(), warning only
然后我可以成功连接:
$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
Connected to 192.168.1.55.
Escape character is '^]'.
这是因为通过localhost
的连接由Docker userland代理处理,该代理绑定到端口8888:
# netstat -tlnp | grep 8888
tcp6 0 0 :::8888 :::* LISTEN 2809/docker-proxy
但是到另一个接口ip的连接 - 以及来自另一个主机的任何连接 - 将由iptables nat
表中的规则处理:
# iptables -t nat -S DOCKER
-N DOCKER
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8888 -j DNAT --to-destination 172.17.0.138:80
或者是否有其他可靠的方法来检查应用程序是否已在容器内启动?
您有几个选择:
只需直接连接到容器ip,而不是依赖端口转发。例如,在上面的例子中,我开始的容器被分配了地址172.17.0.138。我可以连接到那个而不是主机地址。很容易找到docker容器的ip地址:
$ docker inspect --format'{{.NetworkSettings.IPAddress}}'my-container 172.17.0.138
等到您的应用程序实现成功连接。在这个我最终启动Web服务器的示例中,我可以等到curl
成功连接:
while ! curl -sf http://localhost:8888/; do
sleep 1
done
-f
标志告诉curl如果无法成功获取URL,则会退出并显示错误代码。
答案 1 :(得分:1)
我遇到了使用此Python脚本解决的相同问题:
def is_port_connected_in_container(host, port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.1)
# try to connect; if it fails, port is closed
try:
s.connect((host, port))
except socket.timeout:
return False
# try to receive some data
try:
received = s.recv(1)
except socket.timeout:
# no data, but this only times out if port was open
return True
# no timeout, so port open depends on whether we received something
return len(received) > 0