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 deles está recebendo arquivos, e o outro está gerando 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, é possível usar com eficiência os recursos do servidor que executam vários contêineres em poucos servidores (agrupamento por classes). É possível escalonar horizontalmente os contêineres com agilidade, de modo que a nova arquitetura possa lidar com um súbito burst de carga alta e reduzir o escalonamento horizontal 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 ser 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 Como fazer a 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 confirmar se o faturamento está ativado para o projeto.

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

    Ative as APIs

  5. No Console do Cloud, 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 com o SDK do Cloud pré-instalado com a ferramenta de linha de comando gcloud e os valores já definidos para seu 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 a mesma 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 do Cloud, 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