Como executar o Django no ambiente do Cloud Run

A implantação de aplicativos com estado no Cloud Run, como o Django, envolve a integração de serviços para interagir entre si para formar um projeto coeso.

Neste tutorial, presume-se que você esteja familiarizado com o desenvolvimento de Web com o Django. Se você é novo no desenvolvimento do Django, é recomendável escrever seu primeiro aplicativo Django antes de continuar.

Embora este tutorial demonstre especificamente o Django, é possível usar esse processo de implantação com outros frameworks baseados em Django, como Wagtail e Django CMS.

Este tutorial usa o DMARC 4, que exige pelo menos o Python 3.8.

Objetivos

Com este tutorial, você vai:

  • Criar e conectar um banco de dados do Cloud SQL.
  • Criar e usar valores de secret do Secret Manager.
  • Implantar um app Django no Cloud Run.

  • Hospedar arquivos estáticos no Cloud Storage.

  • Usar o Cloud Build para automatizar a implantação.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Antes de começar

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. Verifique se as permissões suficientes estão disponíveis para a conta usada neste tutorial.

Preparar o ambiente

Clonar um aplicativo de exemplo

O código do aplicativo de amostra Django está no repositório GoogleCloudPlatform/python-docs-samples no GitHub.

  1. É possível fazer o download da amostra como um arquivo ZIP e extraí-lo ou clonar o repositório na máquina local:

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
    
  2. Acesse o diretório que contém o código de amostra:

    Linux/MacOS

    cd python-docs-samples/run/django
    

    Windows

    cd python-docs-samples\run\django
    

Confirmar a configuração do Python

Este tutorial depende do Python para executar o aplicativo de amostra na máquina. O exemplo de código também requer a instalação de dependências

Para mais detalhes, consulte o guia do ambiente de desenvolvimento em Python.

  1. Confirme se o Python contém a versão 3.7 ou posterior.

     python -V
    

    Você verá Python 3.7.3 ou superior.

  2. Crie um ambiente virtual do Python e instale as dependências:

    Linux/macOS

    python -m venv venv
    source venv/bin/activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

    Windows

    python -m venv env
    venv\scripts\activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

Faça o download do proxy do Cloud SQL Auth para se conectar ao Cloud SQL pela máquina local

Quando implantado, o aplicativo usa o proxy do Cloud SQL Auth integrado ao ambiente do Cloud Run para se comunicar com a instância do Cloud SQL. No entanto, para testar o aplicativo no local, é necessário instalar e usar uma cópia local do proxy no ambiente de desenvolvimento. Para mais detalhes, consulte o guia do proxy do Cloud SQL Auth.

O proxy do Cloud SQL Auth usa a API Cloud SQL para interagir com sua instância do SQL. Para fazer isso, ele quer a autenticação do aplicativo pelo gcloud.

  1. Autentique e receba as credenciais da API:

    gcloud auth application-default login
    
  2. Faça o download e instale o proxy do Cloud SQL Auth na sua máquina local.

    Linux de 64 bits

    1. Faça o download do proxy do Cloud SQL Auth:
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
    2. Torne o proxy do Cloud SQL Auth executável:
      chmod +x cloud_sql_proxy

    Linux de 32 bits

    1. Faça o download do proxy do Cloud SQL Auth:
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
    2. Se o comando wget não for encontrado, execute sudo apt-get install wget e repita o comando de download.
    3. Torne o proxy do Cloud SQL Auth executável:
      chmod +x cloud_sql_proxy

    macOS de 64 bits

    1. Faça o download do proxy do Cloud SQL Auth:
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
    2. Torne o proxy do Cloud SQL Auth executável:
      chmod +x cloud_sql_proxy

    macOS de 32 bits

    1. Faça o download do proxy do Cloud SQL Auth:
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
    2. Torne o proxy do Cloud SQL Auth executável:
      chmod +x cloud_sql_proxy

    Mac M1

    1. Faça o download do proxy do Cloud SQL Auth:
        curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.arm64
        
    2. Torne o proxy do Cloud SQL Auth executável:
        chmod +x cloud_sql_proxy
        

    Windows de 64 bits

    Clique com o botão direito do mouse em https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe e selecione Salvar link como para fazer o download do proxy do Cloud SQL Auth. Renomeie o arquivo para cloud_sql_proxy.exe.

    Windows de 32 bits

    Clique com o botão direito do mouse em https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe e selecione Salvar link como para fazer o download do proxy do Cloud SQL Auth. Renomeie o arquivo para cloud_sql_proxy.exe.

    Imagem do Docker do proxy do Cloud SQL Auth

    Por conveniência, várias imagens de contêiner que contêm o proxy do Cloud SQL Auth estão disponíveis no GitHub no repositório do proxy do Cloud SQL Auth. É possível extrair a imagem mais recente na sua máquina local usando o Docker com o seguinte comando:
    docker pull gcr.io/cloudsql-docker/gce-proxy:1.30.1
    

    Outros SOs

    Para outros sistemas operacionais não incluídos aqui, compile o proxy do Cloud SQL Auth na origem.

    Você pode optar por mover o download para um lugar comum, como um local no PATH ou seu diretório principal. Se você optar por fazer isso, ao iniciar o proxy do Cloud SQL Auth posteriormente no tutorial, lembre-se de consultar o local escolhido ao usar os comandos cloud_sql_proxy.

Criar serviços de apoio

Neste tutorial, usamos vários serviços do Google Cloud para fornecer o banco de dados, o armazenamento de mídia e o armazenamento de secrets que oferecem suporte ao projeto Django implantado. Esses serviços são implantados em uma região específica. Para garantir a eficiência entre os serviços, todos eles precisam ser implantados na mesma região. Para mais informações sobre a região mais próxima de você, consulte Produtos disponíveis por região.

Neste tutorial, usamos os mecanismos integrados de hospedagem de recursos estáticos no Cloud Run.

Configurar uma instância do Cloud SQL para PostgreSQL

O Django oficialmente oferece suporte a vários bancos de dados relacionais, mas oferece a maior parte do suporte para o PostgreSQL. O PostgreSQL conta com o suporte do Cloud SQL. Portanto, este tutorial escolhe usar esse tipo de banco de dados.

A seção a seguir descreve a criação de uma instância, um banco de dados e um usuário do banco de dados do PostgreSQL para o aplicativo.

  1. Crie a instância do PostgreSQL:

    Console

    1. No Console do Cloud, acesse a página Instâncias do Cloud SQL.

      Acessar a página "Instâncias" do Cloud SQL

    2. Clique em Create Instance.

    3. Clique em PostgreSQL.

    4. No campo ID da instância, insira INSTANCE_NAME.

    5. Insira uma senha para o usuário postgres.

    6. Mantenha os valores padrão dos outros campos.

    7. Clique em Criar.

    Leva alguns minutos para criar a instância e ela deve estar pronta para uso.

    gcloud

    • Crie a instância do PostgreSQL:

      gcloud sql instances create INSTANCE_NAME \
          --project PROJECT_ID \
          --database-version POSTGRES_13 \
          --tier db-f1-micro \
          --region REGION
      

    Substitua:

    • INSTANCE_NAME: o nome da instância do Cloud SQL.
    • PROJECT_ID: o ID do projeto do Google Cloud
    • REGION: a região do Google Cloud

    Leva alguns minutos para criar a instância e ela deve estar pronta para uso.

  2. Na instância criada, crie um banco de dados:

    Console

    1. Na página da instância, acesse a guia Bancos de dados.
    2. Clique em Create database.
    3. Na caixa de diálogo Nome do banco de dados, insira DATABASE_NAME.
    4. Clique em Criar.

    gcloud

    • Crie o banco de dados na instância recém-criada:

      gcloud sql databases create DATABASE_NAME \
          --instance INSTANCE_NAME
      

      Substitua DATABASE_NAME por um nome para o banco de dados dentro da instância.

  3. Crie um usuário de banco de dados:

    Console

    1. Na página da instância, acesse a guia Usuários.
    2. Clique em Adicionar conta de usuário.
    3. Na caixa de diálogo Adicionar uma conta de usuário à instância, em "Autenticação integrada":
    4. Digite o nome de usuário DATABASE_USERNAME.
    5. Insira a senha DATABASE_PASSWORD
    6. Clique em Adicionar.

    gcloud

    • Crie o usuário na instância recém-criada:

      gcloud sql users create DATABASE_USERNAME \
          --instance INSTANCE_NAME \
          --password DATABASE_PASSWORD
      

      Substitua PASSWORD por uma senha segura.

Configurar um bucket do Cloud Storage

É possível armazenar recursos estáticos incluídos no Django e mídia enviada por usuários em armazenamento de objetos altamente disponível usando o Cloud Storage. O pacote django-storages[google] processa a interação do Django com esse back-end de armazenamento.

Console

  1. In the Google Cloud console, go to the Cloud Storage Buckets page.

    Go to Buckets page

  2. Click Create bucket.
  3. On the Create a bucket page, enter your bucket information. To go to the next step, click Continue.
    • For Name your bucket, enter a name that meets the bucket naming requirements.
    • For Location, select the following: MEDIA_BUCKET
    • For Choose a default storage class for your data, select the following: Standard.
    • For Choose how to control access to objects, select an Access control option.
    • For Advanced settings (optional), specify an encryption method, a retention policy, or bucket labels.
  4. Click Create.

gcloud

A ferramenta de linha de comando gsutil foi instalada como parte da instalação da CLI gcloud.

  • Crie um bucket do Cloud Storage:

    gsutil mb -l REGION gs://PROJECT_ID_MEDIA_BUCKET
    

    Substitua MEDIA_BUCKET por um sufixo para o bucket de mídia. Combinado com o ID do projeto, isso cria um nome de bucket exclusivo.

Armazenar valores do secret no Secret Manager

Agora que os serviços de backup estão configurados, o Django precisa de informações sobre esses serviços. Em vez de colocar esses valores diretamente no código-fonte do Django, este tutorial usa o Secret Manager para armazenar essas informações com segurança.

O Cloud Run e o Cloud Build interagem com secrets usando as respectivas contas de serviço. As contas de serviço são identificadas por um endereço de e-mail que contém o número do projeto.

Criar o arquivo de ambiente Django como um secret do Secret Manager

Você armazena as configurações necessárias para iniciar o Django em um arquivo env protegido. O aplicativo de amostra usa a API Secret Manager para recuperar o valor do secret e o pacote django-environ para carregar os valores no ambiente Django. O secret é configurado para ser acessível pelo Cloud Run e pelo Cloud Build.

  1. Crie um arquivo chamado .env, definindo a string de conexão do banco de dados, o nome do bucket de mídia e um novo valor SECRET_KEY:

    echo DATABASE_URL=postgres://DATABASE_USERNAME:DATABASE_PASSWORD@//cloudsql/PROJECT_ID:REGION:INSTANCE_NAME/DATABASE_NAME > .env
    echo GS_BUCKET_NAME=PROJECT_ID_MEDIA_BUCKET >> .env
    echo SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n1) >> .env
    
  2. Armazene o secret no Secret Manager:

    Console

    1. No Console do Cloud, acesse a página do Secret Manager.

      Acessar a página "Gerenciador de secrets"

    2. Clique em Criar secret.

    3. No campo Nome, use django_settings.

    4. Na caixa de diálogo Valor do secret, cole o conteúdo do arquivo .env.

    5. Clique em Criar secret.

    6. Em Detalhes de django_settings, anote o número do projeto:

      projects/PROJECTNUM/secrets/django_settings
      
    7. Exclua o arquivo local para evitar modificações de configuração locais.

    gcloud

    1. Crie um novo secret, django_settings, com o valor do arquivo .env:

      gcloud secrets create django_settings --data-file .env
      
    2. Para confirmar a criação do secret, verifique-o:

      gcloud secrets describe django_settings
      
      gcloud secrets versions access latest --secret django_settings
      
    3. Encontre o valor do número do projeto (PROJECTNUM):

      export PROJECTNUM=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)')
      
    4. Exclua o arquivo local para evitar modificações de configuração locais:

      rm .env
      
  3. Configure o acesso ao secret:

    Console

    1. Clique na guia Permissões.
    2. Clique em Adicionar.
    3. No campo Novos membros, digite PROJECTNUM-compute@developer.gserviceaccount.com e pressione Enter.
    4. No campo Novos membros, digite PROJECTNUM@cloudbuild.gserviceaccount.com e pressione Enter.
    5. No menu suspenso Papel, selecione Acessador de secrets do Secret Manager.
    6. Clique em Save.

    gcloud

    1. Conceda acesso ao secret para a conta de serviço do Cloud Run:

      gcloud secrets add-iam-policy-binding django_settings \
          --member serviceAccount:PROJECTNUM-compute@developer.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      
    2. Conceda acesso ao secret para a conta de serviço do Cloud Build:

      gcloud secrets add-iam-policy-binding django_settings \
          --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      

      Na saída, confirme se bindings lista as duas contas de serviço como membros.

Criar um secret para a senha de administrador do Django

O usuário administrador do Django normalmente é criado executando o comando de gerenciamento interativo createsuperuser.

Este tutorial usa uma migração de dados para criar o usuário administrador, recuperando a senha de administrador no Secret Manager.

Console

  1. No Console do Cloud, acesse a página do Secret Manager.
  2. Clique em Criar secret.

  3. No campo Nome, use superuser_password.

  4. No campo Valor do secret, insira uma senha aleatória e única.

  5. Clique em Criar secret.

  6. Em Detalhes da superuser_password, anote o número do projeto (projects/PROJECTNUM/secrets/superuser_password).

  7. Clique na guia Permissões.

  8. Clique em Adicionar.

  9. No campo Novos membros, digite PROJECTNUM@cloudbuild.gserviceaccount.com e pressione Enter.

  10. No menu suspenso Papel, selecione Acessador de secrets do Secret Manager.

  11. Clique em Save.

gcloud

  1. Crie um novo secret, superuser_password, a partir de uma senha gerada aleatoriamente:

    echo -n "$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 30 | head -n1)" | gcloud secrets create superuser_password --data-file -
    
  2. Conceda acesso ao secret do Cloud Build:

    gcloud secrets add-iam-policy-binding superuser_password \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    

    Na saída, confirme se bindings lista apenas o Cloud Build como membro.

Conceder acesso ao Cloud Build para o Cloud SQL

Para que o Cloud Build aplique as migrações do banco de dados, é preciso conceder permissões para que o Cloud Build acesse o Cloud SQL.

Console

  1. No Console do Cloud, acesse a página Gerenciamento de identidade e acesso.

    Acessar a página "Gerenciamento de identidade e acesso"

  2. Para editar a entrada de PROJECTNUM@cloudbuild.gserviceaccount.com, clique em Editar.

  3. Clique em Adicionar outro papel.

  4. Na caixa de diálogo Selecionar um papel, selecione Cliente do Cloud SQL.

  5. Clique em Save.

gcloud

  1. Conceda permissão para que o Cloud Build acesse o Cloud SQL:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/cloudsql.client
    

Executar o app no computador local

Com os serviços de backup configurados, agora você pode executar o aplicativo no seu computador. Essa configuração permite o desenvolvimento local e a aplicação de migrações de banco de dados. As migrações de banco de dados também são aplicadas no Cloud Build, mas você precisará ter essa configuração local para usar makemigrations.

  1. Em um terminal separado, inicie o proxy do Cloud SQL Auth:

    Linux/macOS

    ./cloud_sql_proxy -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    Windows

    cloud_sql_proxy.exe -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    Essa etapa estabelece uma conexão do computador local com a instância do Cloud SQL para testes locais. Mantenha o proxy do Cloud SQL Auth em execução durante todo o teste local do aplicativo. A execução desse processo em um terminal separado permite que você continue trabalhando enquanto esse processo é executado.

  2. Em um novo terminal, defina o ID do projeto localmente (usado pela API Secret Manager):

    Linux/macOS

      export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    

    Windows

      set GOOGLE_CLOUD_PROJECT=PROJECT_ID
    
  3. Defina uma variável de ambiente para indicar que você está usando o proxy do Cloud SQL Auth (esse valor é reconhecido no código):

    Linux/macOS

      export USE_CLOUD_SQL_AUTH_PROXY=true
    

    Windows

      set USE_CLOUD_SQL_AUTH_PROXY=true
    
  4. Execute as migrações do Django para configurar os modelos e os recursos:

    python manage.py makemigrations
    python manage.py makemigrations polls
    python manage.py migrate
    python manage.py collectstatic
    
  5. Inicie o servidor da Web do Django:

    python manage.py runserver
    
  6. No navegador, acesse http://localhost:8000/.

    A página exibe o seguinte texto: "Hello, world. Você está no índice de pesquisas". O servidor da Web do Django em execução no seu computador exibe as páginas do aplicativo de amostra.

  7. Pressione Ctrl/Cmd+C para interromper o servidor da Web local.

Implantar o app no Cloud Run

Com a configuração de serviços de apoio, é possível implantar o serviço Cloud Run.

  1. Usando o cloudmigrate.yaml fornecido, use o Cloud Build para criar a imagem, executar as migrações do banco de dados e preencher os recursos estáticos:

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    

    A primeira versão leva alguns minutos para ser concluída.

  2. Quando a criação for bem-sucedida, implante o serviço Cloud Run pela primeira vez, definindo a região de serviço, a imagem de base e a instância do Cloud SQL conectada:

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service \
        --add-cloudsql-instances PROJECT_ID:REGION:INSTANCE_NAME \
        --allow-unauthenticated
    

    Será exibida a resposta que mostra a implantação bem-sucedida, com o URL de serviço:

    Service [polls-service] revision [polls-service-00001-tug] has been deployed
    and is serving 100 percent of traffic at https://polls-service-<hash>-uc.a.run.app
    
  3. Agora que o URL do serviço é conhecido, atualize o serviço para definir esse valor como uma variável de ambiente:

    SERVICE_URL=$(gcloud run services describe polls-service --platform managed \
        --region REGION --format "value(status.url)")
    
    gcloud run services update polls-service \
        --platform managed \
        --region REGION \
        --set-env-vars CLOUDRUN_SERVICE_URL=$SERVICE_URL
    
  4. Para ver o serviço implantado, acesse o URL do serviço.

  5. Para fazer login no administrador do Django, anexe /admin ao URL, faça login com o nome de usuário admin e a senha definida anteriormente.

Atualização do aplicativo

Embora as etapas iniciais de provisionamento e implantação tenham sido complexas, fazer atualizações é um processo mais simples:

  1. Execute o script de criação e migração do Cloud Build:

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    
  2. Implante o serviço, especificando apenas a região e a imagem:

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service
    

Como configurar para produção

Agora você tem uma implantação do Django funcionando, mas pode seguir algumas etapas para garantir que seu aplicativo esteja pronto para produção.

Desativar depuração

Confirme se a variável DEBUG em mysite/settings.py está definida como False. Isso impedirá que as páginas de erro detalhadas sejam exibidas para o usuário, o que pode vazar informações sobre as configurações.

Limitar os privilégios de usuário do banco de dados

Todos os usuários criados com o Cloud SQL têm os privilégios associados ao papel cloudsqlsuperuser: CREATEROLE, CREATEDB e LOGIN.

Para impedir que o usuário do banco de dados do Django tenha essas permissões, crie-o manualmente no PostgreSQL. Você precisará ter o terminal interativo psql instalado ou usar o Cloud Shell com essa ferramenta pré-instalada.

Console

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  2. No Cloud Shell, use o terminal integrado para se conectar à instância INSTANCE_NAME:

    gcloud sql connect INSTANCE_NAME --user postgres
    
  3. Insira a senha do usuário do postgres.

    Agora você está usando o psql. Você verá o prompt postgres=>.

  4. Crie um usuário:

    CREATE USER DATABASE_USERNAME WITH PASSWORD 'DATABASE_PASSWORD';
    

    Substitua PASSWORD por uma senha aleatória e exclusiva.

  5. Conceda direitos totais sobre o novo banco de dados para o novo usuário:

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO DATABASE_USERNAME;
    
  6. Saia de psql:

    \q
    

gcloud

  1. Inicie uma conexão com a instância do SQL:

    gcloud sql connect INSTANCE_NAME --user postgres
    

    Substitua INSTANCE_NAME pela instância criada do Cloud SQL.

  2. Insira a senha do usuário do postgres.

    Agora você está usando o psql. Você verá o prompt postgres=>.

  3. Crie um usuário:

    CREATE USER DATABASE_USERNAME WITH PASSWORD 'DATABASE_PASSWORD';
    
  4. Conceda direitos totais sobre o novo banco de dados para o novo usuário:

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO DATABASE_USERNAME;
    
  5. Saia de psql:

    \q
    

Como definir permissões mínimas

Por padrão, esse serviço é implantado com a conta de serviço de computação padrão. No entanto, em alguns casos, o uso da conta de serviço padrão pode fornecer muitas permissões. Se você quiser ser mais restritivo, será necessário criar sua própria conta de serviço e atribuir apenas as permissões exigidas pelo serviço. As permissões necessárias podem variar de serviço para serviço, dependendo dos recursos usados por um determinado serviço.

Os papéis mínimos do projeto exigidos por este serviço são os seguintes:

  • Chamador do Cloud Run
  • Cliente do Cloud SQL
  • Administrador do Storage, no bucket de mídia
  • Acessador de Secret Manager, no secret de configurações do Django. O acesso ao secret do administrador do Django não é exigido pelo próprio serviço.

Para criar uma conta de serviço com as permissões necessárias e atribuí-la ao serviço, execute este comando:

  1. Na CLI gcloud, crie uma conta de serviço com os papéis necessários:

    gcloud iam service-accounts create polls-service-account
    SERVICE_ACCOUNT=polls-service-account@PROJECT_ID.iam.gserviceaccount.com
    
    # Cloud Run Invoker
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/run.invoker
    
    # Cloud SQL Client
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/cloudsql.client
    
    # Storage Admin, on the media bucket
    gsutil iam ch \
        serviceAccount:${SERVICE_ACCOUNT}:roles/storage.objectAdmin \
        gs://MEDIA_BUCKET
    
    # Secret Accessor, on the Django settings secret.
    gcloud secrets add-iam-policy-binding django_settings \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/secretmanager.secretAccessor
    
  2. Implante o serviço, associando-o à nova conta de serviço:

    gcloud run services update polls-service \
        --platform managed \
        --region REGION \
        --service-account ${SERVICE_ACCOUNT}
    

Entenda o código

Exemplo de aplicativo

O app de exemplo do Django foi criado com ferramentas padrão do Django. Os comandos a seguir criam o projeto e o aplicativo de pesquisa:

django-admin startproject mysite
python manage.py startapp polls

As visualizações básicas, os modelos e as configurações de rota foram copiados de Como criar seu primeiro aplicativo Django (Parte 1 e Parte 2).

Secrets do Secret Manager

O arquivo settings.py contém o código que usa a API Secret Manager Python para recuperar a versão mais recente do secret nomeado e extraí-la para o ambiente (usando django-environ):

# SECURITY WARNING: don't run with debug turned on in production!
# Change this to "False" when you are ready for production
env = environ.Env(DEBUG=(bool, True))
env_file = os.path.join(BASE_DIR, ".env")

# Attempt to load the Project ID into the environment, safely failing on error.
try:
    _, os.environ["GOOGLE_CLOUD_PROJECT"] = google.auth.default()
except google.auth.exceptions.DefaultCredentialsError:
    pass

if os.path.isfile(env_file):
    # Use a local secret file, if provided

    env.read_env(env_file)
# ...
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    # Pull secrets from Secret Manager
    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")

    client = secretmanager.SecretManagerServiceClient()
    settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
    name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
    payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")

    env.read_env(io.StringIO(payload))
else:
    raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")

O secret foi usado para armazenar diversos valores de secret para reduzir o número de diferentes secrets que precisavam ser configurados. Embora o superuser_password possa ter sido criado diretamente na linha de comando, o método baseado em arquivo foi usado. Se for gerado a partir da linha de comando, foi usado um cuidado usando head -c para determinar o comprimento da string gerada aleatoriamente, garantindo que não havia caracteres de nova linha no final do arquivo, o que poderia causar problemas quando a senha foi inserida no administrador do Django.

Configurações de CSRF

O Python tem proteção integrada contra falsificação de solicitações entre sites (CSRF, na sigla em inglês). A partir do Python 4.0, as mudanças no funcionamento disso significam que é importante dizer ao Flutter o que é o URL hospedado para que ele possa oferecer as melhores proteções para os usuários que enviam dados.

Você fornece o URL do app como uma variável de ambiente no arquivo settings.py. Esse é o valor que o Flutter usa para as configurações relevantes.

# SECURITY WARNING: It's recommended that you use this when
# running in production. The URL will be known once you first deploy
# to Cloud Run. This code takes the URL and converts it to both these settings formats.
CLOUDRUN_SERVICE_URL = env("CLOUDRUN_SERVICE_URL", default=None)
if CLOUDRUN_SERVICE_URL:
    ALLOWED_HOSTS = [urlparse(CLOUDRUN_SERVICE_URL).netloc]
    CSRF_TRUSTED_ORIGINS = [CLOUDRUN_SERVICE_URL]
    SECURE_SSL_REDIRECT = True
    SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
else:
    ALLOWED_HOSTS = ["*"]

Substituições de secret local

Se um arquivo .env for encontrado no sistema de arquivos local, ele será usado no lugar do valor do Secret Manager. Criar um arquivo .env localmente pode ajudar com testes locais. Por exemplo, desenvolvimento local em um banco de dados SQLite ou outras configurações locais.

Conexão com o banco de dados

O arquivo settings.py contém a configuração do banco de dados SQL. Se você definir o USE_CLOUD_SQL_AUTH_PROXY, a configuração DATABASES será alterada para inferir o uso do proxy do Cloud SQL Auth.

# Use django-environ to parse the connection string
DATABASES = {"default": env.db()}

# If the flag as been set, configure to use proxy
if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
    DATABASES["default"]["HOST"] = "127.0.0.1"
    DATABASES["default"]["PORT"] = 5432

Estática, armazenada em nuvem

O arquivo settings.py também usa django-storages para integrar o bucket de mídia do Cloud Storage diretamente ao projeto:

# Define static storage via django-storages[google]
GS_BUCKET_NAME = env("GS_BUCKET_NAME")
STATIC_URL = "/static/"
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
STATICFILES_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_DEFAULT_ACL = "publicRead"

Automação com o Cloud Build

O arquivo cloudmigrate.yaml executa não apenas as etapas comuns de criação de imagem (criação da imagem do contêiner e envio da imagem para o registro do contêiner), mas também os comandos migrate e collectstatic do Django. Eles exigem acesso ao banco de dados, que é realizado usando o app-engine-exec-wrapper, um auxiliar do proxy do Cloud SQL Auth:

steps:
  - id: "build image"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}", "."]

  - id: "push image"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"]

  - id: "apply migrations"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "migrate",
      ]

  - id: "collect static"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "collectstatic",
        "--verbosity",
        "2",
        "--no-input",
      ]

substitutions:
  _INSTANCE_NAME: django-instance
  _REGION: us-central1
  _SERVICE_NAME: polls-service
  _SECRET_SETTINGS_NAME: django_settings

images:
  - "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"

Variáveis de substituição são usadas nessa configuração. Se você alterar os valores no arquivo, significa que a sinalização --substitutions pode ser descartada no momento da migração.

Nessa configuração, apenas migrações existentes são aplicadas. As migrações precisam ser criadas localmente usando o método de proxy do Cloud SQL Auth definido em "Como executar o aplicativo localmente". Esse modelo pode ser estendido para executar outros comandos manage.py, conforme necessário.

Para estender a configuração do Cloud Build para incluir a implantação em uma configuração sem precisar executar dois comandos, consulte Implantação contínua do git usando o Cloud Build. Isso exige alterações no IAM, conforme descrito.

Criação de superusuário com migrações de dados

O comando de gerenciamento do Django createsuperuser só pode ser executado de forma interativa, ou seja, quando o usuário puder inserir informações em resposta às solicitações. Embora seja possível usar esse comando com o Cloud SQL Proxy e executar comandos em uma configuração local do Docker, outra maneira é criar o superusuário como uma migração de dados:

import os

from django.contrib.auth.models import User
from django.db import migrations
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps

import google.auth
from google.cloud import secretmanager

def createsuperuser(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
    """
    Dynamically create an admin user as part of a migration
    Password is pulled from Secret Manger (previously created as part of tutorial)
    """
    if os.getenv("TRAMPOLINE_CI", None):
        # We are in CI, so just create a placeholder user for unit testing.
        admin_password = "test"
    else:
        client = secretmanager.SecretManagerServiceClient()

        # Get project value for identifying current context
        _, project = google.auth.default()

        # Retrieve the previously stored admin password
        PASSWORD_NAME = os.environ.get("PASSWORD_NAME", "superuser_password")
        name = f"projects/{project}/secrets/{PASSWORD_NAME}/versions/latest"
        admin_password = client.access_secret_version(name=name).payload.data.decode(
            "UTF-8"
        )

    # Create a new user using acquired password, stripping any accidentally stored newline characters
    User.objects.create_superuser("admin", password=admin_password.strip())

class Migration(migrations.Migration):

    initial = True
    dependencies = []
    operations = [migrations.RunPython(createsuperuser)]

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

Excluir o projeto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

A seguir