Módulo 1: Migrar do webapp2 do App Engine para o Flask

Esta série de codelabs (tutoriais práticos e autoguiados) destina-se a ajudar os desenvolvedores do Google App Engine (Padrão) a modernizar os aplicativos por meio de uma série de migrações. A etapa mais significativa é deixar de usar os serviços originais de pacote em tempo de execução porque os ambientes de execução de última geração são mais flexíveis, oferecendo aos usuários uma variedade maior de opções de serviços. A migração para o ambiente de execução de geração mais recente permite uma integração com os produtos do Google Cloud mais facilmente, usa uma variedade maior de serviços compatíveis e oferece suporte às versões de linguagem atuais.

Veja neste tutorial inicial as primeiras etapas de migração para modernizar a estrutura da Web em aplicativos do App Engine: como mudar de webapp2 para Flask. No seu aplicativo, você pode usar qualquer framework da Web que processe o roteamento. No entanto, neste tutorial, usamos o Flask porque ele é amplamente usado pela comunidade.

Você aprenderá como realizar as seguintes tarefas:

  • Usar bibliotecas de terceiros (incorporadas ou não)
  • Atualizar os arquivos de configuração
  • Migre um app simples de webapp2 para o Flask

Pré-requisitos

Pesquisa

Como você usará este codelab?

Apenas leitura Leitura e exercícios

A biblioteca webapp foi empacotada quando o App Engine foi lançado no Python 2.5 em 2008. Anos depois, foi substituído pelo sucessor webapp2 quando o ambiente de execução 2.7 foi descontinuado, em 2013.

Embora webapp2 (consulte documentos) ainda existe e possa ser usado fora do App Engine como um framework da Web compatível com WSGI, ele não faz seu roteamento de solicitações de usuários para o código apropriado no aplicativo. Em vez disso, ele conta com o App Engine, arquivos de configuração e o desenvolvedor para executar esse roteamento do tráfego da Web para os "gerenciadores" correspondentes. Além disso, os principais benefícios do webapp2 estão intrinsecamente vinculados aos serviços em pacote do Google App Engine, suspendendo-o embora, mesmo se funcionar em Python 3 (veja também problema relacionado).

Este módulo oferece uma experiência prática para a migração de um aplicativo webapp2 simples para o Flask, um framework compatível com o App Engine e muitos outros serviços fora do Google Cloud, tornando os apps muito mais portáteis. Se o Flask não for um framework desejado para mover seu aplicativo, selecione outro, desde que ele faça o próprio roteamento. Este codelab mostra os tomadores de decisões de tecnologia da informação (ITDMs, na sigla em inglês) e os desenvolvedores as etapas de migração para que você possa se familiarizar com esse processo, independentemente da biblioteca na qual você está migrando.

Estas são as principais etapas para essa migração:

  1. Configuração/Pré-trabalho
  2. Adicionar biblioteca de terceiros do Flask
  3. Atualizar arquivos do aplicativo
  4. Atualizar arquivo do modelo HTML

Antes de continuarmos a parte principal do tutorial, vamos configurar o projeto, receber o código e, em seguida, (conhecer) o comando gcloud e implantar o app de referência para sabermos que começamos a trabalhar com o código de trabalho.

1. Configurar projeto

Como desenvolvedor atual, seu painel do App Engine provavelmente já mostra quais serviços você está executando. Para este tutorial, recomendamos que você crie um novo projeto ou reutilize um existente para este tutorial. Verifique se o projeto tem uma conta de faturamento ativa e o App Engine (aplicativo) está ativado.

2. Fazer o download do app de amostra de linha de base

O repositório de migração do GAE tem todo o código necessário. Clone ou faça o download do arquivo ZIP. Para este tutorial, comece com o código na pasta Módulo 0 (START). Quando você concluir o tutorial, o código deverá corresponder à pasta do Module 1 (FINISH). Caso contrário, confira as diferenças para avançar para o próximo laboratório.

A pasta Módulo 0 deve ter arquivos como este, conforme ilustrado com o comando POSIX ls:

$ ls
app.yaml        index.html      main.py

3. (Re)Familiarize-se com os comandos gcloud

Se você ainda não tiver o comando gcloud na sua máquina, instale o SDK do Google Cloud e verifique se gcloud está disponível como parte do seu caminho de execução e se familiarize com os seguintes gcloud:

  1. gcloud components update atualizar o SDK do Google Cloud
  2. gcloud auth login faça login na sua conta credenciada
  3. gcloud config list lista as definições de configuração do projeto do GCP.
  4. gcloud config set project PROJECT_ID definir o ID do projeto do GCP
  5. gcloud app deploy Implante seu aplicativo do App Engine

Se você não tem desenvolvimento recente do App Engine com gcloud, execute os primeiros quatro comandos (no 1 a 4) para fazer a configuração antes de passar para as próximas etapas. Vamos fazer uma rápida visão geral desses comandos.

Primeiro, gcloud components update garante que você tenha a versão mais recente do SDK do Cloud. A execução desse comando resultará em uma resposta semelhante a esta:

$ gcloud components update

Your current Cloud SDK version is: 317.0.0
You will be upgraded to version: 318.0.0

┌──────────────────────────────────────────────────┐
│        These components will be updated.         │
├──────────────────────────┬────────────┬──────────┤
│           Name           │  Version   │   Size   │
├──────────────────────────┼────────────┼──────────┤
│ Cloud SDK Core Libraries │ 2020.11.06 │ 15.5 MiB │
│ gcloud cli dependencies  │ 2020.11.06 │ 10.6 MiB │
└──────────────────────────┴────────────┴──────────┘

The following release notes are new in this upgrade.
Please read carefully for information about new features, breaking changes,
and bugs fixed.  The latest full release notes can be viewed at:
  https://cloud.google.com/sdk/release_notes

318.0.0 (2020-11-10)

      . . .
      (release notes)
      . . .

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce.

Do you want to continue (Y/n)?

╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area                             ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Cloud SDK Core Libraries                   ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: gcloud cli dependencies                    ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud SDK Core Libraries                     ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: gcloud cli dependencies                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation          ═╣
╚════════════════════════════════════════════════════════════╝

Performing post processing steps...done.

Update done!

To revert your SDK to the previously installed version, you may run:
  $ gcloud components update --version 317.0.0

Em seguida, use gcloud auth login para autenticar-se nos comandos gcloud que você emitirá de novo no futuro:

$ gcloud auth login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id= . . .

You are now logged in as [YOUR_EMAIL].
Your current project is [PROJECT_ID].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

Use gcloud config list para ver quais são suas configurações de projeto atuais:

$ gcloud config list
[core]
account = YOUR_EMAIL
disable_usage_reporting = False
project = PROJECT_ID

Your active configuration is: [default]

O comando acima deve guiar você na criação de um novo projeto ou na seleção de um já existente. Se a saída de gcloud config list não corresponder ao projeto selecionado que você pretende usar neste tutorial, execute gcloud config set project PROJECT_ID para definir o ID do projeto. Em seguida, confirme se o ID do projeto correto está definido ao executar gcloud config list novamente.

$ gcloud config set project PROJECT_ID
Updated property [core/project].

Se preferir usar o Console do Cloud, siga a interface do usuário para criar um novo projeto, se preferir, ou use qualquer projeto que você já tem. No painel do projeto, você verá o cartão de informações do projeto, que mostra o código dele, junto com o nome e o número do projeto:

Card de informações do projeto

O último comando (#5), gcloud app deploy é para implantar seu aplicativo no App Engine. Como estamos apenas começando, a execução agora é opcional, mas definitivamente não desestimule a implantação do código do Módulo 0 para confirmar se funciona. Após a execução, selecione a região geográfica em que o aplicativo será executado (normalmente na sua localização). No entanto, ele não pode ser alterado depois de definido. Em seguida, assista ao restante das informações de implantação. Quando ele for concluído, você será notificado do URL em que seu aplicativo será veiculado. Veja a seguir uma versão resumida do que poderá ser exibido:

$ gcloud app deploy
Services to deploy:

descriptor:      [/private/tmp/mod0-baseline/app.yaml]
source:          [/private/tmp/mod0-baseline]
target project:  [PROJECT_ID]
target service:  [default]
target version:  [20201116t220827]
target url:      [https://PROJECT_ID.REG_ABBR.r.appspot.com]

Do you want to continue (Y/n)?

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://PROJECT_ID.REG_ABBR.r.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

Se você não usar o App Engine há algum tempo, perceberá que a implantação original comando appcfg.py update foi substituído por gcloud app deploy. Para saber mais sobre o gcloud app deploy, acesse a página de documentação.

Outra alteração recente é o URL dos aplicativos implantados, ajustado de http://PROJECT_ID.appspot.com para http://PROJECT_ID.REG_ABBR.r.appspot.com. No futuro, a maioria dos apps será convertida para o novo formato. Veja mais informações sobre o formato de URL na documentação de solicitações e roteamento.

Depois que o app for implantado, atualize o navegador (possivelmente algumas) para ver as visitas mais recentes:

app visitme

Se o app for novo, você verá apenas algumas ou algumas visitas.

O ambiente de execução do Python 2 do App Engine fornece um conjunto de bibliotecas de terceiros integradas em que você só precisa especificá-las no seu arquivo app.yaml para usar. Embora essa migração não exija uso, ela estará no próximo tutorial de migração (para o Módulo 2).

Bibliotecas de terceiros que não são integradas em um arquivo chamado requirements.txt e são instaladas localmente na pasta lib do mesmo diretório do código do aplicativo para onde é feito upload de tudo para o App Engine. Veja mais informações na documentação para agrupar bibliotecas de terceiros.

Bibliotecas copiadas como Flask exigem que você solicite que o App Engine procure-as na pasta lib usando o arquivo de configuração appengine_config.py. O arquivo de configuração appengine_config.py é colocado na mesma pasta de aplicativo de nível superior que requirements.txt e lib. Nesta parte do tutorial, você irá:

  • Criar requirements.txt (especifique as bibliotecas de terceiros [não integradas])
  • Criar appengine_config.py (reconhecer bibliotecas de terceiros)
  • Instalar pacotes e dependências de terceiros

1. Criar requirements.txt

Crie um arquivo requirements.txt para especificar os pacotes. No nosso caso, o Flask é a biblioteca de terceiros necessária. No momento da redação deste artigo, a versão mais recente era 1.1.2. Portanto, crie requirements.txt com esta linha:

Flask==1.1.2

Consulte a documentação requirements.txt para saber mais sobre os formatos aceitos.

2. Criar appengine_config.py

A próxima etapa é fazer o App Engine reconhecer bibliotecas externas de terceiros. Crie um arquivo chamado appengine_config.py com o seguinte conteúdo:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Esse código faz exatamente o que foi especificado anteriormente, ou seja, direciona o App Engine para a pasta lib das bibliotecas copiadas.

3. Instalar pacotes e dependências

Agora, execute o comando pip install para criar a pasta lib e instale o Flask e as respectivas dependências:

$ pip install -t lib -r requirements.txt

Se você usou pip ou pip2, após a conclusão da instalação do pacote, precisará ter uma pasta lib que terá conteúdo semelhante a este:

$ ls lib
bin/
click/
click-7.1.2.dist-info/
flask/
Flask-1.1.2.dist-info/
itsdangerous/
itsdangerous-1.1.0.dist-info/
jinja2/
Jinja2-2.11.2.dist-info/
markupsafe/
MarkupSafe-1.1.1.dist-info/
werkzeug/
Werkzeug-1.0.1.dist-info/

Agora, vamos atualizar o arquivo do aplicativo, main.py.

1. Importações

As importações vêm primeiro em todos os arquivos Python. A importação do framework webapp2 é seguida pela biblioteca ndb do Datastore e, por fim, pela extensão do App Engine que processa modelos variados no Django. Você verá o seguinte:

  • Antes:
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

Ao mudar para o Flask, você importa as partes do Flask e do renderizador do modelo ao mesmo tempo. Exclua o par de importações relacionadas ao webapp2 e substitua-as da seguinte maneira (deixe a importação de ndb como está):

  • Depois:
from flask import Flask, render_template, request
from google.appengine.ext import ndb

2. Inicialização

Os aplicativos que usam webapp2 exigem uma única matriz (lista Python) que lista todas as rotas e manipuladores em qualquer arquivo Python (pode haver outros):

  • Antes:
app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

Lembre-se de que app.yaml executa um roteamento de nível superior e pode chamar gerenciadores diferentes. O aplicativo de amostra é simples o suficiente para que todas as rotas cheguem ao gerenciador main.py.

Como o Flask não usa tabelas de roteamento como essa, exclua essas linhas em main.py. O Flask também requer inicialização. Portanto, adicione a seguinte linha no top de main.py logo abaixo das importações:

  • Depois:
app = Flask(__name__)

No Flask, você inicializa o framework e usa decoradores para definir as rotas. Além disso, trajetos são pareados com funções, não classes ou métodos.

Está fora do escopo incluir um tutorial do Flask neste codelab. Portanto, dedique algum tempo trabalhando no tutorial do Flask e revise a documentação do Flask para se familiarizar com o framework.

3. Modelo de dados

Não há alterações aqui. O Datastore será o foco do próximo codelab.

4. Gerenciadores

O aplicativo, independentemente da biblioteca usada (webapp2 ou Flask), faz três coisas:

  1. Processar solicitações GET de caminho raiz (/)
  2. Registrar uma página da Web "visita" (criar/criar objeto Visit)
  3. Exibir as 10 visitas mais recentes (com um modelo predefinido, index.html)

O framework webapp2 usa um modelo de execução baseado em classe em que os gerenciadores são criados para cada método HTTP compatível. No nosso caso simples, temos apenas GET. Portanto, um método get() é definido:

  • Antes:
class MainHandler(webapp2.RequestHandler):
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10) or ()  # empty sequence if None
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

Como mencionado acima, o Flask faz o próprio roteamento. Em vez de uma classe de manipulador, você escreve funções e decora elas com a rota para a qual elas devem ser chamadas. Os usuários podem especificar métodos HTTP manipulados na chamada do decorador, ou seja, @app.route('/app/', methods=['GET', 'POST']) Como o padrão é apenas GET (e implicitamente HEAD), ele pode ser deixado de fora.

Ao migrar para o Flask, substitua a classe MainHandler e seu método get() pela seguinte função de roteamento do Flask:

  • Depois:
@app.route('/')
def root():
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10) or ()  # empty sequence if None
    return render_template('index.html', visits=visits)

Obviamente, isso não representa seu aplicativo, com certeza será mais complexo do que esse exemplo. Um dos principais objetivos destes tutoriais é ajudar você a começar, criar um pouco de "memória muscular" e entender onde fazer alterações no código específico do App Engine. Para confirmar se você fez essa alteração corretamente, compare a sua com o Módulo 1 main.py.

5. Arquivos auxiliares

Não há alterações no arquivo .gcloudignore. Sua finalidade é especificar arquivos que não devem ser implantados no App Engine que sejam desnecessários para implantar e executar o aplicativo, incluindo, entre outros, Python auxiliar, controle de origem, código-fonte e outros arquivos. Nossa .gcloudignore tem esta aparência (com comentários removidos para agilizar):

.gcloudignore
.git
.gitignore
.hgignore
.hg/
*.pyc
*.pyo
__pycache__/
/setup.cfg
README.md

1. Mover arquivo de modelo

Na pasta do repositório de referência (Módulo 0), o arquivo de modelo index.html está na mesma pasta dos arquivos do aplicativo. Como o Flask requer arquivos HTML colocados em uma pasta templates, você precisa criar essa pasta (mkdir templates) e mover index.html nela. Em um sistema compatível com POSIX, como Linux ou Mac OS X, os comandos seriam:

mkdir templates
mv index.html templates

2. Atualizar arquivo de modelo

Depois de mover index.html para templates, é hora de fazer uma edição pequena, mas obrigatória. Vamos analisar o arquivo de modelo original em sua totalidade:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

Enquanto webapp2 usa modelos Django que executam chamadas como visit.timestamp.ctime sem parênteses ( ), o Jinja2 os exige explicitamente. Embora pareça um pequeno ajuste, os modelos Jinja são mais eficientes e prontos para uso, já que é possível passar argumentos nas chamadas.

No Django, você precisa criar uma "tag de modelo" ou escrever um filtro. Com isso, atualize index.html adicionando um par de parênteses à chamada visit.timestamp.ctime:

  • Antes:
<li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
  • Depois:
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>

Essa é a única mudança necessária. Nenhuma alteração adicional para index.html é necessária para todos os codelabs de migração restantes.

Implante o aplicativo

Depois de concluir todas as alterações neste tutorial, os arquivos na pasta do aplicativo devem ser idênticos (ou quase) para o arquivo na pasta do repositório do módulo 1. Agora, implante e veja que o aplicativo Module 1 Flask é executado de forma idêntica à versão webapp2 do módulo 0.

Use o comando gcloud app deploy, como fizemos anteriormente ao implantar o código do módulo 0 original. Acesse o aplicativo em PROJECT_ID.appspot.com por meio de um navegador da Web ou de um comando curl ou wget para confirmar que ele funciona conforme o esperado.

Se ocorrer algum tipo de erro no servidor, isso normalmente significa algum tipo de erro de digitação no código do Python. Confira os registros do seu aplicativo para investigar. Compare também os arquivos com os do repositório do módulo 1 (link logo acima).

Opcional: limpar

E a limpeza para evitar cobrança até que você esteja pronto para passar para o próximo codelab de migração? Como você, os desenvolvedores já estão atualizados nas informações de preços do App Engine.

Opcional: desativar app

Se você ainda não estiver pronto para avançar para o próximo tutorial, desative seu app para evitar cobranças. Quando estiver pronto para passar para o próximo codelab, você poderá reativá-lo. Enquanto seu aplicativo estiver desativado, ele não receberá tráfego para custos. No entanto, o uso do Datastore pode ser cobrado se exceder a cota gratuita, Exclua o suficiente para ficar abaixo desse limite.

Por outro lado, se você não quiser continuar com as migrações e quiser excluir tudo completamente, poderá encerrar seu projeto.

Próximas etapas

Existem dois módulos de migração que o START com o código de módulo 1 concluído, os módulos 2 e 7:

  • Módulo 2 (obrigatório se você usar o Datastore)
    • Migrar do App Engine ndb para o Cloud NDB
    • Após a troca para o Cloud NDB, muitas outras opções estarão disponíveis
      • Como colocar seu aplicativo em contêiner para execução no Cloud Run
      • Migração adicional do seu aplicativo para a biblioteca de cliente do Cloud Datastore
      • Como migrar o app para o Cloud Firestore para acessar recursos do Firebase
  • Módulo 7 (obrigatório se você usar filas de tarefas [push]
    • Adicionar o uso de taskqueue do App Engine (push)
    • Prepara o aplicativo Módulo 1 para a migração para o Cloud Tasks no Módulo 8

Problemas/comentários do módulo de migração do App Engine

Se você encontrar problemas com este codelab, pesquise seu problema antes de preenchê-lo. Links para pesquisar e criar novos problemas:

Recursos de migração

Os links para as pastas do repositório do módulo 0 (START) e Módulo 1 (FINISH) podem ser encontrados na tabela abaixo. Elas também podem ser acessadas no repositório de todas as migrações do App Engine, que você pode clonar ou fazer o download de um arquivo ZIP.

Codelab

Python 2

Python 3

Module 0

código

(n/a)

Módulo 1

código

(n/a)

Recursos do App Engine

Veja abaixo mais recursos relacionados a essa migração específica: