Neste tutorial, descrevemos como migrar aplicativos da Web Node.js em execução no Heroku para o Cloud Run no Google Cloud. Este tutorial é destinado a arquitetos e proprietários de produtos que querem migrar os apps do Heroku para serviços gerenciados no Google Cloud.
O Cloud Run é uma plataforma de computação gerenciada que permite executar contêineres sem estado que podem ser invocados por solicitações HTTP. Ele é baseado no Knative de código aberto, que permite a portabilidade entre plataformas e é compatível com fluxos de trabalho e padrões de entrega contínua. A plataforma do Cloud Run está bem integrada ao pacote de produtividade do Google Cloud e facilita o design e o desenvolvimento de apps portáteis, escalonáveis e resilientes.
Neste tutorial, você aprende a migrar um app para o Google Cloud que está escrito em Node.js e usa Heroku Postgres (em inglês) como um serviço de apoio no Heroku. O app da Web é colocado em contêiner e hospedado no Cloud Run e usa o Cloud SQL para PostgreSQL como camada de persistência.
No tutorial, você usa um app simples denominado Tarefas, que permite visualizar e criar tarefas. Essas tarefas são armazenadas no Heroku Postgres na implantação atual do app no Heroku.
Neste tutorial, presumimos que você está familiarizado com a funcionalidade básica do Heroku (em inglês) e que tenha uma conta do Heroku (ou acesso a uma). Também presumimos que você esteja familiarizado com o Cloud Run, o Cloud SQL, o Docker e o Node.js (em inglês).
Objetivos
- Criar uma imagem do Docker para implantar o app no Cloud Run.
- Criar uma instância do Cloud SQL para PostgreSQL para servir como back-end após a migração para o Google Cloud.
- Analisar o código do Node.js para saber como o Cloud Run se conecta ao Cloud SQL e ver as alterações de código necessárias, se houver, para migrar do Heroku para o Cloud Run.
- Migrar os dados do Heroku Postgres para o Cloud SQL para PostgreSQL.
- Implantar o app no Cloud Run.
- Testar o app implantado.
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.
Também é possível que você seja cobrado pelos recursos que usa no Heroku.
Antes de começar
- 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.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Cloud SQL, Cloud Build, Cloud Run, Container Registry, Service Networking, Serverless VPC Access APIs.
-
Make sure that you have the following role or roles on the project: Cloud Run > Cloud Run Admin, Cloud Storage > Storage Admin, Cloud SQL > Cloud SQL Admin, Compute Engine > Compute Network Admin, Resource Manager > Project IAM Admin, Cloud Build > Cloud Build Editor, Serverless VPC Access > Serverless VPC Access Admin, Logging > Logs Viewer, Service Accounts > Service Account Admin, Service Accounts > Service Account User, and Service Usage > Service Usage Consumer
Check for the roles
-
In the Google Cloud console, go to the IAM page.
Go to IAM - Select the project.
-
In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.
- For all rows that specify or include you, check the Role colunn to see whether the list of roles includes the required roles.
Grant the roles
-
In the Google Cloud console, go to the IAM page.
Acessar o IAM - Selecionar um projeto.
- Clique em CONCEDER ACESSO.
-
No campo Novos principais, insira seu identificador de usuário. Normalmente, é o endereço de e-mail de uma Conta do Google.
- Na lista Selecionar um papel, escolha um.
- Para conceder outros papéis, clique em Adicionar outro papel e adicione cada papel adicional.
- Clique em Salvar.
-
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Cloud SQL, Cloud Build, Cloud Run, Container Registry, Service Networking, Serverless VPC Access APIs.
-
Make sure that you have the following role or roles on the project: Cloud Run > Cloud Run Admin, Cloud Storage > Storage Admin, Cloud SQL > Cloud SQL Admin, Compute Engine > Compute Network Admin, Resource Manager > Project IAM Admin, Cloud Build > Cloud Build Editor, Serverless VPC Access > Serverless VPC Access Admin, Logging > Logs Viewer, Service Accounts > Service Account Admin, Service Accounts > Service Account User, and Service Usage > Service Usage Consumer
Check for the roles
-
In the Google Cloud console, go to the IAM page.
Go to IAM - Select the project.
-
In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.
- For all rows that specify or include you, check the Role colunn to see whether the list of roles includes the required roles.
Grant the roles
-
In the Google Cloud console, go to the IAM page.
Acessar o IAM - Selecionar um projeto.
- Clique em CONCEDER ACESSO.
-
No campo Novos principais, insira seu identificador de usuário. Normalmente, é o endereço de e-mail de uma Conta do Google.
- Na lista Selecionar um papel, escolha um.
- Para conceder outros papéis, clique em Adicionar outro papel e adicione cada papel adicional.
- Clique em Salvar.
-
Como configurar o ambiente
Abra o Cloud Shell.
No Cloud Shell, defina variáveis de ambiente e valores padrão para a Google Cloud CLI usada neste tutorial.
gcloud config set project PROJECT_ID gcloud config set run/region us-central1
Substitua
PROJECT_ID
pela ID do seu projeto.
Arquitetura
Nas figuras a seguir, descrevemos a arquitetura do app da Web no Heroku (assim como está) e o layout de arquitetura dele no Google Cloud (que você criará).
O app Tarefas atualmente implantado no Heroku consiste em um ou mais dynos da Web. Os dynos da Web são capazes de receber e responder ao tráfego HTTP, ao contrário dos dynos de worker, que são mais adequados a jobs em segundo plano e tarefas cronometradas. O app exibe uma página de índice que mostra tarefas armazenadas em um banco de dados do Postgres, usando a biblioteca de modelos Mustache para Node.js.
É possível acessar o app em um URL HTTPS. Uma rota /tasks
nesse URL permite criar novas tarefas.
No Google Cloud, o Cloud Run é usado como a plataforma sem servidor para implantar o app Tarefas. O Cloud Run foi projetado para executar contêineres sem estado e orientados por solicitações. Ele é adequado para quando você precisa que seu serviço gerenciado seja compatível com apps contentorizados que fazem escalonamento automático, podendo chegar a zero quando não estão veiculando tráfego.
Como mapear componentes usados no Heroku para o Google Cloud
Na tabela a seguir, correlacionamos os componentes da plataforma Heroku com o Google Cloud. Isso ajuda a traduzir a arquitetura descrita neste tutorial do Heroku para o Google Cloud.
Componente | Plataforma Heroku | Google Cloud |
---|---|---|
Contêineres | Dynos (em inglês): o Heroku usa o modelo de contêiner para criar e escalonar apps do Heroku. Esses contêineres do Linux são chamados de dynos e podem ser escalonados para um número especificado para atender às demandas de recursos do app Heroku. É possível selecionar entre vários tipos de dyno com base nos requisitos de memória e CPU do app. | Contêineres do Cloud Run: o Google Cloud é compatível com a execução de cargas de trabalho contentorizadas em contêineres sem estado que podem ser executados em um ambiente totalmente gerenciado ou em clusters do Google Kubernetes Engine (GKE). |
App da Web | App Heroku: os dynos são os blocos de construção dos apps Heroku. Os app geralmente consistem em um ou mais tipos de dyno, geralmente uma combinação de dynos da Web e do worker. | Serviço do Cloud Run: um app da Web pode ser modelado como um serviço do Cloud Run. Cada serviço recebe seu próprio endpoint HTTPS e pode aumentar ou diminuir automaticamente de 0 para N baseado no tráfego para seu endpoint de serviço. |
Banco de dados | Heroku Postgres é o banco de dados como um serviço (DaaS, na sigla em inglês) do Heroku com base no PostgreSQL. | Cloud SQL é um serviço de banco de dados gerenciado para bancos de dados relacionais no Google Cloud. |
Como implantar o app da Web de exemplo Tarefas no Heroku
Nas próximas seções, mostramos como configurar a interface de linha de comando (CLI, na sigla em inglês) para o Heroku, como clonar o repositório de origem do GitHub e implantar o app no Heroku.
Configurar a interface de linha de comando do Heroku
Neste tutorial, a CLI do Heroku no Cloud Shell é executada e é necessário fazer a autenticação usando uma chave de API Heroku. Quando executada no Cloud Shell, a CLI do Heroku não pode autenticar usando uma senha ou autenticação baseada na Web.
Como alternativa, se você executar o exemplo em um terminal local, poderá usar qualquer método de autenticação da CLI do Heroku. Ao executar o tutorial em um terminal local, você também precisa instalar o Google Cloud CLI, o git e o Docker.
Faça login no console da Web do Heroku e, na página de configurações da conta, copie o valor da chave de API.
No Cloud Shell, instale a CLI do Heroku
No Cloud Shell, autentique a CLI do Heroku Quando sua senha for solicitada, insira o valor da chave de API que você copiou do console do Heroku, não a senha que você usa para fazer login no console.
heroku login --interactive
Clonar o repositório de origem
No Cloud Shell, clone o repositório do GitHub do app Tarefas:
git clone https://github.com/GoogleCloudPlatform/migrate-webapp-heroku-to-cloudrun-node.git
Altere os diretórios para o diretório criado ao clonar o repositório:
cd migrate-webapp-heroku-to-cloudrun-node
O diretório contém os seguintes arquivos:
- Um script Node.js denominado
index.js
com o código das rotas veiculadas pelo app da Web. package.json
epackage-lock.json
que descrevem as dependências do app da Web. É preciso instalar essas dependências para que o app seja executado.- Um arquivo
Procfile
que especifica o comando que o app executa na inicialização. Você cria um arquivoProcfile
para implantar o app no Heroku. - Um diretório
views
, com o conteúdo HTML veiculado pelo app da Web na rota "/". - Um arquivo
.gitignore
- Um script Node.js denominado
Implantar um app no Heroku
No Cloud Shell, crie um app Heroku:
heroku create
Anote o nome criado para o aplicativo. Você vai precisar desse valor na próxima etapa.
Crie uma variável de ambiente para o nome do app Heroku:
export APP_NAME=APP_NAME
Substitua
APP_NAME
pelo nome do app retornado pelo comandoheroku create
.Adicione o complemento Heroku Postgres para aprovisionar um banco de dados PostgreSQL:
heroku addons:create heroku-postgresql:mini
Verifique se o complemento foi adicionado:
heroku addons
Se o complemento Postgres tiver sido adicionado, você verá uma mensagem semelhante a esta:
Add-on Plan Price State ----------------- ----- -------- ----- heroku-postgresql mini 5$/month created
Implante o app no Heroku:
git push heroku master
Execute o seguinte comando para confirmar o valor de DATABASE_URL.
heroku config
Anote o valor recuperado para DATABASE_URL. Ele será necessário na próxima etapa.
Execute um contêiner do Docker.
docker run -it --rm postgres psql "DATABASE_URL"
Substitua
DATABASE_URL
pelo URL do Heroku Postgres que você anotou na etapa anterior.No contêiner do Docker, crie a tabela
TASKS
usando o seguinte comando:CREATE TABLE TASKS (DESCRIPTION TEXT NOT NULL);
Saia do contêiner:
exit
No Cloud Shell, execute o seguinte comando para encontrar o URL da Web do seu app Heroku:
heroku info
Abra o URL da Web em uma janela do navegador. O app vai ficar parecido com a seguinte captura de tela, embora sua versão não tenha as tarefas listadas:
Crie tarefas de amostra no app pelo navegador. Verifique se as tarefas são recuperadas do banco de dados e visíveis na IU.
Como preparar o código do app da Web para migração para o Cloud Run
Nesta seção, detalhamos as etapas necessárias para preparar seu app da Web para implantação no Cloud Run.
Criar e publicar seu contêiner do Docker no Container Registry
Você precisa de uma imagem do Docker para criar o contêiner do app para que seja executado no Cloud Run. Crie o contêiner manualmente ou usando o Buildpack.
Criar o contêiner manualmente
No Cloud Shell, crie um Dockerfile no diretório criado clonando o repositório deste tutorial:
cat <<"EOF" > Dockerfile # Use the official Node image. # https://hub.docker.com/_/node FROM node:10-alpine # Create and change to the app directory. WORKDIR /app # Copying this separately prevents re-running npm install on every code change. COPY package*.json ./ RUN npm install # Copy local code to the container image. COPY . /app # Configure and document the service HTTP port. ENV PORT 8080 EXPOSE $PORT # Run the web service on container startup. CMD ["npm", "start"] EOF
Crie seu contêiner com o Cloud Build e publique a imagem no Container Registry:
gcloud builds submit --tag gcr.io/PROJECT_ID/APP_NAME:1 \ --gcs-log-dir=gs://PROJECT_ID_cloudbuild
Crie uma variável de ambiente para manter o nome da imagem do Docker que você criou:
export IMAGE_NAME="gcr.io/PROJECT_ID/APP_NAME:1"
Criar contêiner com o Buildpacks
No Cloud Shell, instale a CLI do pacote (em inglês):
Defina a CLI do pacote para usar o builder do Heroku por padrão:
pack config default-builder heroku/buildpacks:22
Crie uma variável de ambiente para manter o nome da imagem do Docker:
export IMAGE_NAME=gcr.io/PROJECT_ID/APP_NAME:1
Crie a imagem usando o comando
pack
e envie ou publique a imagem para o Container Registry:pack build --publish $IMAGE_NAME
Crie uma instância do Cloud SQL para PostgreSQL
Crie uma instância do Cloud SQL para PostgreSQL para servir como o back-end do app da Web. Neste tutorial, o PostgreSQL é mais adequado como app de exemplo implantado no Heroku, que usa um banco de dados do Postgres como back-end. Para os fins deste app, a migração para o Cloud SQL para PostgreSQL de um serviço Postgres gerenciado não requer alterações no esquema.
Prepare sua rede para o Cloud SQL com um endereço IP privado.
gcloud compute addresses create google-managed-services-default \ --global \ --purpose=VPC_PEERING \ --prefix-length=16 \ --description="peering range for CloudSQL Private Service Access" \ --network=default gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=google-managed-services-default \ --network=default \ --project=PROJECT_ID
Crie uma variável de ambiente denominada
CLOUDSQL_DB_NAME
para manter o nome da instância de banco de dados criada na próxima etapa:export CLOUDSQL_DB_NAME=tasks-db
Crie o banco de dados:
gcloud sql instances create $CLOUDSQL_DB_NAME \ --cpu=1 \ --memory=4352Mib \ --database-version=POSTGRES_15 \ --region=us-central1 \ --network default \ --no-assign-ip
A instância pode levar alguns minutos para ser inicializada.
Defina uma senha para o usuário do Postgres:
gcloud sql users set-password postgres \ --instance=$CLOUDSQL_DB_NAME \ --password=POSTGRES_PASSWORD
Substitua
POSTGRES_PASSWORD
pela senha que você quer usar para o banco de dados do Postgres.
Importar dados para o Cloud SQL do Heroku Postgres
Há vários padrões de migração que podem ser utilizados para migrar dados para o Cloud SQL. A melhor abordagem, que requer pouca ou nenhuma inatividade, é configurar o Cloud SQL como uma réplica para o banco de dados que está sendo migrado e fazer do Cloud SQL a instância principal após a migração. O Heroku Postgres não é compatível com réplicas externas (seguidores). Nesse tutorial, você usa ferramentas de código aberto para migrar o esquema do app.
Para o app Tarefas neste tutorial, use o utilitário pg_dump (em inglês) para exportar dados do Heroku Postgres para um bucket do Cloud Storage e importá-los para o Cloud SQL. Esse utilitário pode transferir dados em versões homogêneas ou quando a versão do banco de dados de destino é mais recente que o banco de dados de origem.
No Cloud Shell, receba as credenciais do banco de dados do Heroku Postgres anexado ao app de exemplo. Você precisará dessas credenciais na próxima etapa.
heroku pg:credentials:url
Esse comando retorna a string de informações de conexão e o URL de conexão do app. A string de informações de conexão tem o seguinte formato:
"dbname=DATABASE_NAME host=FQDN port=5432 user=USER_NAME password=PASSWORD_STRING sslmode=require"
Você vai precisar dos valores mostrados na string de conexão na próxima etapa.
Para um exemplo de um valor FQDN (nome de domínio totalmente qualificado) em uma string de informações de conexão, consulte a documentação do Heroku.
Defina variáveis de ambiente para manter os valores do Heroku que você usará nas etapas subsequentes:
export HEROKU_PG_DBNAME=DATABASE_NAME export HEROKU_PG_HOST=FQDN export HEROKU_PG_USER=USER_NAME export HEROKU_PG_PASSWORD=PASSWORD_STRING
Substitua:
DATABASE_NAME
: o nome do banco de dados mostrado na string de informações.FQDN
: o FQDN mostrado na string de informações.USER_NAME
: o nome do usuário mostrado na string de informações.PASSWORD_STRING
: a string de senha mostrada na string de informações.
Crie um backup em formato SQL do banco de dados do Heroku Postgres:
docker run \ -it --rm \ -e PGPASSWORD=$HEROKU_PG_PASSWORD \ -v $(pwd):/tmp \ --entrypoint "pg_dump" \ postgres \ -Fp \ --no-acl \ --no-owner \ -h $HEROKU_PG_HOST \ -U $HEROKU_PG_USER \ $HEROKU_PG_DBNAME > herokudump.sql
Crie uma variável de ambiente para manter o nome do bucket do Cloud Storage.
export PG_BACKUP_BUCKET=gs://PROJECT_ID-pg-backup-bucket
Crie um bucket do Cloud Storage:
gcloud storage buckets create $PG_BACKUP_BUCKET \ --location=us-central1 \ --public-access-prevention \ --uniform-bucket-level-access
Faça upload do arquivo SQL neste bucket:
gcloud storage cp herokudump.sql $PG_BACKUP_BUCKET/herokudump.sql
Autorize a instância do Cloud SQL com os papéis necessários para importar o arquivo SQL do bucket do Cloud Storage:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='get("serviceAccountEmailAddress")') \ --role=roles/storage.objectAdmin gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='get("serviceAccountEmailAddress")') \ --role=roles/cloudsql.editor
Importe o arquivo SQL para a instância do Cloud SQL:
gcloud sql import sql $CLOUDSQL_DB_NAME $PG_BACKUP_BUCKET/herokudump.sql \ --database=postgres \ --user=postgres
Quando solicitado
do you want to continue (y/n)
, digite "y".
Como o Cloud Run acessa o banco de dados do Cloud SQL
Assim como o app da Web implantado no Heroku precisa se conectar à instância gerenciada do Heroku Postgres, o Cloud Run requer acesso ao Cloud SQL para poder ler e gravar dados.
O Cloud Run se comunica com o Cloud SQL usando o proxy do Cloud SQL que é ativado e configurado automaticamente quando você implanta o contêiner no Cloud Run. O banco de dados não precisa ter endereços IP externos aprovados porque toda a comunicação que ele recebe é do proxy usando TCP seguro.
Seu código precisa chamar operações do banco de dados (como a busca de dados do banco de dados ou gravações nele) invocando o proxy em um soquete UNIX.
Como esse app da Web é escrito em Node.js, use a biblioteca pg-connection-string
para analisar um URL de banco de dados e criar um objeto config
. A vantagem dessa abordagem é que ela facilita a conexão com o banco de dados de back-end no Heroku e no Cloud Run.
Na próxima etapa, você passará o URL do banco de dados como variável de ambiente ao implantar o app da Web.
Implantar o aplicativo de exemplo no Cloud Run
No Cloud Shell, configure o acesso VPC sem servidor para permitir tráfego privado do Cloud Run ao Clodu SQL:
gcloud compute networks subnets create serverless-connector-subnet \ --network=default \ --range=10.0.0.0/28 \ --region=us-central1 gcloud compute networks vpc-access connectors create serverless-connector \ --region=us-central1 \ --subnet=serverless-connector-subnet
No Cloud Shell, crie uma variável de ambiente que contenha o nome da conexão da instância do Cloud SQL que você criou:
export DB_CONN_NAME=$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='value(connectionName)')
Crie uma variável de ambiente denominada
DATABASE_URL
para manter a string de conexão e se conectar ao Proxy do Cloud SQL por uma porta UNIX.export DATABASE_URL="socket:/cloudsql/${DB_CONN_NAME}?db=postgres&user=postgres&password=POSTGRES_PASSWORD"
Crie uma conta de serviço para o Cloud Run com um papel do IAM para se conectar ao banco de dados:
gcloud iam service-accounts create sa-run-db-client gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:sa-run-db-client@PROJECT_ID.iam.gserviceaccount.com \ --role=roles/cloudsql.client
Implante o app da Web no Cloud Run.
gcloud run deploy tasksapp-PROJECT_ID \ --image=$IMAGE_NAME \ --service-account=sa-run-db-client@PROJECT_ID.iam.gserviceaccount.com \ --set-env-vars=DATABASE_URL=$DATABASE_URL \ --add-cloudsql-instances $DB_CONN_NAME \ --vpc-connector serverless-connector \ --allow-unauthenticated
O comando anterior também vincula seu contêiner do Cloud Run à instância de banco de dados do Cloud SQL que você criou. O comando define uma variável de ambiente para o Cloud Run apontar para a string
DATABASE_URL
que você criou na etapa anterior.
Teste o aplicativo
No Cloud Shell, veja o URL em que o Cloud Run veicula tráfego:
gcloud run services list
Também é possível analisar o serviço do Cloud Run no Console do Google Cloud.
Verifique se o app da Web está aceitando solicitações HTTP navegando até o URL do serviço do Cloud Run.
O Cloud Run cria ou ativa um novo contêiner quando uma solicitação HTTP é enviada ao endpoint de exibição e se um contêiner ainda não estiver em execução. Isso significa que a solicitação que gera um novo contêiner pode demorar um pouco mais para ser veiculada. Pensando nesse tempo extra, considere o número de solicitações simultâneas compatíveis com seu app e quaisquer requisitos de memória específicos que ele tenha.
Para este app, você usa as configurações de simultaneidade padrão, que permitem que um serviço do Cloud Run atenda 80 solicitações simultaneamente a partir de um único contêiner.
Limpeza
Para evitar cobranças dos recursos usados neste tutorial na sua conta do Google Cloud, siga estas etapas. Você talvez queira excluir também os recursos criados no Heroku para este tutorial.
Excluir o projeto do Google Cloud
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Excluir o app Heroku
Para excluir o app de exemplo implantado no Heroku e o complemento do PostgreSQL associado, execute o seguinte comando:
heroku apps:destroy -a APP_NAME
A seguir
- Saiba mais sobre como importar dados para o Cloud SQL.
- Consulte a documentação do Cloud Run.