Palavras chaves: Docker, deployment, colocar o projeto no ar, container, Heroku, Streamlit
Material produzido para a Tera
A divulgação de um projeto é um passo essencial a ser tomado pelas pessoas que trabalham com a Ciência de Dados, afinal de contas, imagine o desperdício em ter desenvolvido a melhor solução para um problema porém deixá-la esquecida em seu computador?
Antes de mais nada…
O que é o Docker e para o que ele serve?
Docker é uma ferramenta de compartimentalização. Ele agrega todos aqueles arquivos necessários para o funcionamento de um aplicativo e os concentra em um único compartimento chamado container.
Certo, então o Docker simplesmente organiza meu documento de código e base de dados em um lugar só?
Não é bem isso. A princípio pode parecer que um projeto de Ciência de Dados funciona apenas com um script de código e dados. Entretanto, vale lembrar que mesmo o mais simples dos projetos utiliza muitas coisas, desde bibliotecas ao próprio sistema operacional da máquina.
Um projeto que tenha sido codificado utilizando uma versão específica de uma biblioteca pode apresentar um comportamento inesperado ou quebrar caso seja executado em uma máquina que contenha uma versão diferente da mesma biblioteca. Essa incompatibilidade pode ocorrer inclusive com os sistemas operacionais: um projeto desenvolvido em um ambiente Windows pode comportar-se diferente em um Linux. Esse problema de incompatibilidade de configurações entre máquinas é conhecido como dependency hell🔥.
O risco de incompatibilidade é mitigado pelo Docker, que concentra no container tudo o que o aplicativo precisa para funcionar em qualquer máquina. Isso garante que o projeto se comporte exatamente da mesma forma para qualquer usuário.
A definição acima parece de uma máquina virtual. Qual é a diferença entre uma máquina virtual e um container?
De fato, em termos práticos, ambos são semelhantes. Tanto a máquina virtual quanto o container emulam ambientes operacionais com configurações específicas dentro de uma máquina. Elas diferem, contudo, na maneira como isso é feito.
De forma geral, uma máquina virtual emula um computador de forma integral, processando todas as configurações, desde o sistema operacional, softwares e até bibliotecas.
Ou seja, a carga de processamento da máquina virtual é alta pois ela cria virtualmente uma segunda máquina completa com os recurso da máquina física.
O container, por sua vez, processa apenas as configurações necessárias para a execução do projeto, evitando a alocação desnecessária da capacidade de processamento da máquina física.
Essa diferença é a vantagem do container, pois ao economizar esse poder de processamento, o projeto é executado em menos tempo.
Em outras palavras, a vantagem do container é sua eficiência.
Entendido o que é o Docker e quais são suas funcionalidades básicas, o próximo passo consiste em entender como usá-lo.
Guia prático do Docker
Este guia prático contém um passo-a-passo para colocar um projeto simples no ar. Cada etapa aborda os comandos a serem executados e sua explicação conceitual.
O funcionamento do Docker será exemplificado a partir de um projeto comum em Python que utilize o framework de aplicação web do Streamlit. O Docker será utilizado para criar uma versão executável da aplicação web e, por fim, o deployment será via Heroku.
Passo 1: Python
Durante o desenvolvimento de um projeto é comum a utilização de recursos como o Jupyter Notebook ou o Google Colab que facilitem a visualização gráfica do código.
Para o deployment será necessário converter o código do formato “.ipynb” em um arquivo com extensão “.py”. Essa conversão é simples, bastando utilizar um programa de editor de texto (e.g. Notepad ou Sublime) para salvar o arquivo na extensão “.py”.
Passo 2: Streamlit
Provavelmente, uma solução de machine learning apresentada apenas em linhas de código não será compreendida pela maioria de seus usuários. Uma maneira de solucionar isso é transformar o código em uma interface gráfica amigável e de fácil entendimento. O Streamlit é uma das opções mais populares para cumprir essa função.
O Streamlit é uma biblioteca open source do Python e sua função é permitir o desenvolvimento da interface de um aplicativo web. Desenhada para ser uma solução simples e de fácil utilização, a biblioteca permite a implementação de uma interface pré-definida em poucas linhas de código.
Uma introdução do Streamlit e suas funcionalidades básicas pode ser encontrada neste artigo. O exemplo utilizado pode ser acessado no link abaixo:
Este guia prático do Docker se baseará no mesmo projeto acima, e pode ser encontrado no repositório GitHub abaixo:
Copie o repositório acima em sua máquina física e certifique-se que o Streamlit consiga executá-lo. Para isso, abra o terminal e execute os comandos abaixos:
Uma janela do navegador deverá ser aberta e apresentar a imagem abaixo:
É importante que tenhamos certeza que o Streamlit está sendo executado corretamente. Caso o projeto não tenha carregado no navegador ou o terminal falhou em executar o projeto, será necessário investigar o problema. Nesse sentido, o próprio log resultado no terminal é uma pista dos possíveis erros.
Passo 3: Docker
3.1: Instalando o Docker
O Docker pode ser utilizado em máquinas Mac, Windows ou Linux. O website oficial contém uma seção dedicada para a instalação em cada plataforma.
Certifique-se que o Docker foi instalado corretamente executando o seguinte comando no terminal:
O hello-world
foi importado do repositório público do Docker (i.e. Docker Hub) e executado em nossa máquina física. Isso significa que a instalação foi um sucesso.
Repare que na primeira linha de retorno do código o objeto destacado foi image
e não um container
:
unable to find image "hello-world:latest" locally
A imagem é um “diagrama”que contém os elementos necessários para a execução de um aplicativo, sendo a partir dela que um container é criado. Para entender mais das diferenças, esse artigo da Sofija Simic faz uma análise interessante sobre imagens vs containers.
A próxima etapa é criar uma imagem do projeto exemplo.
3.2: Preparação para criação da imagem
A criação da imagem do projeto exemplo depende de outros dois arquivos: o Dockerfile e o requirements.txt.
O Dockerfile é um arquivo de texto sem extensão que contém os comandos a serem executados pelo Docker durante a criação da imagem, ou seja, o Dockerfile é a “receita” da imagem. Caso o arquivo não seja incluído no projeto, o terminal resultará na mensagem de erro abaixo:
Para criar o Dockerfile basta copiar o código a seguir em um editor de texto, como por exemplo o Notepad ou o Sublime, e salvá-lo sem extensão:
Dica: no Windows, basta salvar o documento com aspas, ou seja, “Dockerfile”)
Além do Dockerfile, será utilizado também um arquivo chamado requirements.txt, que é um documento de texto simples que contém as bibliotecas e versões específicas utilizadas no projeto. Em nosso exemplo, o requirements.txt contém os seguintes códigos:
Esse documento, diferentemente do Dockerfile, não é essencial para rodar o Docker. Nesse caso, basta incluir manualmente as bibliotecas e suas versões no Dockerfile, o que pode ser mais simples se estamos falando de duas ou três bibliotecas. Contudo, quando o projeto contém múltiplas bibliotecas (que é o mais provável), torna-se impraticável fazê-lo manualmente.
Felizmente, existem maneiras fáceis de se criar o requirements.txt, como o uso da biblioteca Pipreqs. Ela gera automaticamente o documento requirements.txt com base nas bibliotecas encontradas na pasta raiz.
No terminal execute o código abaixo:
3.3: Criando a imagem
Para criar a imagem, é necessário executar no terminal o código abaixo. Essa linha de código significa basicamente “docker, pegue os arquivos da pasta atual e construa uma imagem e o nomeie como artigo_docker”.
Dica 💡: a primeira execução desse código deve levar alguns minutos, então aproveite para pegar um café e trocar sua playlist de música.
Repare que o processo de criação da imagem durou vários passos (nesse exemplo foram 7 passos) e esses passo são determinados por cada linha do Dockerfile.
Essa lógica de construção gradual da imagem é denominada criação por camadas, e também contribui para a agilidade do Docker. Neste exemplo a primeira camada foi o Python (mais especificamente, uma imagem da versão 3.8.2 do Python que encontra-se no repositório público do Docker Hub). Gradulmente, outras camadas foram sendo agregadas até resultar na imagem final artigo_docker.
A vantagem disso é que, caso a imagem seja recriada ou opte-se por criar outras imagens também utilizem a versão 3.8.2 do Python, o processo leva menos tempo, dado que as parte das configurações necessárias já estarão salvas em sua máquina física.
Para verificar as imagens existentes em sua máquina física, insira no terminal docker image ls
. O terminal deverá retornar três imagens: a hello-world usada no começo do artigo, a python utilizada em nossa imagem e a própria imagem artigo_docker.
Disclaimer: não executaremos o container no Docker.
Apesar do Docker ser capaz de montar e executar o container, neste tutorial usaremos o Docker apenas para criar a imagem, enquanto criar o container e executá-lo ficará a cargo do Heroku. A lógica disso é que o objetivo é disponibilizar o projeto na internet, porntato, o container deverá ser executado no servidor, e não em um ambiente local.
Passo 4: Heroku
Uma vez construída a imagem, os próximos passos são construir o container e executá-lo em um servidor. Este tutorial utiliza a plataforma de servidores em nuvem Heroku. Será necessário a criação de uma conta, mas fique tranquilo pois há a possibilidade criar uma conta gratuita que permite a hospedagem simultânea de até cinco aplicativos.
Faça o login em sua conta e crie um novo aplicativo:
Após criar sua conta, será necessário também instalar o Heroku Command Line Interface (CLI), que possibilita a interação do usuário com o servidor via terminal de comando. O link abaixo é um tutorial de como instalar o Heroku CLI para Mac, Windows ou Linux:
No terminal, execute o script abaixo uma linha por vez:
Hora da Verdade
Uma aba do navegador deverá ter sido aberta e o endereço deverá ter um sufixo herokuapp.com. É comum que a janela demore alguns minutos para carregar pois o primeiro acesso é mais demorado que os próximos.
Caso a página aberta seja parecida com esta página, parabéns, você conseguiu colocar o projeto no ar usando o Docker!
Caso, infelizmente, este não seja o caso, não se aborreça. Gaste mais alguns minutos lendo o FAQ ao final do artigo. Quem sabe seu problema não é resolvido?
Conclusão
Este artigo introduziu o Docker e alguns de seus conceitos principais, como imagem, container e criação em camadas, além de disponibilizar um guia prático contendo o passo-a-passo de como usá-lo.
É importante ressaltar, contudo, que o deployment é apenas uma das utilidades do Docker. Aproveite o conhecimento adquirido e descubra as possibilidades que essa tecnologia pode proporcionar.
Vai lá, explore esse mundão e aprenda coisas novas! E, se possível, depois volte para nos contar o que você descobriu.
Disclaimer: a partir de 1/11/2020 o Docker mudou sua política de uso e anunciou um limite na quantidade de importações que uma conta gratuita pode fazer:
“Free accounts are limited to 200 pulls per 6 hour period.”
FAQ
Como eu crio um arquivo sem extensão (i.e. Dockerfile)?
Tanto em uma máquina Linux quanto em um Mac, basta renomear o arquivo sem extensão e salvá-lo.
No Windows, entretanto, essa tarefa não é óbvia, pois arquivos sem extensão são automaticamente atribuídos como .txt. A solução é colocar o nome do arquivo entre aspas, ou seja, “Dockerfile”.
Qual é a diferença entre usar o Docker e o GitHub para colocar um projeto no ar com o Heroku?
As duas estratégias para o deployment diferem em relação aos arquivos necessários, grau de complexidade e limitações.
Enquanto o deployment com o Docker requer o arquivo Dockerfile para a criação da imagem, o GitHub requer o arquivo Procfile.
Embora o uso do GitHub possa ser considerado mais simples, dado que não é necessário usar o terminal de comando, ele é limitado, dado que é possível fazer o deployment apenas de repositórios próprios. O uso do Docker, em contrapartida, requer o uso do terminal (via Heroku CLI) porém pode ser aplicado em qualquer imagem.
Observação: o Heroku permite até 6 maneiras diferentes para colocar um projeto no ar.
Como deletar uma imagem criada por engano?
Primeiro é necessário listas as imagens existentes com docker image ls
e depois executar o comando docker rmi -f [ID IMAGEM]
.
Dica: não é necessário escrever o ID completo, mas apenas os caracteres suficientes para identificar a imagem a ser deletada. Nesse exemplo apenas os 4 primeiros caracteres foram suficientes para identificar o ID.
O navegador retornou a mensagem de erro abaixo. O que fazer?
Apesar da mensagem padrão de erro do Heroku sugerir executar o comando heroku logs --tail
para encontrar o erro, essa abordagem pode não ser a mais eficiente. O problema de começar a análise pelo logs do Heroku é que os registros são relativamente complexos de se entender e indicam problemas vinculados ao Heroku. Isso significa que irregularidades ocorridas em passos anteriores, como por exemplo durante a criação do Dockerfile, podem passar despercebidas.
Portanto, a abordagem sugerida é rever o guia prático deste artigo, certificando-se que todos os passos e códigos foram corretamente executados.
Após conferir a correta criação da imagem pelo Docker é que vale a pena avaliar os logs do Heroku. Caso essa seja seu caso, o log contém linhas que identificam o erro ocorrido e sua categoria, como por a imagem abaixo. Com essa pista em mãos, o caminho é explorar o StackOverflow e/ou fóruns especializados.
Glossário
- Container: unidade operacional executável formado por todas as configurações necessárias para a execução de um aplicativo. O container é uma instância de uma imagens.
- Docker: tecnologia de compartimentalização baseada em container.
- Docker Hub: repositório de imagens, semelhante ao Git Hub.
- Dockerfile: lista de comandos a serem tomados pelo Docker durante a criação de uma imagem.
- Imagem: unidade operacional não executável que concentra os arquivos necessários para a execução de um aplicativo. É o “diagrama” dos containers.
- Máquina virtual: unidades operacional que emula uma máquina de forma independente da máquina física. Ela permite executar programas próprios de sistemas operacionais diferentes ou mesmo isolar uma aplicação do resto do sistema.
- Streamlit: biblioteca open source de desenvolvimento de aplicativos web.