Replicando ambientes com Docker

(Last Updated On: 3 de abril de 2018)

Nossa equipe escreveu alguns testes para o programa que estamos desenvolvendo entrar em produção. Toda nova funcionalidade do sistema deve antes passar por esses testes para depois entrar em produção.

Quando testei o código na minha máquina, funcionou. Porém, quando passei o código para outros desenvolvedores, ele não funcionou!

Por que na minha máquina funciona e nas outras não?

Investigando um pouco mais, percebi que existiam dependências e versões específicas de frameworks e bibliotecas que não eram resolvidas nas máquinas dos outros desenvolvedores.

Nesse caso o problema ocorreu com os testes, mas e se fosse o código em produção?

Precisamos de ambientes iguais, tanto para desenvolvimento, testes e produção. Ou seja, em todos esses ambientes, a versão das bibliotecas, frameworks e demais dependências devem ser iguais. Do contrário, podem causar erros.

Mas como conseguimos ter ambientes iguais?

Conhecendo os containers

Nós podemos criar especificações que devem ser seguidas para manter todos os ambientes o mais igual possível. Dessa forma, todos os desenvolvedores criam seus ambientes por meio dessas especificações, porém, isso pode levar muito tempo de todos os desenvolvedores.

Outra forma de fazer isso é criar apenas um ambiente e replicá-lo para todos do time. Ou seja, criamos apenas uma vez esse ambiente e ele é repassado para todos da equipe. Para isso, podemos utilizar containers.

Num primeiro contato, definimos containers como uma “virtualização não convencional”. Isto é, em uma virtualização tradicional, colocamos outro sistema operacional em cima do nosso.

Esse sistema virtualizado possuí o proprio kernel e hardwares virtual. Já quando criamos containers, estamos compartilhando o kernel e o hardware da máquina com os containers.

Ou seja, nosso container possui apenas as bibliotecas e binários necessários para seu funcionamento. Por isso, são mais leves do que a virtualização tradicional.

Um desses sistemas de criação de containers é o Docker. Com ele conseguimos criar nossos containers a partir de imagens, que nada mais são do que especificações de containers.

Dessa forma, quando precisarmos testar nosso programa, basta criar um container (ou containers) baseado na nossa imagem. Portanto, precisamos criar uma imagem.

Criando nossa própria imagem

Para criar imagens no Docker, podemos utilizar o Dockerfile para criar um imagem baseada em uma imagem existente.

Por exemplo, podemos criar uma imagem da nossa aplicação e rodá-la em um container. Para isso, vamos criar um arquivo chamado aplicacao.dockerfile.

Nesse arquivo, temos que falar qual a imagem que estamos nos baseando para criar nossa imagem. Como minha aplicação é em Python, vou dizer que ela se baseia (FROM) na imagem do python.

FROM python

Nossa aplicação utiliza um microframework Python para web chamado Flask. Ou seja, nossa imagem precisa ter esse framework para a aplicação funcionar. Logo, dizer para o Dockerfile rodar (RUN) o comando para instalá-lo:

RUN pip install flask

Queremos que o container rode nossa aplicação. Portanto precisamos copiar (COPY) o código da nossa aplicação para a nossa imagem. No meu caso, o código está na pasta src, logo, vou copiar esse diretório para o diretório /src:

COPY src /src

Temos que acessar nossa aplicação de alguma forma. Para isso, nós podemos expor (EXPOSE) uma porta do nosso container. Dessa forma, sempre que quisermos acessar a aplicação podemos utilizar essa porta do container.

Já temos o interpretador do Python, o código da aplicação e uma porta para conseguir acessá-la. Falta alguma coisa?

Falta iniciarmos a aplicação! Para fazer isso, podemos dizer que quando o container for criado, isto é, no seu ponto de entrada do container (ENTRYPOINT) vamos pedir para o "python”, executar nossa aplicação: ”/src/app.py”

ENTRYPOINT ["python", “/src/app.py”]

Nosso arquivo final fica dessa forma:



FROM python

RUN pip install flask

COPY src /src

EXPOSE 5000

ENTRYPOINT ["python", "/src/app.py"]

Pronto! Temos um Dockerfile file especificando uma imagem. Contudo, perceba que não temos a imagem pronta. Para isso, precisamos falar para o Docker construí-la.

Construindo uma imagem

Para construir nossa imagem, pelo terminal vamos até o diretório onde criamos o Dockerfile.

Lá pedimos para o Docker construir (build), baseado no arquivo (-f) aplicacao.dockerfile, com o nome (-t) que, no meu caso, vou chamar de yurimatheus/app (nome-do-usuário/nome-da-imagem) já que é um padrão no Docker.

Também precisamos dizer que todos os arquivos para construir a imagem estão neste diretório, para isso, utilizamos o ponto (.) no final do comando:

docker build -f aplicacao.dockerfile -t yurimatheus/app .

Legal! Criamos nossa imagem! Vamos criar um container dessa imagem para testar se nossas configurações funcionaram.

Portanto, vamos falar para o docker rodar (run) um container baseado na imagem que acabamos de criar (yurimatheus/app):

docker run yurimatheus/app

Lembra que colocamos uma porta no container para conseguir acessar a aplicação? Logo, temos que mapear uma porta da nossa máquina host para o container. Isto é, dizer que quando alguém acessar uma porta na máquina host, na verdade estará acessando o container.

Neste caso, vou falar que a porta (-p) 8080 da nossa máquina host vai ser mapeada para a porta 5000 do container, que foi a porta que especificamos no Dockerfile:

docker run -p 8080:5000 yurimatheus/app

Funcionou! Temos nossa aplicação rodando em um container com uma imagem que nós mesmos criamos.

Para saber mais

Criamos um Dockerfile bem simples. Podemos criar Dockerfiles para criar imagens complexas, com diversos outros recursos.

Além de copiar arquivos para a imagem, podemos também criar volumes. Como o container é um processo isolado do sistema host, quando salvamos algo no container e este é reiniciado, ou desativado, nós perdemos esses dados.

É aí que os volumes entram em cena. Com volumes fazemos uma cópia dos dados do container na nossa máquina local. Dessa forma, mesmo se o container parar, ainda temos os dados disponíveis.

Podemos também utilizar o Docker para reduzir nossos gastos como, por exemplo, os gastos com servidores. Ao invés de ter um servidor para cada aplicação, podemos ter containers.

Podemos tem um container para cada ambiente, testes, homologação, produção. Ou então, podemos ter diversos containers nesses ambientes. Um para cada serviço, criando assim, uma arquitetura de microserviços.

Para gerenciar esses diversos containers, o Docker nos oferece uma ferramenta chamada de Docker Compose. Com ele, conseguimos compor uma aplicação com diversos containers.

No curso de Docker da Alura, além de aprender sobre como o Docker funciona, como criar suas imagens, a como subir seus container na nuvem, você também aprende a utilizar o Docker Compose.

Porém, quando o número de containers começa a crescer muito, mesmo com o Docker Compose é difícil de gerenciá-los. Por isso, foram surgindo outras ferramentas, uma muito utilizada é o Kubernetes.

Com ele conseguimos orquestrar nossos containers com base em um único arquivo de configuração.

Aqui na Alura, temos um curso de Kubernetes, onde você aprenderá a realizar essa orquestração. A realizar a comunicação de containers da aplicação com banco de dados, a escalar seus containers e realizar o balanceamento de carga, entre outras coisas.

FIQUE POR DENTRO

Próximo ArtigoUX não é só para designers