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:
replicas: 3Esto 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_dbSe 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:
replicas: 3
endpoint_mode: dnsrr ## Round Robin Load BalancingSi 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.yamlse 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.yamldebe 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:
replicas: 3
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.
