Challenge Medium

Docker 101: Publish All Exposed Ports on Random Host Ports to Avoid Port Conflicts

Can you get several builds of an app running side by side without port conflicts, so you can test them simultaneously?

When a container port is published with -p, as in the previous challenge, you pick the host port yourself. A host port can be taken by only one listening socket (of the same protocol) at a time, so each new container needs a host port that no other container or process uses yet.

You can pick free ports by hand for a few long-running containers. But it can quickly become a problem when containers are started by scripts and tools (e.g., CI jobs running tests in parallel, preview environments for every pull request, several copies of an app on a development server, etc.).

Luckily, Docker can pick a free host port by itself. The -P (or --publish-all) flag of docker run publishes every port that the image declares with the EXPOSE instruction, and Docker assigns a random free host port to each of them. However, since the port is not known in advance, you need to look it up after the container starts.

In this challenge, you need to start three copies of the same web app and run smoke tests against them:

  • registry.iximiuz.com/app:3f9c2a1
  • registry.iximiuz.com/app:8b1e7d4
  • registry.iximiuz.com/app:c04f5e9

The app listens on port 8080 inside the container, and the image declares this port with EXPOSE.

Start one container from each of the three images, and let Docker publish all ports the images expose on random host ports:

Hint: Publishing all exposed ports

Look for the --publish-all (or -P) flag in the docker run --help output. Unlike --publish, it takes no value, because the ports come from the image. The docker image inspect command shows which ports an image exposes in its ExposedPorts field.

Hint: Port is already allocated

If you published the first server on a fixed host port, the second one cannot take the same port and fails to start. Docker still creates the failed container, so remove it before starting a new one under the same name.

The smoke test suite lives in the app's repository at ~/app/smoke-test.sh. It takes the address of a running server as its only argument, in the host:port form, and sends a few requests to it:

~/app
./smoke-test.sh localhost:32768

Find out which host port Docker assigned to each of the three servers, and run the suite against every one of them through that port:

Hint: Finding the assigned host ports

The PORTS column of the docker ps output shows the host address and port of every published container port, next to the image the container runs. The docker port command prints the same information but for a single container. Pick the one you like more.