Docker: containers, isolamento e replicabilidade de ambientes de produção

Se com o Vagrant você consegue ter o ambiente de dev como parte do código fonte do projeto, como ter o mesmo para o ambiente de produção? Conheça agora o Docker!

Docker é uma abstração, que adiciona recursos e simplifica o uso, dos linux containers (LXC), que são, basicamente, uma forma de isolamento de processo e sistemas, quase como virtualização, porém mais leve e integrada ao host. Linux-only, nesse caso.

O Docker então te permite criar aplicações e “containers”, que isolam o SO base e todo a pilha de dependências de seu app (libs, servidores, etc, etc) de forma leve em espaço e performance. É o vagrant para produção, basicamente. Pense em VMs muito leves, que podem rodar em cima de outras VMs, na verdade.

Assim, você pode usar o Docker para ter diversas aplicações com ambientes diversos (apache vs unicorn vs tomcat vs whatevernot) em uma mesma maquina ou vm porém sem perder muito em recursos.

O Docker trabalha ainda com um sistema de arquivos “empilhaveis”, o aufs, que permite que os passos para configuração do seu container funcionem de forma incremental e “cacheable”, mais ou menos como “commits” do GIT. Pense em GIT para seu ambiente de produção ;-).

Atualizou libs: commit. Instalou o server: commit. Terminou uma nova versão: Tag. Da mesma forma você pode mandar o ambiente em partes para a nuvem (push) você também pode trazer apenas as atualizações (pull). Viu, git.

E como fazer, afinal:

Primeiro, o Docker é para o linux, assim em outros sistemas você vai precisar de uma maquina virtual com linux (usando, por exemplo, o vagrant :-). Instale o docker para sua distro e comece seu primeiro projeto.

Você deve escolher uma maquina base, como uma das muitas disponíveis no Docker index. Pode ser que já tenha uma 100% como você precisa, ou até os 80% chatos prontos. Em seguida o principal comando do docker:

docker run -i -t ubuntu /bin/bash

Esse comando diz: docker, rode (run), de forma interativa (-i, para terminais), em cima da imagem do ubuntu (-t ubuntu, de tag) o comando bash (/bin/bash). Outro exemplo:

docker run -t ubuntu echo hello from docker

Repare que após rodar um comando esse vai retornar um identificador, esse é o id da imagem gerada pelo comando. Você pode ver todos os containers, ativos ou não:

docker ps # containers em execução
docker ps -a # todos

Como configurar uma maquina então?

CONTAINER=$(docker run -t ubuntu apt-get update) # atualiza e salva o id do container
CONTAINER=$(docker run $CONTAINER apt-get install apache2 -y) # instala o apache e salva o id do container
docker tag $CONTAINER diogok/apache2 # identifica o ultimo comando
$RUNNING_CONT=$(docker run -d -t diogko/apache2 apache -D FOREGROUND)
docker ps
docker logs  $RUNNING_CONT

Temos vários parâmetros importantes, alguns são:

Redirecionando portas: -p host:guest direciona a porta host para o porta do guest, pode usar várias vezes. Ou -P para expor várias portas aleatoriamente (apenas portas descritas como passiveis de expor, mais disso mais tarde).

docker run -p 8080:80 -t diogok/apache2 #direciona a porta 8080 da maquina host para a 80 do apache

 Variáveis de ambiente: usando -e FOO=BAR o container vai ter essa variável disponível.

Rordar em background: -d , pois por padrão ele vai ficar no seu terminal.

Compartilhar volumes(pastas): -v /pasta1:/pasta2 compartilha a pasta  /pasta1 do host como a /pasta2 do guest (ele monta como um volume). Pode usar para vários containers ao mesmo tempo.

Isso tudo é legal, mas o grande ganho eu acho que vem com  a configuração sendo parte do projeto, usando o Dockerfile.  O formato do Dockerfile é bem simples, eis um exemplo:

FROM ubuntu:14.04 # baseado no ubuntu 14.04
RUN apt-get update # rode esse comando
RUN apt-get install apache2 -y # lembre de confirmar automáticamente, pois você não vai ter um tty
ADD index.html /var/www/index.html # copia um arquivo do projeto
EXPOSE 80 # expõe a porta 80
CMD [“apache”,”-D”,”FOREGROUND”] # esse é o comando padrão

Para construir esse Dockerfile em um container basta executar, na pasta do projeto:

docker build -t diogok/apache2 .

Então para rodar o container:

docker run -d -P -t diogok/apache2

Para ver em execução:

docker ps

Ler os logs:

docker log $container_id

E enviar pro registro online:

docker push diogok/apache2

Cada passo é atômico e fica em cache, assim se você muda um passo ele só vai refazer este e os seguintes.

Isso tudo vai ter dar um ambiente replicação para dev,homolog e prod, seja lá onde cada um for (aws, digitalocean, linode, sua máquina…).

Experimente com diferentes construções do docker e divirta-se.