Escalabilidad con Docker Compose

Advertisements

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: 3

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:
      		replicas: 3
            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.

Advertisements
$ 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.

  1. No hay una distribución de cargas entre las instancias.
  2. 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 archivo docker-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 servicio reverse-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:
      		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:

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.

Referencias

Advertisements

Leave a Reply

Your email address will not be published. Required fields are marked *