Como integrar microsserviços com o Pub/Sub e o GKE

Neste tutorial, você implantará um aplicativo de compartilhamento de fotos no Google Kubernetes Engine (GKE), onde aprenderá a usar o Pub/Sub para invocar processos de longa duração de forma assíncrona. Você também aprenderá a usar as notificações do Pub/Sub para Cloud Storage para adicionar jobs secundários sem modificar o código do aplicativo. O aplicativo é conteinerizado pelo Cloud Build e armazenado no Container Registry. Além disso, ele usa o Cloud Vision para detectar imagens impróprias.

Ao projetar um aplicativo da Web com base em uma arquitetura de microsserviços, você decide como dividir os recursos do seu aplicativo em microsserviços e como chamá-los do seu aplicativo. Para serviços demorados, convém usar chamadas de serviço assíncronas. Este tutorial é destinado a desenvolvedores e arquitetos que querem implementar microsserviços de maneira assíncrona usando tecnologias modernas, incluindo o GKE e o Pub/Sub.

Os relatórios State of DevOps identificaram recursos que impulsionam o desempenho da entrega de software. Neste tutorial, você terá ajuda com o recurso de arquitetura.

Padrão de arquitetura para um aplicativo de geração de miniaturas

O diagrama a seguir ilustra um cenário de exemplo em que um aplicativo gera imagens em miniatura.

A arquitetura do aplicativo foi implantada no Compute Engine.

No diagrama anterior, o aplicativo recebe arquivos de imagem dos clientes e gera miniaturas automaticamente. Atualmente, esse aplicativo é implementado com instâncias de máquina virtual (VM, na sigla em inglês) no Compute Engine e com armazenamento de arquivos de back-end no Cloud Storage. O Cloud Load Balancing distribui solicitações para várias VMs.

Para reduzir a sobrecarga operacional e manter as VMs, migre esse sistema para uma nova arquitetura que não use VMs.

A nova arquitetura, ilustrada no diagrama a seguir, consiste em vários serviços gerenciados.

Arquitetura do aplicativo implantado sem VMs.

Nessa nova arquitetura, o cliente envia uma imagem para o aplicativo diretamente para o Cloud Storage. Em seguida, as notificações do Pub/Sub colocam uma mensagem na fila de mensagens do Pub/Sub. A mensagem chama um microsserviço executado no GKE. O microsserviço recupera a imagem do Cloud Storage, gera uma miniatura e faz o upload dela para o Cloud Storage.

Essa nova arquitetura tem as seguintes vantagens:

  • Escalonabilidade independente: na arquitetura original, o aplicativo executado no Compute Engine oferece dois recursos principais. Um recebe arquivos, e o outro gera uma miniatura da imagem original. Receber arquivos enviados consome largura de banda de rede, enquanto a geração de miniaturas é uma tarefa que consome muita CPU. As instâncias do Compute Engine podem ficar sem recursos de CPU para gerar imagens e ainda ter recursos de rede suficientes para receber arquivos. Na nova arquitetura, essas tarefas são compartilhadas pelo Cloud Storage e pelo GKE, tornando-as escalonáveis de maneira independente.
  • Uso eficiente de recursos: na arquitetura original, escalonar horizontalmente as instâncias do Compute Engine consome mais recursos para executar sistemas operacionais. Com o GKE, você pode usar de forma eficiente os recursos do servidor que executam vários contêineres em apenas alguns servidores (bin packing). Você pode escalonar os contêineres com agilidade, de modo que a nova arquitetura possa lidar com uma súbita explosão de carga alta e escalonar rapidamente quando estiver pronta.
  • Fácil de adicionar novas funcionalidades: na arquitetura original, se você quiser adicionar funcionalidades, precisará implantá-las nas mesmas instâncias do Compute Engine. Na nova arquitetura, é possível desenvolver um aplicativo, como um remetente de e-mail, para notificá-lo quando uma nova miniatura for gerada. O Pub/Sub pode se conectar aos aplicativos de geração de miniaturas e remetentes de e-mail de maneira assíncrona sem modificar o código original nas instâncias do Compute Engine.
  • Acoplamento reduzido: na arquitetura antiga, um problema comum é o acoplamento temporal. Se um servidor de retransmissão de e-mails estiver desativado, o aplicativo tentará enviar uma notificação, mas ela falhará. Esses processos estão altamente associados e um cliente pode não receber uma resposta bem-sucedida do aplicativo. Na nova arquitetura, o cliente recebe uma resposta bem-sucedida porque a geração de uma miniatura e o envio de uma notificação são levemente associados.

Essa nova arquitetura tem as seguintes desvantagens:

  • Esforço extra para modernizar o aplicativo: colocar um aplicativo em um contêiner exige tempo e esforço. A nova arquitetura usa mais serviços e requer uma abordagem diferente de observação, que inclui alterações no monitoramento do aplicativo, no processo de implantação e no gerenciamento de recursos.
  • Manipulação da duplicação de miniaturas no aplicativo: o Pub/Sub garante pelo menos uma entrega de mensagens, o que significa que mensagens duplicadas podem ser enviadas.

Sobre o aplicativo de álbum de fotos

O diagrama a seguir mostra o design inicial do aplicativo de álbum de fotos.

Arquitetura do aplicativo de álbum de fotos.

O diagrama anterior ilustra como a miniatura é gerada:

  1. Um cliente faz o upload de uma imagem para o aplicativo.
  2. O aplicativo armazena a imagem no Cloud Storage.
  3. Uma solicitação é gerada para a miniatura.
  4. O gerador de miniaturas gera a miniatura.
  5. A resposta bem-sucedida é enviada ao aplicativo de álbum de fotos.
  6. A resposta bem-sucedida é enviada ao cliente, e é possível encontrar a miniatura no Cloud Storage.

Depois de implantar o aplicativo, você enfrenta os seguintes problemas:

  • O aplicativo leva muito tempo para gerar a miniatura. Como resultado, os clientes estão passando por muitos tempos limite.
  • A equipe de gerenciamento de serviços quer detectar conteúdo enviado de forma inadequada. Mas a equipe do aplicativo não tem recursos suficientes para implementar o recurso neste momento.

O diagrama a seguir extrai a geração de miniaturas como um serviço separado de maneira assíncrona.

Arquitetura de extração de miniaturas.

Você usa o Pub/Sub para enviar solicitações de serviço ao serviço de geração de miniaturas. Essa nova arquitetura torna a chamada de serviço assíncrona para que uma miniatura seja criada em segundo plano depois que o aplicativo envia a resposta de volta para um cliente. Esse design também permite que o serviço de geração de miniaturas seja escalonado para que vários jobs possam ser executados em paralelo.

Objetivos

  • Implantar um aplicativo de álbum de fotos de exemplo no GKE.
  • Fazer chamadas de serviço assíncronas do aplicativo.
  • Usar as notificações do Pub/Sub para o Cloud Storage para acionar o aplicativo quando um novo arquivo for enviado para o bucket do Cloud Storage.
  • Usar o Pub/Sub para executar mais tarefas sem modificar o aplicativo.

Custos

Neste tutorial, usamos 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.

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Limpeza.

Antes de começar

  1. Faça login na sua conta do Google Cloud. Se você começou a usar o Google Cloud agora, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  2. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  3. Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como verificar se o faturamento está ativado em um projeto.

  4. Ative as APIs GKE, Cloud SQL, Cloud Build, and Cloud Vision.

    Ative as APIs

  5. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  6. Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como verificar se o faturamento está ativado em um projeto.

  7. Ative as APIs GKE, Cloud SQL, Cloud Build, and Cloud Vision.

    Ative as APIs

  8. No console, ative o Cloud Shell.

    Ativar o Cloud Shell

    Na parte inferior do console do Cloud, uma sessão do Cloud Shell é iniciada e exibe um prompt de linha de comando. O Cloud Shell é um ambiente shell com a CLI do Google Cloud já instalada e com valores já definidos para o projeto atual. A inicialização da sessão pode levar alguns segundos.

Como configurar o ambiente

Nesta seção, você atribui configurações padrão para valores usados ao longo do documento. Se você fechar a sessão do Cloud Shell, perderá essas configurações de ambiente.

  1. No Cloud Shell, defina seu projeto padrão do Cloud, substituindo project-id pelo ID do projeto do Google Cloud:

    gcloud config set project project-id
    
  2. Defina a região padrão do Compute Engine, substituindo region por uma região próxima a você. Para mais informações, consulte Regiões e zonas.

    gcloud config set compute/region region
    export REGION=region
    
  3. Defina a zona padrão do Compute Engine, substituindo zone por uma zona próxima a você:

    gcloud config set compute/zone zone
    export ZONE=zone
    
  4. Faça o download dos arquivos de exemplo e defina seu diretório atual.

    git clone https://github.com/GoogleCloudPlatform/gke-photoalbum-example
    cd gke-photoalbum-example
    

Como criar um bucket do Cloud Storage e fazer o upload da imagem de miniatura padrão

  1. No Cloud Shell, crie um bucket do Cloud Storage para armazenar as imagens e as miniaturas originais:

    export PROJECT_ID=$(gcloud config get-value project)
    gsutil mb -c regional -l ${REGION} gs://${PROJECT_ID}-photostore
    
  2. Faça o upload do arquivo de miniatura padrão:

    gsutil cp ./application/photoalbum/images/default.png \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    
    • As imagens enviadas são armazenadas no seguinte formato: gs://project-id-photostore/filename, em que filename representa o nome do arquivo de imagem que é carregado.
    • As miniaturas geradas são armazenadas no seguinte formato: gs://project-id-photostore/thumbnails/filename.
    • A imagem original e a miniatura correspondente têm o mesmo valor filename, mas a miniatura é armazenada no bucket thumbnails.
    • Enquanto a miniatura é criada, a imagem da miniatura do marcador default.png é exibida no aplicativo de álbum de fotos.

      Imagem em miniatura do marcador de posição padrão.

  3. Tornar público o arquivo de miniatura:

    gsutil acl ch -u AllUsers:R \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    

Como criar uma instância do Cloud SQL e um banco de dados MySQL

  1. No Cloud Shell, crie a instância do Cloud SQL:

    gcloud sql instances create photoalbum-db --region=${REGION} \
        --database-version=MYSQL_5_7
    
  2. Recuperar o nome da conexão:

    gcloud sql instances describe photoalbum-db \
        --format="value(connectionName)"
    

    Anote o nome, porque você o usará posteriormente no tutorial.

  3. Defina a senha do usuário MySQL root@%.

    gcloud sql users set-password root --host=% --instance=photoalbum-db \
        --password=password
    

    Substitua password por uma senha segura para o usuário root@%.

  4. Conecte-se à instância do Cloud SQL.

    gcloud sql connect photoalbum-db --user=root --quiet
    

    Quando solicitado, digite a password que você configurou na etapa anterior.

  5. Crie um banco de dados chamado photo_db, em que o usuário é appuser com uma senha pas4appuser:

    create database photo_db;
    grant all privileges on photo_db.* to appuser@"%" \
        identified by 'pas4appuser' with grant option;
    
  6. Confirme o resultado e saia do MySQL:

    show databases;
    select user from mysql.user;
    exit
    

    Na saída, confirme se o banco de dados photo_db e o usuário appuser foram criados:

    MySQL [(none)]> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | photo_db           |
    | sys                |
    +--------------------+
    5 rows in set (0.16 sec)
    
    MySQL [(none)]> select user from mysql.user;
    +-----------+
    | user      |
    +-----------+
    | appuser   |
    | root      |
    | mysql.sys |
    +-----------+
    3 rows in set (0.16 sec)
    
    MySQL [(none)]> exit
    Bye
    

Como criar um tópico de Pub/Sub e uma assinatura

  1. No Cloud Shell, crie um tópico Pub/Sub chamado thumbnail-service:

    gcloud pubsub topics create thumbnail-service
    

    O aplicativo de álbum de fotos envia solicitações para o serviço de geração de miniaturas publicando uma mensagem no tópico thumbnail-service.

  2. Crie uma assinatura do Pub/Sub chamada thumbnail-workers:

    gcloud pubsub subscriptions create --topic thumbnail-service thumbnail-workers
    

    O serviço de geração de miniaturas recebe solicitações da assinatura thumbnail-workers.

Como criar um cluster do GKE

  1. No Cloud Shell, crie um cluster do GKE com permissão para chamar APIs:

    gcloud container clusters create "photoalbum-cluster" \
        --scopes "https://www.googleapis.com/auth/cloud-platform" \
        --num-nodes "5"
    
  2. Receba as credenciais de acesso configuradas para gerenciar o cluster usando o comando kubectl em etapas posteriores:

    gcloud container clusters get-credentials photoalbum-cluster
    
  3. Mostre a lista de nós:

    kubectl get nodes
    

    Na saída, confirme se há cinco nós com STATUS de Ready:

    NAME                                                STATUS    ROLES     AGE       VERSION
    gke-photoalbum-cluster-default-pool-0912a91a-24vt   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-5h1n   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-gdm9   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-swv6   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-thv8   Ready     <none>    6m        v1.9.7-gke.6
    

Como criar imagens para o aplicativo

  1. Em um editor de texto, abra o arquivo application/photoalbum/src/auth_decorator.py e atualize o nome de usuário e a senha:

    USERNAME = 'username'
    PASSWORD = 'passw0rd'
    
  2. No Cloud Shell, crie uma imagem para o aplicativo de álbum de fotos usando o serviço Cloud Build:

    gcloud builds submit ./application/photoalbum -t \
        gcr.io/${PROJECT_ID}/photoalbum-app
    
  3. Crie uma imagem para o serviço de geração de miniaturas thumbnail-worker usando o serviço Cloud Build:

    gcloud builds submit ./application/thumbnail -t \
        gcr.io/${PROJECT_ID}/thumbnail-worker
    

Como implantar o aplicativo de álbum de fotos

  1. No Cloud Shell, atualize os manifestos de implantação do Kubernetes para o álbum de fotos e o gerador de miniaturas com os valores do seu ambiente:

    connection_name=$(gcloud sql instances describe photoalbum-db \
        --format "value(connectionName)")
    
    digest_photoalbum=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/photoalbum-app:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_photoalbum}/" \
        config/photoalbum-deployment.yaml
    
    digest_thumbnail=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/thumbnail-worker:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_thumbnail}/" \
            config/thumbnail-deployment.yaml
    
  2. Crie recursos de implantação para iniciar o aplicativo de álbum de fotos e o serviço de geração de miniaturas:

    kubectl create -f config/photoalbum-deployment.yaml
    kubectl create -f config/thumbnail-deployment.yaml
    
  3. Crie um recurso de serviço para atribuir um endereço IP externo ao aplicativo:

    kubectl create -f config/photoalbum-service.yaml
    
  4. Verifique os resultados dos pods:

    kubectl get pods
    

    Na saída, confirme se há três pods para cada photoalbum-app e thumbail-worker com STATUS de Running:

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-728k5   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-hqxqr   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-xnxhc   2/2       Running   0          2m
    
  5. Verifique os resultados dos serviços:

    kubectl get services
    

    Na saída, confirme se há um endereço IP externo na coluna EXTERNAL-IP para photoalbum-service. Pode levar alguns minutos até que todos estejam configurados e em execução.

    NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
    kubernetes           ClusterIP      10.23.240.1     <none>            443/TCP        20m
    photoalbum-service   LoadBalancer   10.23.253.241   146.148.111.115   80:32657/TCP   2m
    

    Anote o endereço IP externo, porque ele será usado posteriormente neste tutorial. Neste exemplo, é 146.148.111.115.

Como testar o aplicativo de álbum de fotos

  1. Para acessar o aplicativo implantado em um navegador da Web, acesse o seguinte URL e digite o nome de usuário e a senha que você configurou anteriormente:

    http://external-ip
    

    Substitua external-ip pelo endereço IP que você copiou na etapa anterior.

  2. Para fazer upload de um arquivo de imagem de sua escolha, clique em Fazer upload. O marcador de espaço em miniatura é exibido na tela.

    Miniatura de marcador enquanto você aguarda o serviço gerar uma miniatura exclusiva.

    Em segundo plano, o serviço de geração de miniaturas cria uma miniatura da imagem enviada. Para ver a miniatura gerada, clique em Atualizar. A API Cloud Vision adiciona rótulos de imagem que são detectados.

    Miniatura com rótulos de imagem associados.

    Para ver a imagem original, clique na miniatura.

Como adicionar um recurso de detecção de imagem inadequado

A imagem a seguir ilustra como usar as notificações do Pub/Sub para o Cloud Storage para acionar um serviço que detecta conteúdo impróprio. Esse recurso desfoca a imagem quando um novo arquivo com conteúdo inadequado é armazenado no bucket do Cloud Storage.

Arquitetura de recurso de conteúdo inadequado.

Na imagem anterior, o serviço usa o recurso Detecção de pesquisa segura da API Vision para detectar conteúdo impróprio em uma imagem.

Criar um tópico, uma assinatura e uma notificação do Pub/Sub

  1. No Cloud Shell, crie um tópico Pub/Sub chamado safeimage-service:

    gcloud pubsub topics create safeimage-service
    
  2. Crie uma assinatura do Pub/Sub chamada safeimage-workers:

    gcloud pubsub subscriptions create --topic safeimage-service \
        safeimage-workers
    
  3. Configure uma notificação do Pub/Sub para que uma mensagem seja enviada ao tópico safeimage-service quando um novo arquivo for enviado para o bucket do Cloud Storage:

    gsutil notification create -t safeimage-service -f json \
        gs://${PROJECT_ID}-photostore
    

Criar e implantar a imagem do worker

  1. No Cloud Shell, crie uma imagem de contêiner para a assinatura safeimage-workers usando o Cloud Build:

    gcloud builds submit ./application/safeimage \
        -t gcr.io/${PROJECT_ID}/safeimage-worker
    
  2. Atualize os manifestos de implantação do Kubernetes para o serviço de imagem segura com o ID do projeto do Cloud, o nome da conexão do Cloud SQL e os resumos da imagem do contêiner:

    digest_safeimage=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/safeimage-worker:latest --format \
        "value(image_summary.digest)")
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_safeimage}/" \
        config/safeimage-deployment.yaml
    

Criar um recurso de implantação

  1. Crie um recurso de implantação chamado safeimage-deployment para implantar o tópico safeimage-service:

    kubectl create -f config/safeimage-deployment.yaml
    
  2. Verifique os resultados:

    kubectl get pods
    

    Na saída, confirme se há três pods de safeimage-worker com STATUS de Running.

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   8          30m
    safeimage-worker-7dc8c84f54-6sqzs   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-9bskw   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-b7gtp   1/1       Running   0          2m
    thumbnail-worker-86bd95cd68-9wrpv   2/2       Running   0          30m
    thumbnail-worker-86bd95cd68-kbhsn   2/2       Running   2          30m
    thumbnail-worker-86bd95cd68-n4rj7   2/2       Running   0          30m
    

Testar o recurso de detecção de imagem imprópria

Nesta seção, você faz o upload de uma imagem de teste para verificar se o recurso Safe Detection Search Detection desfoca uma imagem imprópria. A imagem de teste é uma imagem de uma menina vestida como um zumbi (licenciada sob uma licença CC0 da Pixaby).

  1. Faça o download da imagem de teste.
  2. Para fazer upload da imagem, acesse http://external-ip e clique em Upload.
  3. Clique em Atualizar. O aplicativo exibe uma miniatura desfocada.

    Miniatura desfocada.

    Para ver se a imagem enviada também está desfocada, clique na miniatura.

Limpeza

A maneira mais fácil de eliminar o faturamento é excluir o projeto do Cloud criado para o tutorial. A outra opção é excluir os recursos individuais.

Excluir o projeto

  1. No console, acesse a página Gerenciar recursos.

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir recursos individuais

Em vez de excluir o projeto, exclua os recursos criados neste tutorial.

  1. Exclua recursos do GKE:

    kubectl delete -f config/safeimage-deployment.yaml
    kubectl delete -f config/photoalbum-service.yaml
    kubectl delete -f config/thumbnail-deployment.yaml
    kubectl delete -f config/photoalbum-deployment.yaml
    
  2. Exclua o cluster do GKE:

    gcloud container clusters delete photoalbum-cluster --quiet
    
  3. Exclua imagens do Container Registry:

    gcloud container images delete safeimage-worker
    gcloud container images delete thumbnail-worker
    gcloud container images delete photoalbum-app
    
  4. Exclua assinaturas e tópicos do Pub/Sub:

    gcloud pubsub subscriptions delete safeimage-workers
    gcloud pubsub topics delete safeimage-service
    gcloud pubsub subscriptions delete thumbnail-workers
    gcloud pubsub topics delete thumbnail-service
    
  5. Exclua a instância do Cloud SQL:

    gcloud sql instances delete photoalbum-db --quiet
    
  6. Exclua o bucket do Cloud Storage:

    gsutil rm -r gs://${PROJECT_ID}-photostore
    gsutil rm -r gs://${PROJECT_ID}_cloudbuild
    
  7. Exclua os arquivos:

    cd ..
    rm -rf gke-photoalbum-example
    

A seguir