Tempo de execução do Python

Visão geral

O ambiente de execução do Python é a pilha de software responsável por instalar o código do aplicativo e as respectivas dependências, além de executar o aplicativo. O ambiente de execução padrão é declarado em app.yaml como runtime: python:

runtime: python
env: flex

No ambiente flexível, os tempos de execução são criados usando o Docker. O ambiente de execução do Python é baseado no Ubuntu 16.04. O código-fonte para o ambiente de execução do Python está disponível publicamente no GitHub.

Intérprete

O interpretador padrão é o Python 2.7.9 (em inglês). É possível especificar o uso do Python 2 ou do Python 3 no app.yaml do aplicativo com a configuração runtime_config:

runtime: python
env: flex

runtime_config:
    python_version: 3

As seguintes versões do interpretador são compatíveis:

  • Python 2.7.9, conforme especificado por 2.
  • Python 3.7.2, conforme especificado por 3.

Dependências

O ambiente de execução procura um arquivo requirements.txt no diretório de origem do aplicativo e usa o pip (ambos em inglês) para instalar as dependências antes de iniciar o aplicativo. Para mais informações sobre como declarar e gerenciar pacotes, consulte Como usar bibliotecas do Python.

Como usar bibliotecas C com Python

Para permitir o uso de pacotes Python que precisam de extensões C, os cabeçalhos da versão atual do Python e os pacotes Ubuntu a seguir são pré-instalados no sistema:

Com esses pacotes, é possível instalar as bibliotecas mais usadas do Python. Se o aplicativo exigir mais dependências no nível do sistema operacional, use um tempo de execução personalizado baseado no tempo de execução necessário para instalar os pacotes adequados.

Inicialização do aplicativo

O ambiente de execução inicia seu aplicativo usando o entrypoint definido em app.yaml. O entrypoint deve iniciar um processo que responde a solicitações HTTP na porta definida pela variável de ambiente PORT.

A maioria dos aplicativos da Web usa um servidor WSGI, como Gunicorn, uWSGI ou Waitress (todos em inglês).

Antes de poder usar um desses servidores, é preciso incluí-los como uma dependência no requirements.txt do aplicativo. O tempo de execução assegura que todas as dependências sejam instaladas antes de chamar o entrypoint.

Flask==0.10.1
gunicorn==19.3.0

Veja um exemplo de entrypoint usando Gunicorn para um aplicativo Flask:

entrypoint: gunicorn -b :$PORT main:app

Veja um exemplo de entrypoint usando Gunicorn para um aplicativo Django:

entrypoint: gunicorn -b :$PORT mydjangoapp:wsgi

O Gunicorn é o servidor WSGI recomendado, mas é possível usar qualquer outro servidor WSGI. Por exemplo, este é um entrypoint que usa o uWSGI com o Flask:

entrypoint: uwsgi --http :$PORT --wsgi-file main.py --callable app

No caso de aplicativos que podem processar solicitações sem um servidor WSGI, você pode simplesmente executar um script python:

entrypoint: python main.py

Os exemplos básicos de entrypoint mostrados acima são destinados a ser pontos de partida e podem funcionar com seus aplicativos da Web. No entanto, a maioria dos aplicativos precisará configurar melhor o servidor WSGI. Em vez de especificar todas as configurações no entrypoint, crie um arquivo gunicorn.conf.py no diretório raiz do projeto, onde o app.yaml está localizado, e especifique-o no seu entrypoint:

entrypoint: gunicorn -c gunicorn.conf.py -b :$PORT main:app

Você pode ler sobre todos os valores de configuração do Gunicorn na documentação.

Workers

O Gunicorn usa workers para processar pedidos. Por padrão, o Gunicorn usa workers de sincronização. Essa classe de worker é compatível com todos os aplicativos da Web, mas cada um pode processar apenas uma solicitação por vez. Por padrão, o Gunicorn usa apenas um desses workers. Isso geralmente faz com que suas instâncias sejam subutilizadas e aumentem a latência em aplicativos com carga alta.

Recomendamos configurar o número de workers em duas a quatro vezes o número de núcleos de CPU da sua instância mais um. Você pode especificar isso em gunicorn.conf.py como:

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1

Além disso, alguns aplicativos da Web que são vinculados principalmente a E/S podem apresentar uma melhoria de desempenho usando uma classe de worker diferente. Se sua classe de trabalhadores exigir mais dependências, como gevent ou tornado, essas dependências precisarão ser declaradas no arquivo requirements.txt do aplicativo.

HTTPS e proxies de encaminhamento

O App Engine encerra a conexão HTTPS no balanceador de carga e encaminha a solicitação ao aplicativo. A maioria dos aplicativos não precisa saber se a solicitação foi enviada por HTTPS ou não, mas os aplicativos que precisam dessas informações devem configurar o Gunicorn para aceitar o proxy do Google App Engine em gunicorn.conf.py:

forwarded_allow_ips = '*'
secure_scheme_headers = {'X-FORWARDED-PROTO': 'https'}

Agora o Gunicorn garantirá que o wsgi.url_scheme para 'https', que a maioria dos frameworks da Web usará como indicação da solicitação, seja seguro. Se seu servidor ou framework WSGI não for compatível com isso, basta verificar manualmente o valor do cabeçalho X-Forwarded-Proto.

Alguns aplicativos também precisam averiguar o endereço IP do usuário. Isso está disponível no cabeçalho X-Forwarded-For.

Observe que a configuração secure_scheme_headers em gunicorn.conf.py precisa ser em letras maiúsculas, como X-FORWARDED-PROTO, mas os cabeçalhos que seu código pode ler serão em letras maiúsculas e minúsculas, por exemplo, X-Forwarded-Proto.

Como ampliar o tempo de execução

O tempo de execução padrão do Python pode ser usado para criar um tempo de execução personalizado. Os ambientes de execução personalizados são configurados por meio de Dockerfiles. É possível gerar um Dockerfile baseado no ambiente de execução padrão do Python usando gen-config:

gcloud beta app gen-config --custom

Personalize Dockerfile e .dockerignore como quiser. Finalmente, você precisará especificar runtime: custom em vez de runtime: python em app.yaml. Consulte Customizing the Python Runtime (em inglês) para ver mais informações.

Variáveis de ambiente

As variáveis de ambiente a seguir são definidas pelo ambiente de execução:

Variável de ambiente Descrição
GAE_INSTANCE O nome da instância atual.
GAE_MEMORY_MB A quantidade de memória disponível para o processo do aplicativo.
GAE_SERVICE O nome do serviço especificado no arquivo app.yaml do aplicativo. Se nenhum nome de serviço for especificado, será definido como default.
GAE_VERSION O rótulo da versão do aplicativo atual.
GOOGLE_CLOUD_PROJECT O ID do projeto associado ao seu aplicativo, que fica visível no Console do Google Cloud
PORT A porta que receberá as solicitações HTTP.

Para definir variáveis extras de ambiente, use app.yaml.

Servidor de metadados

Cada instância do aplicativo pode usar o servidor de metadados do Compute Engine para consultar informações sobre a instância, incluindo o nome do host, o endereço IP externo, o ID da instância, metadados personalizados e informações sobre a conta do serviço. Não é possível definir metadados personalizados para cada instância no App Engine. Em vez disso, defina metadados personalizados para o projeto e leia esses metadados a partir das instâncias do Engine e do Compute Engine.

A função de exemplo abaixo usa o servidor de metadados para receber o endereço IP externo da instância:

METADATA_NETWORK_INTERFACE_URL = \
    ('http://metadata/computeMetadata/v1/instance/network-interfaces/0/'
     'access-configs/0/external-ip')

def get_external_ip():
    """Gets the instance's external IP address from the Compute Engine metadata
    server. If the metadata server is unavailable, it assumes that the
    application is running locally.
    """
    try:
        r = requests.get(
            METADATA_NETWORK_INTERFACE_URL,
            headers={'Metadata-Flavor': 'Google'},
            timeout=2)
        return r.text
    except requests.RequestException:
        logging.info('Metadata server could not be reached, assuming local.')
        return 'localhost'