Docker, do Básico a Orquestração e Clusterização - 4. Orquestração
Nessa série de artigos estamos abordando tópicos para uma boa utilização do Docker .
No artigo anterior abordamos duas maneiras de construir um container, algumas dicas para montagem e utilização. Agora nos perguntamos montamos um “containerzão” com todos os serviços que minha aplicação precisa para rodar ou montamos vários “containerzinhos” um para cada serviço da aplicação.
Sugiro que sempre monte de acordo com a sua arquitetura em produção, quanto mais “live/production” nosso ambiente de desenvolvimento está, menos surpresas teremos em nossas entregas.
Quando você está trabalhando em uma aplicação cheia de serviços acoplados como banco, memória, busca elástica entre outros serviços acabamos montando tudo no mesmo Virtualbox, ou no mesmo Vagrant, por que se subirmos uma VM para cada serviço nossa máquina host vai pro Goiás. Toda hora vai ficar travando e coisa do gênero.
Com Docker a coisa muda de figura, conseguimos subir vários container na mesma máquina e ligamos eles à nossa maneira na mesma rede. Por exemplo podemos ter um web server que deva se comunicar diretamente com um servidor de banco de dados, então eles devem se enxergar dentro da rede.
Por sua vez o sevidor de banco de dados não precisa se comunicar com uma aplicação de elastic search por exemplo.
Orquestração Vida Loka
A orquestração na unha dá muito trabalho para manter. Neste exemplo vamos subir um container rodando um banco de dados MySQL.
$ docker run -d --name mysql wfsilva/mysql
Antes de rodar o container de Web vamos apagar o antigo
$ docker rm -f web
Agora sim podemos subir o container da aplicação com link para o container de banco de dados:
docker run -it --name web --link mysql:mysql wfsilva/nginx-php-fpm-docker /run.sh
Neste momento temos 2 containers rodando wfsilva/nginx-php-fpm-docker e wfsilva/mysql.
Se entrarmos no container “web” conseguiremos acessar o container “mysql” como se fossem 2 servidores na mesma rede:
$ docker exec -ti wfsilva/nginx-php-fpm-docker bash
# ping mysql
PING localhost (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.064 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.125 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.092 ms
56 bytes from 172.17.0.5: icmp_seq=3 ttl=64 time=0.096 ms
^C
Orquestração com o Fig (Hoje internalizado como Docker Compose)
O Fig é um carinha feito em python que foi inventado para facilitar o uso de vários containers interligados. Ele foi internalizado pelo pessoal do Docker e agora se chama docker-compose . Ele junto com o docker-machine e o docker-swarm são as grandes novidades anunciadas na DockerCon EU 2014 que ocorreu em dezembro de 2014.
Para instalar bastava rodar o comando:
$ pip install fig
Agora temos as seguintes opções:
$ curl -L https://github.com/docker/compose/releases/download/1.1.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
ou
$ pip install -U docker-compose
Com o fig / docker-compose todos os containers que rodam sua aplicação ficam descritos em um arquivo yml onde os nós principais são os containers e os nós dentro de cada container representam suas propriedades.
Ex. de docker-compose.yml:
web:
build: .
command: /run.sh
ports:
- "80:80"
volumes:
- .:/src
links:
- mysql
mysql:
image: mysql
ports: "3306:3306"
O arquivo fala por si só. Ele descreve 2 containers nomeados web e mysql.
O container web vai contruir a partir de um dockerfile que steja localizado no mesmo path onde o arquivo docker-compose.yml está. Vai rodar o run.sh quando iniciar. Vai mapear a porta 80 para a porta 80 do docker host, desta maneira podemos acessá-lo como se fosse um serviço local através do ip 127.0.0.1 . Vai montar o diretório que está para dentro do /src no container e vai ligar com o container mysql.
O container mysql será baixado pronto do repositório no dockerhub e vai mapear a porta 3306 para a porta 3306 do docker host.
Para contruir um container rodamos fig build
$ fig build web
$ # ou
$ docker-compose build web
Para contruir todos os containers do arquivo yml basta rodar sem parâmetros:
$ fig build
$ # ou
$ docker-compose build
Para iniciar ou encerrar um ou mais containers basta passar os nomes:
$ fig start web mysql
$ fig stop mysql
$ # ou
$ docker-compose start web mysql
$ docker-compose stop mysql
Para subir o grupo todo utilizamos o parâmetro up que além de subir os containers vai mostrar os logs de todos os containers na tela. Para finalizar basta dar um ctrl+c. Ou ao iniciar passamos o parâmetro -d que não mostrará os logs na tela.
$ fig up -d
$ # ou
$ docker-compose up -d
Para acessar os logs de execução dos containers:
$ fig logs
$ # ou
$ docker-compose logs
Outra coisa bem legal é o scale. Se temos um container que só expõe a porta (EXPOSE 80) e não mapeia (EXPOSE 80:80) podemos escalar ele:
$ fig scale web=8
$ # ou
$ docker-compose scale web=8
Teremos 8 instâncias do container web rodando. Cada uma em um ip diferente e expondo a porta 80. No docker host essas portas 80 estarão mapeadas em portas altas.
Abaixo veremos um exemplo de yml onde utilizo um container chamado proxy que vi implementado por Jason Wilder .
Nesse container ele mapeia o /var/run/docker.sock da docker host para /tmp/docker.sock dentro do container. No container também tem um binário forego, um script em go que monitora esse arquivo mapeado /tmp/docker.sock e se há alterações ele usa o docker-gen para reconstruir um nginx.conf, se baseando num arquivo de template.
Por fim ele faz um reload do Nginx server e com isso esse Nginx acaba fazendo proxy pass e load balance para os containers monitorados.
O que acham de um yml desse:
proxy:
build: ./proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock
ports:
- "80:80"
redis:
build: ./redis
privileged: true
volumes:
- ./redis:/data
ports:
- "6379:6379"
entrypoint: redis-server
rabbit:
image: tutum/rabbitmq
environment:
- RABBITMQ_PASS=teste
ports:
- "5672:5672"
- "15672:15672"
solr:
build: ./solr
privileged: true
volumes:
- ./src/solr:/src/solr
ports:
- "8983:8983"
entrypoint: /start-solr.sh
mysql:
build: ./mysql
privileged: true
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=teste
- MYSQL_USER=teste
- MYSQL_PASSWORD=teste
- MYSQL_DATABASE=teste_db
web:
build: ./web
environment:
- VIRTUAL_HOST=teste.dev
links:
- redis:redis
- rabbit:rabbit
- solr:solr
- mysql:mysql
privileged: true
volumes:
- ./src:/src
ports:
- "80"
entrypoint: /run.sh
Pois é, se rodamos o comando:
$ fig scale web=5
$ # ou
$ docker-compose scale web=5
O proxy será regenerado e começa a fazer um load balance dos requests feitos para o domínio teste.dev entre todos o containers web que estiverem rodando.
Isso é ótimo para testar se a aplicação suporta load balance entre diversos servidores.
Mais detalhes dessa suruba de containers desse arquivo yml no meu github .
To Be Continued
Ainda abordaremos como utilizar o docker em ambiente Windows e Mac (boot2docker e docker-compose) e o gerenciador de clusters de containers: docker-swarm.
Té +