Implantar o processamento de imagens usando microsserviços e mensagens assíncronas

Last reviewed 2023-07-17 UTC

Neste documento, descrevemos como implementar a arquitetura de referência descrita em Integrar microsserviços com o Pub/Sub e o GKE. A arquitetura foi projetada para processar processos de longa duração usando contêineres e mensagens assíncronas.

O documento usa um exemplo de aplicativo de compartilhamento de fotos que gera miniaturas de fotos. Implante o aplicativo usando o Google Kubernetes Engine (GKE) e use o Pub/Sub para invocar processos de longa duração de forma assíncrona. Você também usa as notificações do Pub/Sub para o Cloud Storage para adicionar jobs secundários sem modificar o código do aplicativo.

O aplicativo é conteinerizado pelo Cloud Build e armazenado no Artifact Registry. Ele usa o Cloud Vision para detectar imagens inadequadas.

Arquitetura

O diagrama a seguir ilustra o design do aplicativo de álbum de fotos de exemplo que implementa a arquitetura de referência.

Arquitetura do aplicativo de álbum de fotos.

Figura 1. Arquitetura para processamento de imagens baseada no uso de contêineres e mensagens assíncronas.

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.

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

Arquitetura do processo de extração de miniaturas.

Figura 2. Arquitetura do processo 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 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.

Quando terminar de criar o aplicativo de exemplo, você poderá evitar a cobrança contínua excluindo os recursos criados. Saiba mais em 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 a cobrança está ativada para o seu projeto do Google Cloud.

  4. Ative as APIs GKE, Cloud SQL, Cloud Build, Artifact Registry, 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 a cobrança está ativada para o seu projeto do Google Cloud.

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

    Ative as APIs

  8. No Console do Google Cloud, ative o Cloud Shell.

    Ativar o Cloud Shell

    Na parte inferior do Console do Google 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.

Configure 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 Google Cloud:

    gcloud config set project PROJECT_ID
    

    Substitua PROJECT_ID pelo ID do projeto do Google Cloud.

  2. Defina a região padrão do Compute Engine:

    gcloud config set compute/region REGION
    export REGION=REGION
    

    Substitua REGION por uma região próxima a você. Para mais informações, consulte Regiões e zonas.

  3. Configure sua zona padrão do Compute Engine:

    gcloud config set compute/zone ZONE
    export ZONE=ZONE
    

    Substitua ZONE por uma zona próxima a você.

  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
    

Criar um bucket do Cloud Storage e fazer 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 está sendo criada, a seguinte imagem de marcador de posição default.png é exibida no aplicativo de álbum de fotos.

      A 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_8_0
    
  2. Recuperar o nome da conexão:

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

    Anote o nome, porque você o usará mais tarde.

  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 senha que você configurou na etapa anterior.

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

    create database photo_db;
    create user 'appuser'@'%' identified by 'pas4appuser';
    grant all on photo_db.* to 'appuser'@'%' with grant option;
    flush privileges;
    
  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> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | photo_db           |
    | sys                |
    +--------------------+
    5 rows in set (0.16 sec)
    
    mysql> \t
    Outfile disabled.
    mysql> select user from mysql.user;
    +-------------------+
    | user              |
    +-------------------+
    | appuser           |
    | cloudsqlreplica   |
    | cloudsqlsuperuser |
    | root              |
    | cloudsqlexport    |
    | cloudsqlimport    |
    | cloudsqloneshot   |
    | root              |
    | cloudsqlexport    |
    | cloudsqlimport    |
    | cloudsqloneshot   |
    | root              |
    | cloudsqlapplier   |
    | cloudsqlimport    |
    | mysql.infoschema  |
    | mysql.session     |
    | mysql.sys         |
    | root              |
    +-------------------+
    18 rows in set (0.16 sec)
    
    mysql> exit
    Bye
    

Criar um tópico do 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.

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 cujo valor STATUS é Ready:

    NAME                                                STATUS   ROLES    AGE     VERSION
    gke-photoalbum-cluster-default-pool-d637570a-2pfh   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-3rm4   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-f7l4   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-qb2z   Ready    <none>   2m53s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-rvnp   Ready    <none>   2m54s   v1.24.10-gke.2300
    

Criar o repositório do Artifact Registry

  • No Cloud Shell, crie um novo repositório para armazenar imagens de contêiner:

    gcloud artifacts repositories create photoalbum-repo \
        --repository-format=docker \
        --location=us-central1 \
        --description="Docker repository"
    

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 \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/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 \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/thumbnail-worker
    

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 \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/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 \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/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 pod photoalbum-app e thumbail-worker e se o valor STATUS é 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
    

    Os pods thumbnail-worker inscrevem solicitações de geração de miniaturas da assinatura thumbnail-workers. Para mais detalhes, veja como a função callback é usada no código-fonte.

  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 do serviço photoalbum-service. Pode levar alguns minutos até que todos os serviços estejam 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 mais tarde. No exemplo, o atributo é 146.148.111.115.

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, clique em Fazer upload.

    A miniatura do marcador de espaço exibida enquanto você espera o serviço gerar uma miniatura exclusiva.

    O marcador de espaço em miniatura é exibido na tela.

    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.

    A miniatura com os rótulos de imagem associados.

    Para ver a imagem original, clique na miniatura.

Adicionar um recurso de detecção de imagem inadequada

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 do 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.

O aplicativo de fotos aciona o gerador de miniaturas e o verificador de imagens de forma assíncrona. Como resultado, não há garantia de que eles serão executados em uma ordem específica. Se a geração da miniatura ocorrer antes que a imagem seja desfocada, é possível que você veja uma miniatura inadequada por um tempo. No entanto, o verificador de imagens acaba desfocando a imagem inadequada e a miniatura inadequada.

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 us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/safeimage-worker
    
  2. Atualize os manifestos de implantação do Kubernetes para o serviço de imagem segura com o ID do projeto do Google Cloud, o nome da conexão do Cloud SQL e os resumos da imagem do contêiner:

    digest_safeimage=$(gcloud container images describe \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/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 safeimage-worker cujo valor STATUS é 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
    

    Os pods safeimage-worker inscrevem ro solicitações de detecção de imagem inadequadas da assinatura safeimage-workers. Para mais detalhes, veja como a função callback é usada no código-fonte.

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 é a foto de uma menina vestida como 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.

    Uma miniatura desfocada.

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

Limpeza

Se você não quiser manter os recursos do Google Cloud criados para o aplicativo de exemplo, remova-os para não ser cobrado por eles no futuro. É possível excluir todo o projeto ou remover recursos do cluster e, depois, excluir o cluster.

Excluir o projeto

  1. No Console do Google 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, você pode excluir os recursos individuais criados.

  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 o repositório do Artifact Registry:

    gcloud artifacts repositories delete photoalbum-repo --location us-central1 --quiet
    
  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