I'm looking for a way to map the same port into 2 different ports, each for another container in a different network.
consider the below docker-compose scenario:
services:
web:
build: .
ports:
- "8080:8080"
networks:
Net1:
Net2:
serv1:
image: tomcat:7.0.92-jre8
networks:
Net1:
serv2:
image: tomcat:7.0.92-jre8
networks:
Net2:
Now what I would really like to do is to actually map the "web" service port 8080 so that serv1 could consume it as 8081 and serv2 will be using it as 8082.
Is that even possible?
Thanks
Ports are published to the host, not to docker networks, and not to other docker containers. So the above "8080:8080" maps port 8080 on the docker host into that container's port 8080.
For container-to-container communication, that happens using docker's internal DNS for service discovery, and the container port. So both serv1 and serv2 can connect to http://web:8080 to reach the web service on its container port. That in no way prevents serv1 and serv2 from listening within their own container on any ports they wish.
Related
Assuming that I have 2 nodes in the swarm (Node 1 is a manager, node2 is a worker), and using the following compose to launch
version: "3.9"
services:
app1:
image: app1image
ports:
- 8080:8080
deploy:
mode: global
app2:
image: app2image
ports:
- 9080:9080
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- "node.role==manager"
My questions are:
If I try to access app1 through node1 could I be routed to the app1 container in node2?
Since the app2 only deploys to node1, if I try to access it through node2 on port 9080 will I be able to?
Besides ports referenced by the docker documentation(TCP port 2377 for cluster management communications
TCP and UDP port 7946 for communication among nodes
UDP port 4789 for overlay network traffic) are there any other ports that need to be opened? Like in case app1 wants to call app2
So, to understand whats actually going on:
version: "3.9"
networks:
default:
driver: overlay
ingress:
external: true
services:
app1:
image: app1image
ports:
- 8080:5000
deploy:
mode: global
networks:
- default
app2:
image: app2image
ports:
- 9080:5000
networks:
- default
deploy:
placement:
constraints:
- node.role==manager
In this configuration my expectation is that the app is listening on 0.0.0.0:5000.
So, what docker has done is created two networks: an ingress network that is used to bridge ports on each host, to each container:
node1:8080 node2:8080 will be routed and loadbalanced to app1 containers.
and
node1:9080, nod2:9080 will be routed and loadbalanced to app2 containers.
The service containers, or tasks, also have been attached to an implicit default network for the compose stack. Its an overlay - or software defined - network so each container has an ip on that network that is unrelated to the node its on. I have decided that the actual listen port is port :5000 for both services, so any services attached to {stack}_default will be able to use the servicename, and the actual port address:
app1:5000 will route via a vip to loadbalance traffic to instances of app1, and app1.tasks is a dnsrr record that will return each container ip.
Likewise app2:5000 will route to the app2 container on the manager node.
The app1 and app2 dns names are entirely private to services that are part of the stack / attached to the {stack_default} network so the app1:5000 names are not available external to the swarm, or even to other stacks or containers that are not explicitly attached.
So:
yes.
yes.
no but:
If you ports: to publish ports, those ports are external to docker and do not go through the overlay network. You would need to add every port published to the firewalls if required for node to node comms. e.g. 8080 and 9080 need to be open.
However, because overlay network allows connections, uses 4789 at the physical link layer, the traffic goint to app1, and app2 ips (the :5000 traffic) on the overlay is tunneled and does not need to be opened.
I'im fairly new to docker and docker compose.
I have a simple scenario, based on three applications (app1, app2, app3) that I want to connect to my host's network. The purpose is having an internet connection also inside the container.
Here is my docker-compose file:
version: '3.9'
services:
app1container:
image: app1img
build: ./app1
networks:
network_comp:
ipv4_address: 192.168.1.1
extra_hosts:
anotherpc: 192.168.1.44
ports:
- 80:80
- 8080:8080
app2container:
depends_on:
- "app1container"
image: app2img
build: ./app2
networks:
network_comp:
ipv4_address: 192.168.1.2
ports:
- 3100:3100
app3container:
depends_on:
- "app1container"
image: app3img
build: ./app3
networks:
network_comp:
ipv4_address: 192.168.1.3
ports:
- 9080:9080
networks:
network_comp:
driver: ""
ipam:
driver: ""
config:
- subnet: 192.168.0.0/24
gateway: 192.168.1.254
I already read the docker-compose documentation, which says that there is no a bridge driver for Windows OS. Is there anyway a solution to this issue?
You shouldn't usually need to do any special setup for this to work. When your Compose service has ports:, that makes a port available on the host's IP address. The essential rules for this are:
The service inside the container must listen on the special 0.0.0.0 "all interfaces" address (not 127.0.0.1 "this container only"), on some (usually fixed) port.
The container must be started with Compose ports: (or docker run -p). You choose the first port number, the second port number must match the port inside the container.
The service can be reached via the host's IP address on the first port number (or, if you're using the older Docker Toolbox setup, on the docker-machine ip address).
http://host.example.com:12345 (from other hosts)
|
v
ports: ['12345:8080'] (in the `docker-compose.yml`)
|
v
./my_server -bind 0.0.0.0:8080 (the main container command)
You can remove all of the manual networks: configuration in this file. In particular, it's problematic if you try to specify the Docker network to have the same IP address range as the host network, since these are two separate networks. Compose automatically provides a network named default that should work for most practical applications.
We have multiple microservices that are run on port 8080. As far as I know that only 1 service can run on port 8080.
Would it mean running the microservice as a port: 8080:8081 or 8081:8081?
Below are the services that we are trying to implement in docker-compose
reference-service:
image: **
ports:
- "8080:8080"
test-service:
image: **
ports:
- "8080:8081"
There are two kind of ports: container port and host port. Two processes cannot hold the same container port inside one container. You also cannot expose services' container ports to the same host port.
However each service runs inside its own container so that both can use container port 8080.
So that the following configuration is acceptable: you have two services, each is running in its own container and have container port 8080. Each of container ports are exposed to different host ports like this:
reference-service:
image: **
ports:
- "8080:8080"
test-service:
image: **
ports:
- "8081:8080"
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.
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.
I would like to set up the following scenario:
One physical machine with Docker containers
traefik in a container with network backend
another container which is using the host machines network (network_mode: host)
Traefik successfully finds the container and adds it with the IP address 127.0.0.1 which obviously not accessible from the traefik container (different network/bridge).
docker-compose.yml:
version: '3'
services:
traefik:
image: traefik
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/etc/traefik/traefik.toml
networks:
- backend
app:
image: my_app
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:myapp.example"
- "traefik.port=8080"
network_mode: host
networks:
backend:
driver: bridge
The app container is added with
Server URL Weight
server-app http://127.0.0.1:8080 0
Load Balancer: wrr
Of course I can access app with http://127.0.0.1:8080 on the host machine or with http://$HOST_IP:8080 from the traefik container.
Can I somehow convince traefik to use another IP for the container?
Thanks!
Without a common docker network, traefik won't be able to route to your container. Since you're using host networking, there's little need for traefik to proxy the container, just access it directly. Or if you need to only access it through the proxy, then place it on the backend network. If you need some ports published on the host and others proxied through traefik, then place it on the backend network and publish the ports you need to publish, rather than using the host network directly.