I have docker-compose file for my docker swarm stack.I want my stack services to be deployed on specific network and that network i want to be ingress network so that i can use DNSRR of docker.
version: "3"
services:
a:
image: xyz/a:dev
ports:
- "80:80"
- "443:443"
networks:
-my_network
b:
image: xyz/b:dev
ports:
- "5000:5000"
networks:
-my_network
networks:
my_network:
driver:overlay
ipam:
driver: default
config:
-subnet: 10.0.1.0/24
here, where can i specify that this network should be ingress network? plus how can i specify ip-range same as specified here in cli : here
Apparently, these options are not exposed in the composefile. The documentation doesn't mention them and to be sure you can check the source code, in particular the latest compose schema.
The only option is to create the ingress network on the command line and reference it from the compose file as an external network.
The ingress network is only for manager/worker nodes.
The routing mesh routes all incoming requests to published ports on available nodes to an active container.
https://docs.docker.com/engine/swarm/ingress/
What you want is an addition overlay network. All services which are assigned to the same overlay network which is not ingress, can talk to each other over the name you've given them.
E.g.
docker service create --name A --network dev ...
docker service create --name B --network dev ...
Service A can simply do ping B.
Example of how to specify port ranges:
ports:
- "9090-9091:8080-8081"
The long form allows specifying the mode as either host or ingress.
ports:
- target: 80
host_ip: 127.0.0.1
published: 8080
protocol: tcp
mode: ingress
See the Ports section of the docker-compose spec for more details.
Related
I do not know how to achieve that. Now all the ports are exposed to the host machine but I just want to expose one container port (80), not the other (8080). Here is the docker-compose file:
---
version: "3.9"
services:
app:
image: sandbox/app
container_name: app
volumes:
- ./src/app:/app/
expose:
- "8080"
restart: unless-stopped
networks:
custom-net:
ipv4_address: 10.0.0.7
web_server:
image: nginx:latest
container_name: proxy
ports:
- "80:80"
networks:
custom-net:
ipv4_address: 10.0.0.6
networks:
custom-net:
name: custom-net
driver: bridge
ipam:
driver: default
config:
- subnet: 10.0.0.0/8
If I run from the local machine nmap 10.0.0.6, it shows port as open in port 80. This container exposure is the desired one. But when I run nmap 10.0.0.7, it also shows as open 8080 port, how it could be that one? Checking some stackoverflow thread, ports is defined like that:
Expose ports. Either specify both ports (HOST:CONTAINER), or just the container port (a random host port will be chosen).
and expose:
Expose ports without publishing them to the host machine - they’ll only be accessible to linked services. Only the internal port can be specified.
Do I miss some network concepts or do I have wrong docker-compose file?
You must be on a native-Linux host. If you happen to know the Docker-internal IP addresses, and you're on a native-Linux host, then you can always connect to a container using those addresses; you can't prevent this (without iptables magic) but it's also not usually harmful. This trick doesn't work in other environments (on MacOS or Windows hosts, or if Docker is in a Linux VM, or from a different host from the container) and it's much more portable to connect only to containers' published ports:.
You should be able to use a much simpler Compose file. Delete all of the networks: blocks and the expose: blocks. You also do not need container_name:, and you should not need to inject code using volumes:. Trimming out all of the unnecessary options leaves you with
version: '3.8' # last version supported by standalone docker-compose tool
services:
app:
image: sandbox/app # may want `build: .` _instead of_ this line
restart: unless-stopped
web_server:
image: nginx:latest # needs some custom configuration?
ports:
- "80:80"
That should literally be the entire file.
From outside Docker but on the same machine, http://localhost:80 matches the first ports: of the web_server container, so forwards to the second ports:, on which the Nginx server is listening. The Nginx configuration should include a line like proxy_pass http://app:8080 which will forward to the application container.
Compared to your original file:
expose: is an artifact of first-generation Docker networking. In a Compose file it does absolutely nothing at all and it's always safe to delete it.
Connections between containers (where web_server uses app as a host name) connect directly to the specified port; they do not use or require expose: or ports: settings, and they ignore ports: if they're present.
Compose assigns container names on its own, and there are docker-compose CLI equivalents to almost all Docker commands that can figure out the right mapping. You don't need to manually specify container_name:.
Docker automatically assigns IP addresses to containers. These are usually an internal implementation detail; it's useful to know that containers do have their own IP addresses (and so you can have multiple containers that internally listen on the same port) but you never need to know these addresses, look them up, or manually specify them.
Compose automatically creates a network named default for you and attaches containers to it, so in most common cases you don't need networks: at all.
Networking in Compose in the Docker documentation describes how to make connections between containers (again, you do not need to know the container-private IP addresses). Container networking discusses these concepts separately from Compose.
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.
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 have a docker-compose file which is globally like this.
version '2'
services:
app:
image: myimage
ports:
- "80:80"
networks:
mynet:
ipv4_adress: 192.168.22.22
db:
image: postgres:9.5
ports:
- "6432:5432"
networks:
mynet:
ipv4_adress: 192.168.22.23
...
networks:
mynet:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.22.0/24
I want to put my postgresql and application in subnetworks to avoid the ports to be exposed outside my computer/server.
From within the app container, I can't connect to 192.168.22.23, I installed net-tools to use ifconfig/netstat, and it doesn't seem the containers are able to communicate.
I assume I have this problem because I'm using subnetworks with static ipv4 adresses.
I can access both static IPs from the host (connect to postgres and access the application)
Do you have any piece of advice, the goal is to access the ports of another container to communicate with him, without removing the use of static ips (on app at least). Here, to connect to postgresql from the app container.
The docker run -p option and Docker Compose ports: option take a bind address as an optional parameter. You can use this to make a service accessible from the same host, but not from other hosts:
services:
db:
ports:
- '127.0.0.1:6432:5432'
(The other good use of this setting is if you have a gateway machine with both a public and private network interface, and you want a service to only be accessible from the private network.)
Once you have this, you can dispense with all of the manual networks: setup. Non-Docker services on the same host can reach the service via the special host name localhost and the published port number. Docker services can use inter-container networking; within the same docker-compose.yml file you can use the service name as a host name, and the internal port number.
host$ PGHOST=localhost PGPORT=6432 psql
services:
app:
environment:
- PGHOST=db
- PGPORT=5432
You should remove all of the manual networks: setup, and in general try not to think about the Docker-internal IP addresses at all. If your Docker is Docker for Mac or Docker Toolbox, you cannot reach the internal IP addresses at all. In a multi-host environment they will be similarly unreachable from hosts other than where the container itself is running.
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.