How to check if application has started inside container

But with version 1.7.1 ports are instantly available, before application has even started inside container.

I don't think that's true -- that is, I think it depends on how you are trying to contact a port. Consider, for example, a container like this:

$ docker run -it -p 8888:80 alpine sh

Here we've set up port forward from host port 8888 to container port 80, but we haven't set up anything to listen inside the container. Trying to connect to port 8888 on localhost results in a successful connection that immediately closes:

$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

Which is exactly what you are experiencing. But if instead of localhost we use an ip address of the host, we see different behavior:

$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
telnet: connect to address 192.168.1.55: Connection refused

If inside the container I start a web server:

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

Then I can successfully connect:

$ telnet 192.168.1.55 8888
Trying 192.168.1.55...
Connected to 192.168.1.55.
Escape character is '^]'.

This happens because connections via localhost are handled by the Docker userland proxy, which is bound to port 8888:

# netstat -tlnp | grep 8888
tcp6       0      0 :::8888                 :::*                    LISTEN      2809/docker-proxy   

But connections to another interface ip -- and any connection originating from another host -- will be handled by the rules in the iptables nat table:

# 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

Or is there other reliable method to check if application has started inside container?

You have a few choices:

  • Just connect to the container ip directly, rather than relying on port forwarding. E.g., in the above example the container I started was assigned address 172.17.0.138. I can just connect to that instead of a host address. It's easy to find the ip address of a docker container:

    $ docker inspect --format '{{ .NetworkSettings.IPAddress }}' my-container 172.17.0.138

  • Wait until you achieve a successful connection to your application. In this example, in which I ultimately started a web server, I could wait until curl successfully connects:

    while ! curl -sf http://localhost:8888/; do
      sleep 1
    done
    

    The -f flag tells curl to exit with an error code if it cannot successfully fetch a URL.

Tags:

Docker