I hope you can help me, thanks in advance!
I have a docker-compose file with three services traefik, app and service-x
. app
can have many instances and I implemented a load balancer / reverse proxy using traefik to it, and it is working fine.
app
calls internally to service-x
and service-x
can also have many instances, but when app
calls http://service-x
it always do it to the same instance (the first one), so I wonder if there is a way to implement a load balance mechanism, so when I call service-x
it is distributed among all the instances?
this is the simplified docker-compose file:
services:
traefik:
image: "traefik"
restart: always
command:
- "--api=true"
...
ports:
- "80:80"
- "443:443"
app:
image: app:latest
labels:
- "traefik.enable=true"
...
ports:
- "3000"
restart: on-failure
links:
- service-x
service-x:
image: service-x:latest
ports:
- "8001"
CodePudding user response:
I wonder if there is a way to implement a load balance mechanism, so when I call service-x it is distributed among all the instances?
That is the way docker-compose behaves by default. If you're not seeing that behavior, I suspect it's your use of the deprecated links
parameter. You haven't need that for years now; when you attach containers to the same user-defined network (which docker-compose does by default), they can refer to each other by name using the DNS service maintained automatically by Docker.
Also -- and this isn't directly related to your question -- you don't need ports
entries for the services that are only used internally.
For a practical example, take a look at this docker-compose.yaml
:
version: "3"
services:
proxy:
image: traefik:latest
command:
- --api.insecure=true
- --providers.docker
- --accesslog=true
- --accesslog.filepath=/dev/stderr
ports:
- "127.0.0.2:80:80"
- "127.0.0.2:443:443"
- "127.0.0.2:8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
app:
image: docker.io/nginx:mainline
volumes:
- "./default.conf:/etc/nginx/conf.d/default.conf"
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`example.com`)"
service-x:
image: docker.io/containous/whoami:latest
In the above, service-x
is running this image, which runs a webserver that reports its hostname and some other metadata.
The role of your app
service is played by nginx, using this configuration:
server {
listen 80;
server_name localhost;
location / {
proxy_pass "http://service-x";
proxy_set_header Host $http_host;
}
}
With the above configuration, a request to http://127.0.02
with a Host
header of example.com
will go to the app
service, which will then proxy the request to the service-x
service.
If we bring up multiple instance of service-x
, like this:
docker-compose up --scale service-x=3
So that we have:
$ docker ps -f label=com.docker.compose.project=proxy-example
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2cbcb3e4e36 containous/whoami:latest "/whoami" 6 minutes ago Up 5 minutes 80/tcp proxy2_service-x_2
48655b9f0dd3 containous/whoami:latest "/whoami" 6 minutes ago Up 5 minutes 80/tcp proxy2_service-x_3
f6cdd1cfe908 nginx:mainline "/docker-entrypoint.…" 10 minutes ago Up 5 minutes 80/tcp proxy2_app_1
d65f996e7113 containous/whoami:latest "/whoami" 22 minutes ago Up 5 minutes 80/tcp proxy2_service-x_1
af1310113b6a traefik:latest "/entrypoint.sh --ap…" 22 minutes ago Up 5 minutes 127.0.0.2:80->80/tcp, 127.0.0.2:443->443/tcp, 127.0.0.2:8080->8080/tcp proxy2_proxy_1
And then make multiple requests through Traefik:
for x in {1..10}; do
curl -sf --resolve example.com:80:127.0.0.2 http://example.com/ | grep Hostname
done
We see that the requests are rotating among the service-x
containers:
Hostname: e2cbcb3e4e36
Hostname: 48655b9f0dd3
Hostname: d65f996e7113
Hostname: e2cbcb3e4e36
Hostname: 48655b9f0dd3
Hostname: d65f996e7113
Hostname: e2cbcb3e4e36
Hostname: 48655b9f0dd3
Hostname: d65f996e7113
Hostname: e2cbcb3e4e36
Notes:
- Why
127.0.0.2
? Because I already have a service listening on127.0.0.1
on port 80.