Docker Compose permite crear múltiples replicas de una mismo servicio, proporcionando escalabilidad a las aplicaciones. Al tener multiples replicas de un mismo servicio, estos pueden distribuir la carga de trabajo, por lo tanto soportando un mayor número de operaciones.
version'3.1'
services
myservice
deploy
replicas3
Esto se realiza por medio del campo services.<myservice>.deploy.replicas
. La cual permite indicar cuantas replicas del mismo servicio serán creadas.
Ahora bien, Docker-Compose es un orquestador básico, por lo cual esto requiere algunos pasos extra para hacerlo posible. A diferencia de orquestadores más completos como Docker-Swarm o Kubernetes, es necesario crear un servicio que sirva de “reverse proxy” y realice el balanceo de carga entre las distintas instancias de un mismo servicio.
Indicando replicas a un servicio
Vamos a comenzar con un archivo docker-compose.yaml
que declara 2 servicios, el primero para una base de datos MySQL y el segundo para una aplicación que consume dicha instancia base de datos.
version'3.1'
services
book-service
image book-service latest
restart always
environment
MYSQL_HOST'book_db'
MYSQL_PORT'3306'
MYSQL_USER'user'
MYSQL_PASSWORD'password'
APP_PORT'8080'
ports
# <Port exposed> : <MySQL Port running inside container>
'8080:8080'
expose
# Opens port 8080 on the container
'8080'
depends_on
book_db
Se puede entonces agregar los campos deploy.replicas
al servicio book-service
indicando la cantidad de instancias deseadas. Y además remover las lineas correspondientes a los puertos indicados en este servicio, de otra manera, al haber 2 o más instancias/replicas del mismo servicio habría un conflicto con el uso de puertos y el deployment fallaría.
version'3.1'
services
book-service
image book-service latest
restart always
environment
MYSQL_HOST'book_db'
MYSQL_PORT'3306'
MYSQL_USER'user'
MYSQL_PASSWORD'password'
APP_PORT'8080'
STOCK_SERVICE_URL'http://stock-service:8080'
depends_on
book_db
deploy
replicas3
endpoint_mode dnsrr ## Round Robin Load Balancing
Si iniciamos los servicios docker-compose up -d
se puede observar como se han creado 3 instancias del servicio book-service
.
$ docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
book-service-1 "java -jar book-serv…" book-service running 8080/tcp
book-service-2 "java -jar book-serv…" book-service running 8080/tcp
book-service-3 "java -jar book-serv…" book-service running 8080/tcp
book_db-1 "docker-entrypoint.s…" book_db running 0.0.0.0:3306->3306/tcp
Sin embargo, hay dos problemas que se deben corregir aún, para que se pueda hacer uso de la escabilidad proporcionada por esta nuevas instancias.
- No hay una distribución de cargas entre las instancias.
- Los puertos no están exponiendo ningún endpoint para acceder a sus endpoints.
Usando un Reverse Proxy
Se utilizará Nginx como reverse proxy, para que sea el punto de entrada de los servicios que están replicados. Nginx recibirá las solicitudes HTTP, y las redireccionará al servicio de docker-compose y este a una de sus múltiples instancias, resolviendo a la vez el problema del balanceo de cargas.
- Se crea un archivo
reverse_proxy.conf
, y lo se guarda junto al archivodocker-compose.yaml
. Este archivo es la configuracion de NGINX para un reverse proxy.
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://book-service:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Esta instrucciones dicen que cuando NGINX lea el puerto 80, en localhost, redireccione al URL http://book-service:8080/
. Es decir, que redireccione al DNS interno del servicio book-service
.
- En el archivo
docker-compose.yaml
se agrega un nuevo servicioreverse-proxy
:
reverse-proxy
image nginx latest
volumes
./reverse_proxy.conf:/etc/nginx/conf.d/default.conf
ports
"8080:80"
depends_on
book-service
Este servicio se llama reverse-proxy
, su imagen es nginx:latest
, utiliza el archivo de configuracion creado anteriormente reverse_proxy.conf
, y mapeo el puerto 80
de nginx con el 8080
que es expuesto externamente.
- Finalmente el archivo
docker-compose.yaml
debe lucir como este:
version'3.1'
services
book-service
image book-service latest
restart always
environment
MYSQL_HOST'book_db'
MYSQL_PORT'3306'
MYSQL_USER'user'
MYSQL_PASSWORD'password'
APP_PORT'8080'
STOCK_SERVICE_URL'http://stock-service:8080'
depends_on
book_db
deploy
replicas3
endpoint_mode dnsrr ## Round Robin Load Balancing
reverse-proxy
image nginx latest
volumes
./reverse_proxy.conf:/etc/nginx/conf.d/default.conf
ports
"8080:80"
depends_on
book-service
- Se inicia la orquestración con docker-compose con la instrucción:
$ docker-compose up
Una vez iniciados las aplicaciones, se puede ver como hay 3 instancias para el servicio book-service
, además de un reverse-proxy escuchando al puerto 8080.
$ docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
book-service-1 "java -jar book-serv…" book-service running 8080/tcp
book-service-2 "java -jar book-serv…" book-service running 8080/tcp
book-service-3 "java -jar book-serv…" book-service running 8080/tcp
book_db-1 "docker-entrypoint.s…" book_db running 0.0.0.0:3306->3306/tcp
reverse-proxy-1 "/docker-entrypoint.…" reverse-proxy running 0.0.0.0:8080->80/tcp
Finalmente se accede al URL del servicio:
- Book Service : http://localhost:8080/ (a traves de NGINX que distribuye a los servicios)
Conclusión
Docker-Compose permite escalar sus servicios para proporcionar multiples instancias, y por medio de una configuración sencilla agregar un reverse-proxy que nos ayude a proporcionar el balanceo de carga y complementar funcionalidades necesarias.