The only "official" way to publish a port in Docker is the
-p|--publish flag of the
docker run (or
docker create) command. And it's probably for good that Docker doesn't allow you to expose ports on the fly easily. Published ports are part of the container's configuration, and the modern infrastructure is supposed to be fully declarative and reproducible. Thus, if Docker encouraged (any) modification of the container's configuration at runtime, it'd definitely worsen the general reproducibility of container setups.
But what if I really need to publish that port?
For instance, I periodically get into the following trouble: there is a containerized Java
monster web service that takes (tens of) minutes to start up, and I'm supposed to develop/debug it. I launch a container and go grab some coffee. But when I'm back from the coffee break, I realize that I forgot to expose port 80 (or 443, or whatever) to my host system. And the browser is on the host...
- Restart the container exposing the port, potentially committing its modified filesystem in between. This is probably "the right way," but it sounds too slow
and boringfor me.
- Modify the container's config file manually and restart the whole Docker daemon for the changes to be picked up. This solution likely causes the container's restart too, so it's also too slow for me. But also, I doubt it's future-proof even though it's kept being suggested 9 years later.
- Access the port using the container's IP address like
curl 172.17.0.3:80. This is a reasonable suggestion, but it works only when that container IP is routable from the place where you have your debugging tools. Docker Desktop (or Docker Engine running inside of a vagrant VM) makes it virtually useless.
- Add a DNAT iptables rule to map the container's socket to the host's. That's what Docker Engine itself would do had you asked it to publish the port in the first place. But are you an iptables expert? Because I'm not. And also, it has the same issue as the above piece of advice - the container's IP address has to be routable from the host system.
- Start another "proxy" container in the same network and publish its port instead - finally, a solution that sounds good to me ❤️🔥 Let's explore it.