如何检查应用程序是否已在容器内启动

ais*_*baa 5 docker

我们有一个集成测试套件,可以在开始任何测试用例之前启动容器.我们曾经在执行任何测试之前等待端口可用,这表明应用程序已准备好接收请求.但是,在应用程序甚至在容器内部启动之前,1.7.1版本的端口立即可用.

是否可以选择推迟停靠端口转发,直到端口在容器内打开?

或者是否有其他可靠的方法来检查应用程序是否已在容器内启动?

lar*_*sks 8

但是,在应用程序甚至在容器内部启动之前,1.7.1版本的端口立即可用.

我不认为这是真的 - 也就是说,我认为这取决于你是如何尝试联系港口的.例如,考虑一个这样的容器:

$ docker run -it -p 8888:80 alpine sh
Run Code Online (Sandbox Code Playgroud)

这里我们设置了从主机端口8888到容器端口80的端口转发,但是我们还没有设置任何内容来监听容器内部.尝试连接到端口8888会localhost导致成功连接立即关闭:

$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.
Run Code Online (Sandbox Code Playgroud)

这正是您所经历的.但是如果不是localhost我们使用主机的IP地址,我们会看到不同的行为:

$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
telnet: connect to address 192.168.1.55: Connection refused
Run Code Online (Sandbox Code Playgroud)

如果在容器内我启动了一个Web服务器:

/ # apk add mini_httpd
[...]  
/ # mini_httpd 
mini_httpd: started as root without requesting chroot(), warning only
Run Code Online (Sandbox Code Playgroud)

然后我可以成功连接:

$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
Connected to 192.168.1.55.
Escape character is '^]'.
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为连接通过localhost由Docker userland代理处理,该代理绑定到端口8888:

# netstat -tlnp | grep 8888
tcp6       0      0 :::8888                 :::*                    LISTEN      2809/docker-proxy   
Run Code Online (Sandbox Code Playgroud)

但是连接到另一个接口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
Run Code Online (Sandbox Code Playgroud)

或者是否有其他可靠的方法来检查应用程序是否已在容器内启动?

你有几个选择:

  • 只需直接连接到容器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
    
    Run Code Online (Sandbox Code Playgroud)

    -f如果无法成功获取URL,该标志告诉curl退出并显示错误代码.