How do I publish ports on specific interface / localhost in Docker Swarm?

I have a Docker Swarm of which the nodes are accessible to the public. While I want to publish the ports of my APIs I don’t want to do that with my databases. However, at the same time, I’d like to be able to connect to the database for debugging purposes. Using regular Docker I’d bind the database ports to localhost only, so with an SSH tunnel I’d be able to connect. Since my nodes have internal interfaces, maybe I could use that. I cannot find how to do this with Swarm however. Is there a way to do that? Or maybe a different way to achieve that?

This feature is not implements for Swarm deployments.

Why would you even run a docker host on machine directly connected to the internet?! Usualy people have a loadbalancer/reverse-proxy on a machine directly connected to the internet and forward the traffic to a docker cluster run in a private network.

Well, when using Traefik as a loadbalancer/reverse-proxy it needs to be directly in the swarm, doesn’t it?

Would you care answering my question from above?

I was trying to. When I use Traefik - which sits directly in the sawrm - as reverse proxy, the swarm needs to be accessible from the internet, doesn’t it? Or would you suggest adding a second reverse proxy in front of Traefik?

I am trying to get a full picture of your environment.
Though, you seem to prefer me to follow your solution… which I am not remotely able to judge without having the full picture (cough).

First of all, thanks for trying to help me. I’m not preferring you follow my solution (I don’t have one). I’ll try to give you a full picture of what I have so far:

  • a swarm
  • two services: an API and a database
  • Traefik as a reverse proxy directly in the swarm (as that’s what I think I’m supposed to do with it)

What I want is to make the API accessible from the internet, the database only accessible internally.

I hope, that answers the questions a gives you a full picture.

The required details to understand your situttion are:
– are there nodes with internet and private ip?
– are there nodes with private ip only?
– is there some sort of loadbalancer/reverse proxy available in the environment?
– are the nodes running at a cloud provider, any other service provider and do they provide a load balancing service?
– or are the nodes run in a typical homelab scenario where internet traffic comes in from a WAN port and traffic needs to be forwarded to your nodes?

are there nodes with internet and private ip?

The nodes have both internet and private ip

are there nodes with private ip only?

This is definitely an option.

is there some sort of loadbalancer/reverse proxy available in the environment?

Apart from Traefik, there is nothing in place. However, I have control over the environment, so I could install sth like that.

are the nodes running at a cloud provider, any other service provider and do they provide a load balancing service?

No, they are on premise.

or are the nodes run in a typical homelab scenario where internet traffic comes in from a WAN port and traffic needs to be forwarded to your nodes?

Nope, all nodes have public ips.

Now the picture is clear :slight_smile:

There are severall options:

– run a dedicated node as loadbalancer with internet/private ip, run the swarm nodes on machines with private ips only. This loadbalancer could be a simple layer4 loadbalancer forwarding traffic from a specific port to a specific port on your cluster, for instance to the traefik container.

– if you choose the loadbalancer to be part of the swarm, make sure to label the hosts and use deployment constraints to pin the services to specific machines. Make sure to use the long syntax for the published database port and use mode:host to bypass the ingress mesh routing.

Thank you so much for your suggestions. I’ll investigate on those… :+1:

My two cents. You can remove the port mapping in the docker-compose.yml to no longer see it from outside world. You can still access the default port for each service inside the docker stack. You would use the service name (and possibly a number if multiple instances) with the default port number from other containers in the docker stack.

@dskow: Did you put the requirement into consideration?