Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Panel
titleColor#FFF
titleBGColor#2A7886
titleContinguts

Table of Contents
maxLevel2

 

 

Balanceig transparent amb Docker Swarm, Compose i Consul

Crearem un cluster de docker-engine i instanciarem allà els nostres contenidors docker. A més configurarem un servei balancejat d'alta disponibilitat escalable.

Docker Swarm: Ens permet crear un cluster docker. El node master rebrà i distribuirà els contenidors als nodes secundaris on s'executaran.

Consul: Ens proporcionarà el servei de discover dels nous nodes i serveis que afegim al clúster swarm.

Registrator: Aquest servei monitoritzarà la informació com ara IP i PORT de cada servei activat als hosts i ho guardarà al consul.

Docker Compose: Ens permet configurar i crear grups de contenidors. Podem escalar el servei ofert per un contenir augmentar o disminuint el nombre de contenidors. 

En la següent imatge es mostren un seguit eines d'DevOps cobreix tot el cicle de vida de les aplicacions, en el tutorial ens centrarem en la part del desplegament fent servir la plataforma OpenNebula juntament amb Docker Swarm, Docker Compose i el servei de Consul.

Requeriments previs

  • Docker Engine: Ens permet crear els contenidors, gestionar-los i instanciar-los
  • Docker Machine: Ens permet crear i gestionar les maquines virtuals
  • Driver Docker Machine Opennebula: Ens permet utilitzar el docker-machine al cloud de l'OpenNebula
  • Docker Compose

Instal·lar el requeriments:

  • Per a poder implementar el docker swarm cluster amb l'OpenNebula hem d'instalar el Docker Engine, Docker Machine i el Driver Docker Machine Opennebula.
    Aquí està el manual de com fer-ho: DOCKER-1 Docker Machine OpenNebula Driver

  • Per instal·lar Docker Compose:

    Code Block
    languagebash
    themeRDark
    sudo -i
    curl -L https://github.com/docker/compose/releases/download/1.6.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose
    exit

Consul

Disposarem d'una maquina virtual que ens proporcionarà el servei de discover amb consul

Creem una màquina virtual a l'OpenNebula anomenada consul i deprés executem un contenidor docker de consul dins d'ella.

Code Block
languagebash
themeRDark
docker-machine create -d opennebula --opennebula-network-id [network_id] --opennebula-image-id [boot2docker_image_id] --opennebula-b2d-size [volatile_disk_size] consul
docker $(docker-machine config consul) run -d -p "8500:8500" -h "consul" progrium/consul -server -bootstrap 

Docker Swarm

Diposarem dos tipus de màquines virtuals amb swarm:

  • Swarm-master: Aquesta màquina amb swarm serà l'encarregada de distribuir les instàncies dels contenidors als diferents nodes que tinguem al clúster.
  • Swarm-node: Aquesta o aquestes màquines seran les que executaran els contenidors docker.

Swarm-master

Creem la màquina virtual del swarm-master:

Code Block
languageperl
themeRDark
export CONSUL_IP=$(docker-machine ip consul)
docker-machine create -d opennebula --opennebula-network-id [network_id] --opennebula-image-id  [boot2docker_image_id] --opennebula-b2d-size [volatile_disk_size] --swarm --swarm-master --swarm-discovery="consul://$CONSUL_IP:8500" --engine-opt cluster-store=consul://$CONSUL_IP:8500 --engine-opt cluster-advertise="eth0:2376" swarm-master

Swarm-node

 Creem la màquina virtual del swarm-node:

Code Block
languageperl
themeRDark
docker-machine create -d opennebula --opennebula-network-id [network_id] --opennebula-image-id [boot2docker_image_id] --opennebula-b2d-size [volatile_disk_size] --swarm --swarm-discovery="consul://$CONSUL_IP:8500" --engine-opt cluster-store=consul://$CONSUL_IP:8500 --engine-opt cluster-advertise="eth0:2376" swarm-node-1

Podem crear els nodes que vulguem. Només hem de canviar el nom de la màquina virtual 

Desplegar contenidors Registrator

Un cop hem creat el master i els diferents nodes, instanciarem els contenidors amb registrator a tot ells. Utilitzarem la image de gliderlabs/registrator

Necessitem tenir un servei Registrator corrent en cada host per monitoritzar tots el serveis que corre cada host. 

Code Block
languageperl
themeRDark
export MASTER_IP=$(docker-machine ip swarm-master)
export NODE_IP=$(docker-machine ip swarm-node-1)

eval $(docker-machine env --swarm swarm-master)
docker run -d --name=registrator -h ${MASTER_IP} --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest consul://${CONSUL_IP}:8500

eval $(docker-machine env swarm-node-1)
docker run -d --name=registrator -h ${NODE_IP} --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest consul://${CONSUL_IP}:8500

Load Balancer

Ara hem d'implementar un balancejador de càrrega que pugui distribuir les peticions per les diferents instàncies del servei. Com augmentarem i disminuirem les instàncies del servei, necessitem que el balancejador de càrrega s'actualitzi automàticament.

Utilitzarem nginx per al load balancer i consul-template per la configuració del nginx.

default.ctmpl

Primer de tot, necessitem crear un template per a la configuració del nginx. Consul-template automàticament omplirà aquest fitxer amb la informació referent al servei instanciat i crearà la configuració pel nginx.

El fitxer default.ctmpl ha de ser així:

Code Block
languageperl
themeRDark
{{$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}};
    }
}

Crearem la variable app amb el valor de la variable d'entorn APP_NAME (definida més endavant al fitxer docker-compose.yml). També crearem un upstream amb el nom de la variable app. La linia least_conn fa que nginx encamini el traffic cap a l'instancia amb menys connexions.

Per cada instancia del servei corrent crearem una linia amb l'adreça del node on s'executa ({{.Address}}) i el port per on està escoltant ({{.Port}}).

Finalment està la zona de configuració del servidor. Aqui definim el port d'escolta del load balancer i creare una reverse proxy a l'upstream que hem creat.

start.sh

Necessitem un script que actui com a entry point per a questa imatge docker.  

El fixer start.sh ha de ser aixi:

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

Aquest script engega primer el servei nginx. Després engega consul-template passant-li dos paràmetres:

  • -consul: Li passem la variable d'entorn $CONSURL_URL definida al docker-compose.yml
  • -template: Li passem 3 paràmetres: el path on està el template que hem creat anteriorment (dins del contenidor), el path on es guardarà el fitxer de configuració generat i la comanda que s'executarà un cop es generi una nova configuració.

El consul-template crearà un nou fitxer de configuració cada cop que un servei s'engegui o s'aturi. La informació sobre aquests serveis es recollida per el servei registrator de cada node swarm i es emmagatzemada en el consul.


Note
El fitxers start.sh i default.ctmpl els guardarem en un directori anomenat "files". En el directori pare hi guardarem els fitxers Dockerfile i docker-compose.yml

Dockerfile  


Code Block
languageperl
themeRDark
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"]

Aquest Dockerfile utilitza nginx com a imatge base i instal·la consul-template damunt. Després copia l'script start.sh i el template default.ctmpl (que abans hem creat) dins del contenidor. Finalment exposa el port 80 i defineix el script start.sh com a entry point de la imatge.

Docker Compose

Docker Compose ens permet escriure la configuració que volem que tinguin els contenidors a desplegar. Utilitzarem Docker Compose File version 2, que ens permet definir la configuració referent a la xarxa, volums, ports, variables d'entorn.

Per saber més sobre la versió 2 del fitxer de docker-compose, vés aqui.

docker-compose.yml

Exemple de docker-compose.yml

Code Block
languageperl
themeRDark
version: '2'
services:
  lb:
    build: .
    container_name: lb
    ports:
      - "80:80"
    environment:
      - APP_NAME=[Nom_del_servei]
      - CONSUL_URL=${CONSUL_IP}:8500
    depends_on:
      - web
    networks:
      - front-tier
  web:
    image: [imatge_docker] 
    ports:
      - "[Port_del_servei]"
    environment:
      - SERVICE_NAME=[Nom_del_servei]
    networks:
      - front-tier
networks:
  front-tier:
    driver: overlay

Gestionar Docker Compose

Per arrencar tots el serveis executem el següent.

Per a veure els detalls dels serveis corrent podem utilitzar la comanda docker-compose ps

Code Block
languageperl
themeRDark
eval $(docker-machine env -swarm swarm-master)
docker-compose up -d
docker-compose ps

 Per parar i eliminar els serveis que estan corrent actualment:

Code Block
languageperl
themeRDark
docker-compose stop; docker-compose rm -f

Ara mateix només tenim una instància del servei. Si volem augmentar o disminuir

Code Block
languageperl
themeRDark
docker-compose scale [nom servei]=[nombre d'instancies]


Per a més informació : https://botleg.com/stories/load-balancing-with-docker-swarm/

Exemple d'ús

 Volem crear un cluster de docker i crear un servei web balancejat amb nginx i escalable amb docker Compose.

Actualment disposeu de dues imatges, ja precreades amb el Docker Engine instal·lat que podeu fer servir:

  • Creem les màquines virtuals de consul, swarm-master i un swarm-node:

Code Block
languagebash
themeEmacs
docker-machine create -d opennebula --opennebula-network-id $NETWORK_ID --opennebula-image-name boot2docker --opennebula-b2d-size 10240 consul
docker $(docker-machine config consul) run -d -p "8500:8500" -h "consul" progrium/consul -server -bootstrap
export CONSUL_IP=$(docker-machine ip consul)
docker-machine create -d opennebula --opennebula-network-id $NETWORK_ID --opennebula-image-name boot2docker --opennebula-b2d-size 10240 --swarm --swarm-master --swarm-discovery="consul://$CONSUL_IP:8500" --engine-opt cluster-store=consul://$CONSUL_IP:8500 --engine-opt cluster-advertise="eth0:2376" swarm-master
docker-machine create -d opennebula --opennebula-network-id $NETWORK_ID --opennebula-image-name boot2docker --opennebula-b2d-size 10240 --swarm --swarm-discovery="consul://$CONSUL_IP:8500" --engine-opt cluster-store=consul://$CONSUL_IP:8500 --engine-opt cluster-advertise="eth0:2376" swarm-node-1
     --opennebula-b2d-size 10240: Creem discos volàtils de 10GB

 

Warning

On $NETWORK_ID, serà l'ID de la xarxa on crearem el clúster. 

 

 

  • Despleguem Registrator a tots els nodes

    Code Block
    languagebash
    themeEmacs
    export MASTER_IP=$(docker-machine ip swarm-master)
    export NODE_IP=$(docker-machine ip swarm-node-1)
    
    eval $(docker-machine env --swarm swarm-master)
    docker run -d --name=registrator -h ${MASTER_IP} --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest consul://${CONSUL_IP}:8500
    
    eval $(docker-machine env swarm-node-1)
    docker run -d --name=registrator -h ${NODE_IP} --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest consul://${CONSUL_IP}:8500
  • Creem els fitxers de configuració necessaris

files/default.ctmpl

Code Block
languageperl
themeRDark
{{$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}};
    }
}

files/start.sh

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

Dockerfile

Code Block
languageperl
themeRDark
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"]

docker-compose.yml

Code Block
languageperl
themeRDark
version: '2'
services:
  lb:
    build: .
    container_name: lb
    ports:
      - "80:80"
    environment:
      - APP_NAME=web_nginx
      - CONSUL_URL=${CONSUL_IP}:8500
    depends_on:
      - web
  web:
    image: nginx
    ports:
      - "80"
    environment:
      - SERVICE_NAME=web_nginx
networks:
  default:
    driver: overlay

 

  • Activem el servei


    Des del directori on tenim el docker-compose.yml, executem:
Code Block
languageperl
themeRDark
eval $(docker-machine env -swarm swarm-master)
docker-compose up -d
docker-compose ps

 

  • Augmentar o disminuir les instancies del servei


    Per augmentar o disminuir les instàncies del servei utilitzem la següent comanda

Code Block
languageperl
themeRDark
docker-compose scale web=4

Amb aquest comanda augmentarem en 4 les instàncies desplegades del servei web.

El nom que indiquem ha de ser en nom que hem indicar en el fitxer docker-compose.yml. Nosaltres el fitxer docker-compose.yml hem indicat que el nom del servei era web.

Executem docker-compose ps per saber com estan les instancies. Hem esborrat les IP. Aqui es veurien com les instancies estan repartides pel diferents nodes del cluster swarm.

 

  • Accedir al servei

     
    Hem d'accedir amb la IP del load balancer (lb)

  • Aturar i/o esborrar el serveis


Code Block
languageperl
themeRDark
docker-compose stop; docker-compose rm -f