Tutorial

Como compilar e implantar um aplicativo Flask usando o Docker no Ubuntu 18.04

Published on January 9, 2020
Português
Como compilar e implantar um aplicativo Flask usando o Docker no Ubuntu 18.04

O autor selecionou a Tech Education Fund para receber uma doação como parte do programa Write for DOnations.

Introdução

O Docker é um aplicativo de código aberto que permite que os administradores criem, gerenciem, implantem e repliquem aplicativos usando contêineres. Os contêineres podem ser considerados como um pacote que abriga dependências que um aplicativo precisa para executar no nível do sistema operacional. Isso significa que cada aplicativo implantado usando o Docker vive em um ambiente próprio e seus requisitos são tratados separadamente.

O Flask é um microframework Web que é construído em Python. Ele é chamado de microframework porque não precisa de ferramentas específicas ou plugins para funcionar. O framework Flask é leve e flexível e, ainda sim, altamente estruturado, tornando-o preferido em relação a outros frameworks.

Implantar um aplicativo Flask com o Docker permitirá que você replique o aplicativo em diferentes servidores com uma reconfiguração mínima.

Neste tutorial, você criará um aplicativo Flask e irá implantá-lo com o Docker. Este tutorial também irá tratar sobre como atualizar um aplicativo após a implantação.

Pré-requisitos

Para seguir este tutorial, você precisará do seguinte:

Passo 1 — Configurando o aplicativo Flask

Para começar, você criará uma estrutura de diretórios que irá reter seu aplicativo Flask. Neste tutorial será criado um diretório chamado TestApp em /var/www, mas é possível modificar o comando para nomeá-lo como quiser.

  1. sudo mkdir /var/www/TestApp

Vá até o diretório TestApp recém-criado:

  1. cd /var/www/TestApp

Em seguida, crie a estrutura base da pasta para o aplicativo Flask:

  1. sudo mkdir -p app/static app/templates

A sinalização -p indica que o mkdir criará um diretório e todos os diretórios pais que não existam. Neste caso, o mkdir criará o diretório pai app enquanto cria os diretórios static e templates.

O diretório app abrigará todos os arquivos relacionados ao aplicativo Flask como suas visualizações e blueprints (planos gráficos). As visualizações são o código que você escreve para responder aos pedidos para seu aplicativo. Os Blueprints criam componentes do aplicativo e oferecem suporte aos padrões comuns dentro de um aplicativo ou de vários aplicativos.

O diretório static é onde estão os ativos como imagens, CSS e arquivos JavaScript. O diretório templates é onde você irá colocar os modelos HTML do seu projeto.

Agora que a estrutura base de pasta está completa, crie os arquivos necessários para executar o aplicativo Flask. Primeiro, crie um arquivo __init__.py dentro do diretório app. Esse arquivo informa o programa interpretador do Python que o diretório app é um pacote e deve ser tratado como tal.

Execute o comando a seguir para criar o arquivo:

  1. sudo nano app/__init__.py

Os pacotes no Python permitem que você agrupe os módulos em namespaces ou hierarquisas lógicos. Esta abordagem permite que o código seja dividido em blocos individuais e gerenciáveis que desempenham funções específicas.

Em seguida, adicione código ao __init__.py que criará uma instância de Flask e importará a lógica do arquivo views.py, que você criará após salvar este arquivo. Adicione o código a seguir ao seu novo arquivo:

/var/www/TestApp/__init__.py
from flask import Flask
app = Flask(__name__)
from app import views

Uma vez adicionado tal código, salve e feche o arquivo.

Com o arquivo __init__.py criado, está tudo pronto para criar o arquivo views.py no diretório app. Este arquivo conterá a maior parte da lógica do seu aplicativo.

  1. sudo nano app/views.py

Em seguida, adicione o código ao seu arquivo views.py. Esse código retornará a string hello world! para os usuários que visitarem sua Web page:

/var/www/TestApp/app/views.py
from app import app

@app.route('/')
def home():
   return "hello world!"

A linha @app.route acima da função é chamada de decorador. Os decoradores modificam a função que as segue. Neste caso, os decoradores avisam ao Flask qual URL irá desencadear a função home(). O texto hello world retornado pela função home será exibido para o usuário no navegador.

Com o arquivo views.py funcionando, estamos prontos para criar o arquivo uwsgi.ini. O arquivo terá as configurações uWSGI para o nosso aplicativo. A uWSGI é uma opção de implantação do Nginx que é um protocolo e um servidor do aplicativo ao mesmo tempo; o servidor do aplicativo pode atender os protocolos uWSGI, FastCGI e HTTP.

Para criar esse arquivo, execute o seguinte comando:

  1. sudo nano uwsgi.ini

Em seguida, adicione o conteúdo seguinte ao seu arquivo para, assim, configurar o servidor do uWSGI:

/var/www/TestApp/uwsgi.ini
[uwsgi]
module = main
callable = app
master = true

Este código define o módulo que irá servir o aplicativo Flask. Neste caso, trata-se do arquivo main.py, referenciado aqui como main. A opção callable manda o uWSGI usar a instância app exportada pelo aplicativo principal. A opção master permite que seu aplicativo permaneça funcionando, de modo a reduzir o tempo de paralisação ao recarregar o aplicativo inteiro.

Em seguida, crie o arquivo main.py, que é o ponto de entrada para o aplicativo. O ponto de entrada diz ao uWSGI como interagir com o aplicativo.

  1. sudo nano main.py

Em seguida, copie e cole o seguinte no arquivo. Este código irá importar a instância Flask chamada app do pacote do aplicativo que foi criado anteriormente.

/var/www/TestApp/main.py
from app import app

Por fim, crie um arquivo requirements.txt para especificar as dependências que o gerenciador de pacotes pip instalará para sua implantação do Docker:

  1. sudo nano requirements.txt

Adicione a seguinte linha para adicionar o Flask como uma dependência:

/var/www/TestApp/app/requirements.txt
Flask==1.0.2

Isso especifica a versão do Flask a ser instalada. No momento em que este tutorial está sendo escrito, a versão 1.0.2 é a versão do Flask mais recente. Você pode verificar as atualizações no site oficial do Flask.

Salve e feche o arquivo. Você configurou o aplicativo Flask com sucesso e está pronto para configurar o Docker.

Passo 2 — Configurando o Docker

Neste passo, serão criados dois arquivos, o Dockerfile e o start.sh, para criar sua implantação do Docker. O Dockerfile é um documento de texto que contém os comandos usados para montar a imagem. O arquivo start.sh é um script shell que irá construir uma imagem e criará um contêiner do Dockerfile.

Primeiramente, crie o Dockerfile.

  1. sudo nano Dockerfile

Em seguida, adicione a configuração desejada ao Dockerfile. Estes comandos especificam como a imagem será construída e quais requisitos extras serão incluídos.

/var/www/TestApp/Dockerfile
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt

Neste exemplo, a imagem do Docker será construída a partir de uma imagem existente, a tiangolo/uwsgi-nginx-flask, que pode ser encontrada no DockerHub. Esta imagem do Docker em particular é uma boa escolha dentre as outras pois ela oferece suporte a uma ampla gama de versões do Python e imagens de SO.

As duas primeiras linhas especificam a imagem pai que será usada para executar o aplicativo e instalar o processador de comando bash, assim como o editor de texto nano. O aplicativo também irá instalar o cliente git para extração e envio para as plataformas de hospedagem com controle de versão tais como GitHub, GitLab e Bitbucket. A ENV STATIC_URL/static é uma variável de ambiente específica para essa imagem do Docker. Ela define a pasta estática onde todos os ativos como imagens, arquivos CSS e arquivos JavaScript são atendidos.

As duas últimas linhas irão copiar o arquivo requirements.txt para o contêiner, de modo a que ele possa ser executado e, em seguida, analisar o arquivo requirements.txt para instalar as dependências especificadas.

Salve e feche o arquivo após adicionar sua configuração.

Com seu Dockerfile funcionando, está quase tudo pronto para escrever seu script start.sh que construirá o contêiner do Docker. Antes de escrever o script start.sh, certifique-se primeiro de que você tenha uma porta aberta para usar na configuração. Para verificar se uma porta está livre, execute o seguinte comando:

  1. sudo nc localhost 56733 < /dev/null; echo $?

Se o resultado do comando acima for 1, então a porta está livre e pode ser usada. Caso contrário, será necessário escolher uma porta diferente para usar no seu arquivo de configuração start.sh.

Assim que você tiver encontrado uma porta aberta para usar, crie o script start.sh:

  1. sudo nano start.sh

O script start.sh é um script shell que irá construir uma imagem do Dockerfile e criar um contêiner a partir da imagem do Docker resultante. Adicione sua configuração ao novo arquivo:

/var/www/TestApp/start.sh
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
  --name=${app} \
  -v $PWD:/app ${app}

A primeira linha é chamada de shebang. Ela especifica que este é um arquivo bash e ele será executado como comando. A linha seguinte especifica o nome que você quer dar à imagem e ao contêiner e salva o arquivo como uma variável chamada app. A próxima linha de comando manda o Docker construir uma imagem a partir do seu Dockerfile, localizado no diretório atual. Neste exemplo, a linha de código criará uma imagem chamada docker.test.

As três últimas linhas criam um novo contêiner chamado docker.test que está exposto na porta 56733. Por fim, ele vincula o diretório atual ao diretório /var/www do contêiner.

Você usará o sinalizador -d para iniciar um contêiner no modo daemon ou para iniciar como um processo em segundo plano. Incluirá o sinalizador -p para vincular uma porta no servidor a uma porta em particular no contêiner do Docker. Neste caso, você está ligando a porta 56733 à porta 80 no contêiner do Docker. O sinalizador -v especifica um volume do Docker para ser montado no contêiner e, neste caso, você estará montando o diretório de projeto inteiro na pasta /var/www no contêiner do Docker.

Execute o script start.sh para criar a imagem do Docker e construir um contêiner a partir da imagem resultante:

  1. sudo bash start.sh

Assim que o script terminar de executar, use o comando a seguir para listar todos os contêineres em execução:

  1. sudo docker ps

Você receberá um resultado que mostra os contêineres:

Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test

Você verá que o contêiner docker.test está em execução. Agora que ele está em execução, acesse o endereço IP na porta especificada no seu navegador: http://ip-address:56733

Você verá uma página parecida com a que segue:

A página principal

Neste passo, seu aplicativo Flask foi implementado no Docker com sucesso. Em seguida, você usará modelos para mostrar o conteúdo aos usuários.

Passo 3 — Servindo arquivos de modelos

Os modelos são arquivos que mostram o conteúdo estático e dinâmico aos usuários que visitam seu aplicativo. Neste passo, você criará um modelo HTML para criar uma página inicial para o aplicativo.

Comece criando um arquivo home.html no diretório app/template:

  1. sudo nano app/templates/home.html

Adicione o código ao seu template. Este código irá criar uma página HTML5 que contém um título e algum texto nele.

/var/www/TestApp/app/templates/home.html

<!doctype html>

<html lang="en-us">   
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Welcome home</title>
  </head>
  
  <body>
    <h1>Home Page</h1>
    <p>This is the home page of our application.</p>
  </body> 
</html>

Salve e feche o arquivo assim que tiver adicionado o seu modelo.

Em seguida, modifique o arquivo app/views.py para atender o arquivo recém-criado:

  1. sudo nano app/views.py

Primeiramente, adicione a seguinte linha no início do seu arquivo para importar o método render_template do Flask. Este método analisa um arquivo HTML para renderizar uma página da Web para o usuário.

/var/www/TestApp/app/views.py
from flask import render_template
...

No final do arquivo, você também irá adicionar uma nova rota para renderizar o arquivo do modelo. Este código especifica que os usuários recebem o conteúdo do arquivo home.html sempre que visitam a rota /template em seu aplicativo.

/var/www/TestApp/app/views.py
...

@app.route('/template')
def template():
    return render_template('home.html')

O arquivo atualizado app/views.py se parecerá com isto:

/var/www/TestApp/app/views.py
from flask import render_template
from app import app 

@app.route('/')
def home():
    return "Hello world!"

@app.route('/template')
def template():
    return render_template('home.html')

Salve e feche o arquivo quando terminar.

Para que estas alterações passar a vigorar, será necessário parar e reiniciar os contêineres do Docker. Execute o comando a seguir para criar o contêiner novamente:

  1. sudo docker stop docker.test && sudo docker start docker.test

Visite seu aplicativo em http://your-ip-address:56733/template para ver o novo modelo sendo mostrado.

homepage

Neste passo, você criou um arquivo modelo do Docker para atender os visitantes em seu aplicativo. No próximo passo, você verá como as alterações que você faz em seu aplicativo podem entrar em vigor sem a necessidade de reiniciar o contêiner do Docker.

Passo 4 — Atualizando o aplicativo

Às vezes, você terá que fazer alterações no aplicativo, seja instalando novos requisitos, atualizando o contêiner do Docker ou do HTML e as alterações de lógica. Nesta seção, você irá configurar o touch-reload para fazer essas alterações sem precisar reiniciar o contêiner do Docker.

O autoreloading do Python monitora todo o sistema de arquivos quanto a alterações e atualiza o aplicativo quando detecta uma mudança. Desencorajamos o uso do autoreloading em produção porque ele pode se tornar um recurso intensivo rapidamente. Neste passo, você usará o touch-reload para monitorar as alterações em um arquivo em particular e recarregar quando o arquivo for atualizado ou substituído.

Para implementar isso, abra seu arquivo uwsgi.ini:

  1. sudo nano uwsgi.ini

Em seguida, adicione a linha destacada ao final do arquivo:

/var/www/TestApp/uwsgi.ini
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini

Ela especifica um arquivo que será modificado para desencadear o recarregamento de um aplicativo inteiro. Uma vez feitas as mudanças, salve e feche o arquivo.

Como uma demonstração, faça uma pequena alteração no seu aplicativo. Comece abrindo seu arquivo app/views.py:

  1. sudo nano app/views.py

Substitua a string retornada pela função home:

/var/www/TestApp/app/views.py
from flask import render_template
from app import app

@app.route('/')
def home():
    return "<b>There has been a change</b>"

@app.route('/template')
def template():
    return render_template('home.html')

Salve e feche o arquivo após fazer uma mudança.

Em seguida, se abrir a página inicial do seu aplicativo em http://ip-address:56733, você verá que as mudanças não estão refletidas. Isso acontece porque a condição para que o recarregamento ocorra é uma alteração feita ao arquivo uwsgi.ini. Para recarregar o aplicativo,utilize a opção touch para ativar a condição:

  1. sudo touch uwsgi.ini

Recarregue a homepage do aplicativo em seu navegador novamente. Você verá que o aplicativo incorporou as mudanças:

Pagina inicial atualizada

Neste passo, você configurou uma condição touch-reload para atualizar seu aplicativo após fazer alterações.

Conclusão

Neste tutorial, você criou e implantou um aplicativo Flask em um contêiner do Docker. Você também configurou o touch-reload para atualizar seu aplicativo sem a necessidade de reiniciar o contêiner.

Com o seu novo aplicativo em Docker, agora é possível dimensionar com facilidade. Para aprender mais sobre como usar o Docker, verifique sua documentação oficial.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more