Utilizando Docker em ambiente de desenvolvimento

Criação de containers e como conectá-los.

Publicado por Lohan Bodevan 3 de Outubro de 2016 às 19:28

Introdução

Docker é uma ferramenta que permite criar containers isolados porém que compartilham o mesmo Kernel. Imagine uma unidade isolada do sistema operacional, totalmente independente, onde você pode instalar pacotes e rodar serviços. Uma das vantagens do Docker sobre softwares de virtualização como Vagrant é que os containers ocupam muito menos disco do S.O hospedeiro.

Neste rápido tutorial, vou mostrar como rodar um código Python simples, usando Memcached e MySQL.

 

O que você precisa saber antes de começar?

Considero que você tenha conhecimentos básicos sobre utilização de um banco de dados relacional como o MySQL e banco de dados em memória como o Memcached. Além, claro, do uso do terminal do seu sistema operacional.

 

Preparando o ambiente

Para quem usa o Ubuntu, ou alguma outra distribuição Linux, é bem fácil instalar o Docker e eu recomendo seguir o passo a passo da documentação oficial, ele é bem claro e prático.

Uma dica importante: Após a instalação, você precisará usar sudo antes de cada comando Docker. Para evitar isso, você precisa seguir os passos abaixo:

  1. Criar um grupo chamado docker

sudo groupadd docker
  1. Adicione seu usuário ao grupo docker

sudo usermod -aG docker $USER
  1. Faça Logout e Logon no sistema

Pronto! Para testar, execute o seguinte comando:

docker run hello-world

Se tudo ocorrer bem você deve ver uma tela de sucesso parecida com essa abaixo:

Resultado hello world

Para quem usa OSX, macOS ou Windows existe um pacote de softwares chamado Docker Tool Box.

A instalação é bem simples, vou deixar aqui o link para configuração em cada plataforma:

  • Instalação do Docker Tool Box no Mac

  • Instalação do Docker Tool Box no Windows

O comando para verificar se a instalação está correta é o mesmo:

docker run hello-world

 

Ação

Vamos criar um container MySQL chamado mysql-db, um Memcached chamado memcached-db e um container para a aplicação chamado python-flask

Criando container MySQL

Agora que temos o Docker instalado vamos criar um container para o nosso banco de dados, para isso usaremos o comando run

docker run -d -p 3306:3306 --name mysql-db -e MYSQL_ROOT_PASSWORD=root mysql:5.6

-d

O argumento `-d` ou `--detach` significa que queremos que o container continue rodando ao invés de executar um único comando e sair, como fizemos com o hello-world.

-p

O argumento `-p` informa a porta que desejamos exportar do nosso container. (hostPort:containerPort). Isso significa que, a porta 3306 da máquina hospedeira irá redirecionar para a porta 3306 do container.

Importante, se você possui o MySQL server instalado e rodando no seu computador, o comando docker vai falhar pois a porta 3306 já estará em uso. Para usar o MySQL apenas via Docker você precisa parar o MySQL local. No Ubuntu pode ser feito da seguinte forma:

sudo service mysql stop

-e

O argumento `-e` tem a função de setar variáveis de ambiente no container, nesse caso iremos setar a variável `MYSQL_ROOT_PASSWORD` com o valor `root`. Ou seja, quando container for criado será setada a senha "root" para o usuário "root" do MySQL.

Teste a conexão do servidor de banco de dados no container com o software client de MySQL de sua preferência.

Para quem usa Ubuntu poderá usar o host “localhost” com usuário “root” e senha “root”.

Para quem usa Mac ou Windows muda apenas o host, ao invés de “localhost” deverá usar o ip da Docker Machine que pode ser consultado da seguinte forma:

docker-machine ip default

--name

`--name` é utilizado para nomear o container. Apesar de não ser um argumento obrigatório, é muito importante pois, caso não seja definido, o Docker irá setar um nome aleatório para o container.

Imagem

O último argumento `mysql:5.6` informa o nome e a versão da imagem que o Docker usará para construir o container. É comum usar a versão da imagem para informar a versão do software, no nosso caso a imagem base que será usada para o container será a do MySQL Server 5.6.

Verificando os containers ativos

docker ps

Este comando lista todos os containers que estão "UP", com seus respectivos IDs e informações de forward de porta. Para listar todos os containers, independente do estado, use o argumento `-a`:

docker ps -a

 

Criando container Memcached

docker run -d -p 11211:11211 --name memcached-db memcached

Para a criação do container memcached nenhuma diferença do exemplo acima, exceto que não utilizamos uma versão específica para imagem, então o Docker se prontificará a achar a última versão de imagem Memcached disponível.

Criando container da aplicação

Para este tutorial iremos utilizar uma aplicação de código Python com o micro framework Flask. O foco aqui não é o código e sim a utilização do Docker, por isso ele será o mais simples possível.

Vamos criar o container:

docker run -d -it -p 5000:5000 --name python-flask -v `pwd`:/home/application/python-flask -w /home/application/python-flask --link memcached-db --link mysql-db python:3.5

Aqui utilizamos alguns argumentos diferentes. Mas calma, vamos vê-los um a um.

-it

Na verdade é uma junção dos argumentos `-i` e `-t`.

O argumento `-t` aloca um pseudo-terminal (pseudo-tty), isso nos irá permitir conectar via ssh no container, porém nesse caso específico só será possível se utilizarmos em conjunto o argumento `-i` que mantém vivo um STDIN.

Diferente dos containers MySQL e Memcached, o container da nossa aplicação não possui nenhum processo padrão rodando, ele é apenas um container Python aguardando que façamos algo com ele.

Se não utilizarmos esses dois argumentos em conjunto, o container iria levantar e cair logo em seguida pois não passamos nenhum comando para ele executar.

-v

Este argumento tem como função montar volumes, ou seja, compartilhar uma determinada pasta da máquina hospedeira com o container. No nosso exemplo utilizamos o seguinte: `pwd`:/home/application/python-flask

Onde `pwd`, conhecido comando de sistemas unix-like, representa a pasta atual. E separamos então com ":" onde a queremos montar dentro do container.

-w

O argumento `-w` não é obrigatório neste contexto porém ele facilita muito nossa vida, ele significa workdir. O propósito é definir uma pasta que será usada como diretório padrão ao conectar via ssh no container.

--link

Aqui acontece a mágica! O argumento `--link`, como o nome sugere, irá criar um link entre o container que está sendo criado com o container citado logo em seguida. No nosso exemplo estamos criando dois links, um para o container que nomeamos de memcached-db e outro de mysql-db.

Isso significa que dentro do container python-flask o servidor Memcached chama-se memcached-db e o servidor MySQL chama-se mysql-db. E como fizemos o forward de portas, podemos acessar ambos servidores por suas portas padrão, 11211 e 3306 sucessivamente.

Portanto ao criar uma conexão com o MySQL via aplicação o host mysql-db deverá ser usado. O mesmo vale para o Memcached (memcached-db). Fácil não é?

O último argumento como já falamos é a imagem Python na versão 3.5, que possui o Python 3.5 como versão padrão. Vale lembrar que em sua grande maioria as imagens bases são versões enxutas de distribuições Linux, otimizadas para o seu propósito. Você encontra diversas imagens no Docker Hub, o repositório oficial de imagens Docker.

Código da aplicação

Os arquivos abaixo deverão ser criados na raiz do projeto.

app.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cache import Cache

app = Flask(__name__)
# Database config
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]/mysql'
db = SQLAlchemy(app)
# Cache config
cache = Cache(app,
              config={'CACHE_TYPE': 'memcached',
                      'CACHE_MEMCACHED_SERVERS': ['memcached-db']
                     }
            )
@app.route("/")
def main():
    db_test = db.engine.execute("SELECT 1;").fetchone()
    cache.set('test_key', 1, 1000)
    cache_test = cache.get('test_key')
    return "DB: OK {} - CACHE: OK {}".format(db_test, cache_test)
if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0')

requirements.txt

Flask==0.11.1
mysqlclient==1.3.7
Flask-SQLAlchemy==2.1
Flask-Cache==0.13.1
python-memcached==1.58

Com estes dois arquivos conseguimos testar se nosso container python-flask está conseguindo conectar-se aos outros dois containers de serviço.

Antes vamos executar um comando para instalar as dependências da nossa aplicação. Em todo caso, nossa aplicação irá rodar dentro do container, por isso o comando deve ser executado lá e existem duas formas de fazer isso.

Executando comandos dentro do container via `docker exec`

docker exec -it python-flask pip install -r requirements.txt

O comando é auto-explicativo, o argumento `-it` já conhecemos, após ele vem o nome do container e em seguida o comando a ser executado dentro dele: pip install -r requirements.txt

Executando comandos dentro do container via ssh

docker exec -it python-flask bash
pip install -r requirements.txt

Esta forma possui dois passos, o primeiro é fazer logon via ssh no container e o segundo é executar de fato o comando para instalar as dependências de nossa APP. Para sair da conexão com o container executar `exit`.

Run

Com isso feito, agora é só dar o start da aplicação:

docker exec -it python-flask python app.py

 

Resultado

Se tudo ocorrer bem você verá as seguintes mensagens ao acessar a URL http://localhost:5000/ (Lembrando que se você está no Windows ou Mac, deverá trocar "localhost" pelo ip de sua Docker Machine).

Resultado link container

 

Conclusão

Vimos aqui alguns conceitos básicos sobre o Docker, como criar containers, como conectá-los e como executar comandos dentro deles via ssh, bem legal não é? Mais da pra ficar ainda melhor, podemos usar o Docker Compose, ele facilita esse trabalho de conectar containers. Podemos também criar um Dockerfile para automatizar alguns comandos como o de instalar dependências e dar o start na nossa aplicação.

Mas eu preferi começar os posts sobre Docker dessa forma para que fica claro o que é feito por baixo dos panos. Acredito muito nas ferramentas que facilitam nossa vida, porém é importante saber o que ela está fazendo.

Espero que tenham sido úteis essas dicas, em breve postarei mais sobre o assunto.

Grande Abraço!


Comentários