Reputation: 1859
I'm using:
docker-compose 3.7
docker engine 18.09.7
In a docker-compose file, how do I specify which network I want a specific listening port bound to?
For example:
version: "3.7"
services:
service-a:
image: service-a:0.1.0
networks:
- network1
service-b:
image: service-b:0.1.0
networks:
- network1
- network2
expose:
- "8000"
- "9000"
ports:
- target: 8000
published: 8000
protocol: tcp
mode: host
- target: 9000
published: 9000
protocol: tcp
mode: host
service-c:
image: service-c:0.1.0
networks:
- network2
networks:
network1:
network2:
In this contrived example service-b
is listening on port 8000
and 9000
.
Is there a way to specify that port 8000
is only accessible on network1
while 9000
is only accessible on network2
?
This would be most helpful in the case where a server listens on, say 0.0.0.0
as the host.
Upvotes: 1
Views: 2631
Reputation: 8988
So if I get this right what you want to achive is to grant service-a
access to port 8000
of service-b
but block any access from service-a
to port 9000
of service-b
. And the same for service-c
but the other way around?
For this you first need to know how the networking with docker-compose
works: for each network under the networks
section docker-compose
(in this case) creates a virtual network connecting a virtual network device of the host machine to it as well as a virtual network device of each container contected to the network. Each of these virtual devices can communicate directly with each other in the same virtual network while the different virtual networks are usally isolated from each other.
The expose
keyword now does not actually expose any ports but instead only documents the intent that a process will listen on that port(s). You can examine this information about a container using docker inspect
. Besides the added meta-data expose
does not actually do much more, see the documentation. So in this case it has no real use.
The ports
keyword on the other hand does expose the listed ports to ports on the host machine - see the docs. Since the containers communicate directly via their share networks this is again not of real use for your scenario.
There are also no other configuration options which are intended to limit the communication of containers within the same network, i.e. there is no officially supported way to do this nicely.
One way to do this would be to modify the application itself to not listen on 0.0.0.0
with each port but only bind to the address of the respective network (network1
/network2
). But this requires application-specific changes and to somehow detect the correct address for each port.
Another way would be to inject your own iptables
rules to block undesired access between containers, see the docs on this. The downside of this is that it has to be done completely outside of docker
and docker-compose
.
And lastly there is this hackish solution: instead of blocking undesired access only allow for explicitly whitelisted ports:
version: "3.7"
services:
service-a:
image: service-a:0.1.0
networks:
- network1
service-b:
image: service-b:0.1.0
networks:
- network2
ports:
- 172.101.0.1:8000:8000
- 172.103.0.1:9000:9000
service-c:
image: service-c:0.1.0
networks:
- network3
networks:
network1:
ipam:
config:
- subnet: 172.101.0.0/24
network2:
network3:
ipam:
config:
- subnet: 172.103.0.0/24
This works by assigning each container to its very own network completely isolating them from each other. But for network1
/network3
we explicitly configure the subnet so we know the gatway IPs (172.101.0.1
/172.103.0.1
) of them which are assigned to the virtual network devices of the host.
Now we can "expose" the ports 8000
/9000
of the service-b
container to these host IP addresses, i.e. port 8000
on 172.101.0.1
will be forwarded to port 8000
of the service-b
container. 172.101.0.1
belongs to the host but is part of network1
and thus can be accessed by service-a
allowing it to only access that one port of service-b
.
Upvotes: 3