Orquestando contenedores Docker para tener un joomla y un mysql en diferentes hosts

En esta ocasión crearemos un pequeño stack para dockerizar joomla, usaremos 2 contenedores Docker, uno para el joomla y otro la base de datos mysql. Lo levantaremos en un cluster para que cada uno de ellos este en una máquina diferente.

Primero debemos nuestro cluster de máquinas, puede seguir nuestro artículo Redes con varios hosts con contenedores Docker y realizar los pasos 1 y 2.

Debería tener las siguientes máquinas ejecutándose:

docker-machine ls
NAME              ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
mh-keystore       -        virtualbox   Running   tcp://192.168.99.100:2376                        v1.11.2   
mhs-demo0         -        virtualbox   Running   tcp://192.168.99.101:2376   mhs-demo0 (master)   v1.11.2   
mhs-demo1         -        virtualbox   Running   tcp://192.168.99.102:2376   mhs-demo0            v1.11.2

Creamos un ficher docker-compose.yml para definir nuestro stack de contenedores Docker:

version: '2'

services:
    web:
        image: joomla
        ports:
            - 8080:80
        environment:
            - JOOMLA_DB_HOST=joomladb
            - JOOMLA_DB_PASSWORD=test
        depends_on:
            - joomladb
        networks:
            - back-tier
    joomladb:
        image: mysql:5.6
        environment:
            MYSQL_ROOT_PASSWORD: test
        volumes:
            - mysql-data:/var/lib/mysql
        networks:
            - back-tier

volumes:
    mysql-data:
        driver: local

networks:
    back-tier:
        driver: overlay

El primer servicio es web y contiene la imagen joomla, mapeará el puerto 8080, se ha configurado un par de variables, uno para indicar el host del mysql y otro para la contraseña del root.

El segundo servicio es una imagen de mysql. Hemos creado un volumen de nombre mysql-data de tipo local, así los datos se persistirán en el sistema de ficheros local.

Los servicios en la misma red son enlazables, en este caso ambos servicios estan en la red back-tier, la cual es de tipo overlay, este tipo de red permite realizar multi-host, esto permite que los servicios sean enlazables entre diferentes hosts.

Luego conectaremos el Docker Client al Docker Engine de la máquina master:

$ eval $(docker-machine env --swarm mhs-demo0)

Y levantar el stack de contededores docker:

$ docker-compose up -d
Creating network "joomla_back-tier" with driver "overlay"
Creating volume "joomla_mysql-data" with local driver
Pulling joomladb (mysql:5.6)...
mhs-demo1: Pulling mysql:5.6... : downloaded
mhs-demo0: Pulling mysql:5.6... : downloaded
Creating joomla_joomladb_1
Pulling web (joomla:latest)...
mhs-demo1: Pulling joomla:latest... : downloaded
mhs-demo0: Pulling joomla:latest... : downloaded
Creating joomla_web_1

Si listamos los contenedores que se estan ejecutando se apreciará que cada uno de los contenedores docker se ha instanciado en diferentes máquinas:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
e4b8435f0487        joomla              "/entrypoint.sh apach"   27 seconds ago      Up 26 seconds       192.168.99.101:8080->80/tcp   mhs-demo0/joomla_web_1
e9916f7f08a2        mysql:5.6           "docker-entrypoint.sh"   2 minutes ago       Up 2 minutes        3306/tcp                      mhs-demo1/joomla_joomladb_1

Como se puede observar al levantar el stack de contenedores Docker cada uno de los contenedores se ha instalado en diferentes máquinas, el joomla en la mhs-demo0 y base de datos en la mhs-demo1.

Si quiere usar el browser para ver la web de joomla, deberá ir a la ip de la máquina mhs-demo0 con el puerto 8080 que se definio en el docker-compose.yml:

http://192.168.99.101:8080/

Y verá el instalador de joomla.

Balanceador de carga
Hasta ahora tenemos una simple instancia de joomla ejecutándose. Necesitamos implementar un balanceador de carga que permita distribuir el tráfico a través de todas las instancias de este servicio. Usaremos la imagen hanzel/load-balancing-swarm.

Hay varias alternativas para balanceadores de carga, como consul o HAproxy, en esta ocasión usaremos nginx para balancear y consul-template para administrar la configuración de nginx.

Entonces vamos a construir el balanceador de carga a partir de una imagen nginx, para ello vamos a crear el archivo de configuración default.ctmpl, un bash script que usaremos de entry point para el contenedor Docker.

Archivo default.ctmpl para la configuración de nginx, tal como:

{{$app := env "APP_NAME"}}

upstream {{printf $app}} {
    least_conn;
    {{range service $app}}
    server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;{{end}}
}

server {
    listen 80 default;

    location / {
        proxy_pass http://{{printf $app}};
    }
}

Bash script que usará de entry point para la imagen:

#!/bin/bash
service nginx start
consul-template --consul=$CONSUL_URL -template="/template/default.ctmpl:/etc/nginx/conf.d/default.conf:service nginx reload"

Y el Dockerfile con la información para construir la imagen:

FROM nginx:latest

RUN apt-get update \
  && apt-get install -y unzip

ADD files/start.sh /bin/start.sh
RUN chmod +x /bin/start.sh
ADD files/default.ctmpl /templates/default.ctmpl

ADD https://releases.hashicorp.com/consul-template/0.12.2/consul-template_0.12.2_linux_amd64.zip /usr/bin/
RUN unzip /usr/bin/consul-template_0.12.2_linux_amd64.zip -d /usr/local/bin

EXPOSE 80
ENTRYPOINT ["/bin/start.sh"]

Para construir la imagen de nuestro balanceador de carga lb a partir de los archivos previamente creados Dockerfile, default.ctmpl, start.sh.

$ docker build -t load-balance-swarm .
Step 1 : FROM nginx:latest
 ---> 0d409d33b27e
Step 2 : RUN apt-get update   && apt-get install -y unzip
 ---> Using cache
 ---> 7e163fd73834
Step 3 : ADD lb/start.sh /bin/start.sh
 ---> Using cache
 ---> 0a56cd8a2965
Step 4 : RUN chmod +x /bin/start.sh
 ---> Using cache
 ---> 94bb63044a65
Step 5 : ADD lb/default.ctmpl /templates/default.ctmpl
 ---> Using cache
 ---> 06f863377456
Step 6 : ADD https://releases.hashicorp.com/consul-template/0.12.2/consul-template_0.12.2_linux_amd64.zip /usr/bin/

 ---> Using cache
 ---> df945c1fdee2
Step 7 : RUN unzip /usr/bin/consul-template_0.12.2_linux_amd64.zip -d /usr/local/bin
 ---> Using cache
 ---> ac9e7cd3b7f1
Step 8 : EXPOSE 80
 ---> Using cache
 ---> 2055813afb33
Step 9 : ENTRYPOINT /bin/start.sh
 ---> Using cache
 ---> 79f6283cb4d4
Successfully built 79f6283cb4d4

Debe subir su imagen a un repositorio de imagenes Docker, en nuestro caso usuarios nuestro servicio DonDocker.com, puede crearse una cuenta cp.dondocker.com. Luego de tener su cuenta haga un login y suba su imagen:

$ docker tag load-balance-swarm hub.dondocker.com/dondocker/load-balance-swarm
$ docker login -u <tu-usuario> -p <tu-password> hub.dondocker.com
$ docker push hub.dondocker.com/dondocker/load-balance-swarm

O puede utilizar la imagen hanzel/load-balancing-swarm

Vamos a realizar unos cambios en el archivo docker-compose.yml:

version: '2'

services:
    lb:
        image: hanzel/load-balancing-swarm
        container_name: lb
        ports:
            - "80:80"
        environment:
            - constraint:node==mhs-demo0
            - APP_NAME=joomla-mysql
            - CONSUL_URL=${KV_IP}:8500
        depends_on:
            - web
        networks:
            - front-tier
    web:
        image: joomla
        #ports:
            #- "80"
        environment:
            - JOOMLA_DB_HOST=joomladb
            - JOOMLA_DB_PASSWORD=test
        depends_on:
            - joomladb
        networks:
            - front-tier
            - back-tier
    joomladb:
        image: mysql:5.6
        container_name: joomladb
        environment:
            MYSQL_ROOT_PASSWORD: test
        volumes:
            - mysql-data:/var/lib/mysql
        networks:
            - back-tier

volumes:
    mysql-data:
        driver: local

networks:
    front-tier:
        driver: overlay
    back-tier:
        driver: overlay

La variable de entorno ** constraint:node==mhs-demo0** indica que el contenedor se ejecute en el node mhs-demo0. Se ha añadido una nueva network front-tier que permitirá enlazar el contenedor balanceador de carga y el joomla. La variable KV_IP indica la IP de la máquina que contiene el contenedor consul, la podemos setear de la siguiente forma:

export KV_IP=$(docker-machine ssh mh-keystore 'ifconfig eth1 | grep "inet addr:" | cut -d: -f2 | cut -d" " -f1')

Ahora levantaremos el stack de contendedores Docker:

$ docker-compose up -d
Creating volume "joomla_mysql-data" with local driver
Creating joomladb
Creating joomla_web_1
Creating lb
...

$ docker-compose ps
Name               Command              State       Ports
joomla_web_1   /entrypoint.sh apache2-for ...   Up      80/tcp                             
joomladb       docker-entrypoint.sh mysqld      Up      3306/tcp                           
lb             /bin/start.sh                    Up      443/tcp, 192.168.99.101:80->80/tcp 

Podríamos scalar el servicio de joomla con el siguiente comando:

$ docker-compose scale web=3
Creating and starting 2 ... done
Creating and starting 3 ... done
$ docker-compose ps
Name               Command              State       Ports
joomla_web_1   /entrypoint.sh apache2-for ...   Up      80/tcp                             
joomla_web_2   /entrypoint.sh apache2-for ...   Up      80/tcp                             
joomla_web_3   /entrypoint.sh apache2-for ...   Up      80/tcp                             
joomladb       docker-entrypoint.sh mysqld      Up      3306/tcp                           
lb             /bin/start.sh                    Up      443/tcp, 192.168.99.101:80->80/tcp 

Como hemos visto swarm nos permite escalar y distribuir la carga de trabajo en un grupo de hosts de forma sencilla.

Los esperamos en el próximo artículo. Aún no nos sigues en twitter? Síguenos @dondocker

Leave a comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *