Como automatizar otimizações de custos com o Cloud Functions, o Cloud Scheduler e o Cloud Monitoring


Neste documento, mostramos como usar o Cloud Functions para identificar e limpar recursos de nuvem desperdiçados, programar funções para são executadas com o Cloud Scheduler e usam políticas de alertas do Cloud Monitoring para executá-las com base no uso observado. Este tutorial é destinado a desenvolvedores, SREs, arquitetos de nuvem e administradores de infraestrutura em nuvem que buscam uma abordagem sistematizada e automatizada para identificar e reduzir gastos desnecessários na nuvem.

Ele pressupõe que você esteja familiarizado com os seguintes produtos:

Objetivos

  • Excluir endereços IP não utilizados: no Google Cloud, os endereços IP estáticos são um recurso gratuito quando estão anexados a um balanceador de carga ou instância de máquina virtual (VM, na sigla em inglês). Quando um endereço IP estático é reservado, mas não é usado, ele acumula uma cobrança por hora. No caso de apps que dependem muito de endereços IP estáticos e de provisionamento dinâmico de grande escala, talvez haja um desperdício considerável ao longo do tempo.
  • Excluir discos permanentes órfãos ou não utilizados: os discos permanentes não serão usados ou serão órfãos se forem criados sem serem anexados a uma VM, ou se uma máquina tiver vários discos, com um ou mais deles removidos.
  • Migrar para classes de armazenamento mais baratas: o Google Cloud oferece várias classes de armazenamento de objetos. Use aquela que melhor atende às suas necessidades.

Arquitetura

O diagrama a seguir descreve a primeira parte da implantação, em que você programa uma Função do Cloud para identificar e limpar endereços IP não utilizados.

Arquitetura de uma Função do Cloud que identifica e limpa endereços IP não utilizados.

No primeiro exemplo, abordamos as seguintes tarefas:

  • Criação de uma VM do Compute Engine com um endereço IP externo estático e um endereço IP externo estático separado não utilizado.
  • Implantação de uma Função do Cloud para identificar endereços não utilizados.
  • Criação de um job do Cloud Scheduler para programar a execução da função usando um gatilho HTTP.

No diagrama a seguir, você programa uma Função do Cloud para identificar e limpar discos permanentes não anexados e órfãos.

Arquitetura de uma Função do Cloud que identifica e limpa discos permanentes não utilizados.

No segundo exemplo, abordamos as seguintes tarefas:

  • Criação de uma VM do Compute Engine com dois discos permanentes e um disco permanente separado removido. Um dos discos é órfão porque não está anexado à VM.
  • Implantação de uma Função do Cloud para identificar discos permanentes não anexados e órfãos.
  • Criação de um job do Cloud Scheduler para programar a execução da Função do Cloud usando um gatilho HTTP.

No diagrama a seguir, você aciona uma Função do Cloud para migrar um bucket de armazenamento para uma classe de armazenamento mais barata com base em uma política de alertas do Monitoring.

Arquitetura de uma Função do Cloud que migra um bucket de armazenamento.

No terceiro exemplo, abordamos as seguintes tarefas:

  • Criação de dois buckets de armazenamento, adição de um arquivo ao bucket de exibição e geração do tráfego nele.
  • Criação de um painel do Monitoring para visualizar a utilização do bucket.
  • Implantação de uma Função do Cloud para migrar o bucket inativo para uma classe de armazenamento mais barata.
  • Acionamento da função usando um payload destinado a simular uma notificação recebida de uma política de alertas do Monitoring.

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.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo 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 Compute Engine, Cloud Functions, and Cloud Storage.

    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 Compute Engine, Cloud Functions, and Cloud Storage.

    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.

  9. Você executa todos os comandos deste documento no Cloud Shell.

Como configurar o ambiente

Nesta seção, você configurará a infraestrutura e as identidades necessárias para essa arquitetura.

  1. No Cloud Shell, clone o repositório e mude para o gcf-automated-resource-cleanup:

    git clone https://github.com/GoogleCloudPlatform/gcf-automated-resource-cleanup.git && cd gcf-automated-resource-cleanup/
    
  2. Defina as variáveis de ambiente e torne a pasta do repositório sua pasta $WORKDIR, em que você executa todos os comandos:

    export PROJECT_ID=$(gcloud config list \
        --format 'value(core.project)' 2>/dev/null)
        WORKDIR=$(pwd)
    
  3. Instale o Apache Bench (em inglês), uma ferramenta de geração de carga de código aberto:

    sudo apt-get install apache2-utils
    

Como limpar endereços IP não utilizados

Nesta seção, você concluirá as seguintes etapas:

  • Criar dois endereços IP estáticos.
  • Criar uma VM que use um endereço IP estático.
  • Revisar o código do Cloud Functions.
  • Implantar a Função do Cloud.
  • Testar a Função do Cloud usando jobs do Cloud Scheduler.

Criar endereços IP

  1. No Cloud Shell, mude para o diretório unused-ip:

    cd $WORKDIR/unused-ip
    
  2. Exporte os nomes dos endereços IP como variáveis:

    export USED_IP=used-ip-address
    export UNUSED_IP=unused-ip-address
    
  3. Crie dois endereços IP estáticos:

    gcloud compute addresses create $USED_IP \
        --project=$PROJECT_ID --region=us-central1
    gcloud compute addresses create $UNUSED_IP \
        --project=$PROJECT_ID --region=us-central1
    

    Este exemplo usa a região us-central1, mas é possível escolher uma região diferente e referenciá-la consistentemente ao restante deste documento.

  4. Confirme que dois endereços foram criados:

    gcloud compute addresses list --filter="region:(us-central1)"
    

    Na saída, o status RESERVED significa que os endereços IP não estão em uso:

    NAME               ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    unused-ip-address  35.232.144.85  EXTERNAL  us-central1          RESERVED
    used-ip-address    104.197.56.87  EXTERNAL  us-central1          RESERVED
    
  5. Defina o endereço IP utilizado como uma variável de ambiente:

    export USED_IP_ADDRESS=$(gcloud compute addresses describe $USED_IP \
        --region=us-central1 --format=json | jq -r '.address')
    

Criar uma VM

  1. No Cloud Shell, crie uma instância:

    gcloud compute instances create static-ip-instance \
        --zone=us-central1-a \
        --machine-type=n1-standard-1 \
        --subnet=default \
        --address=$USED_IP_ADDRESS
    
  2. Confirme se um dos endereços IP agora está em uso:

    gcloud compute addresses list --filter="region:(us-central1)"
    

    A saída é semelhante a esta:

    NAME               ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    unused-ip-address  35.232.144.85  EXTERNAL  us-central1          RESERVED
    used-ip-address    104.197.56.87  EXTERNAL  us-central1          IN_USE
    

Revisar o código da Função do Cloud

  • No Cloud Shell, gere a seção principal do código:

    cat $WORKDIR/unused-ip/function.js | grep "const compute" -A 31
    

    A saída é a seguinte:

    const compute = new Compute();
    compute.getAddresses(function(err, addresses){ // gets all addresses across regions
         if(err){
             console.log("there was an error: " + err);
         }
         if (addresses == null) {
             console.log("no addresses found");
             return;
         }
         console.log("there are " + addresses.length + " addresses");
    
         // iterate through addresses
         for (let item of addresses){
    
              // get metadata for each address
              item.getMetadata(function(err, metadata, apiResponse) {
    
                  // if the address is not used AND if it's at least ageToDelete days old:
                  if ((metadata.status=='RESERVED') & (calculateAge(metadata.creationTimestamp) >= ageToDelete)){
                      // delete address
                      item.delete(function(err, operation, apiResponse2){
                          if (err) {
                              console.log("could not delete address: " + err);
                          }
                      })
                  }
              })
          }
           // return number of addresses evaluated
          res.send("there are " + addresses.length + " total addresses");
      });
    }
    

    No exemplo de código anterior, observe o seguinte:

    • compute.getAddresses(function(err, addresses){ // gets all addresses across regions
      

      Usa o método getAddresses para recuperar os endereços IP em todas as regiões do projeto.

    • // get metadata for each address
      item.getMetadata(function(err, metadata, apiResponse) {
         // if the address is not used:
             if (metadata.status=='RESERVED'){
      

      Recebe os metadados de cada endereço IP e verifica o campo STATUS.

    • if ((metadata.status=='RESERVED') &
      (calculateAge(metadata.creationTimestamp) >= ageToDelete)){
      

      Verifica se o endereço IP está em uso, calcula a duração dele usando uma função auxiliar e compara essa duração com uma constante, definida como 0 para a finalidade do tutorial.

    • // delete address
      item.delete(function(err, operation, apiResponse2){
      

      Exclui o endereço IP.

Implantar a Função do Cloud

  1. No Cloud Shell, implante a Função do Cloud:

    gcloud functions deploy unused_ip_function --trigger-http --runtime=nodejs8
    
  2. Defina o URL do gatilho como uma variável de ambiente:

    export FUNCTION_URL=$(gcloud functions describe unused_ip_function \
        --format=json | jq -r '.httpsTrigger.url')
    

Programar e testar a Função do Cloud

  1. No Cloud Shell, crie uma tarefa do Cloud Scheduler para executar a Função do Cloud todos os dias às 2h:

    gcloud scheduler jobs create http unused-ip-job \
        --schedule="* 2 * * *" \
        --uri=$FUNCTION_URL
    
  2. Acione o job manualmente para testá-lo:

    gcloud scheduler jobs run unused-ip-job
    
  3. Confirme que o endereço IP não utilizado foi excluído:

    gcloud compute addresses list --filter="region:(us-central1)"
    

    A saída é semelhante a esta:

    NAME             ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    used-ip-address  104.197.56.87  EXTERNAL  us-central1          IN_USE
    

Como limpar discos permanentes não utilizados e órfãos

Nesta seção, você concluirá as seguintes etapas:

  • Criar dois discos permanentes.
  • Criar uma VM que use um dos discos
  • Desconectar o disco da VM
  • Revisar o código da função do Cloud
  • Implantar a função do Cloud
  • Testar a Função do Cloud usando jobs do Cloud Scheduler.

Criar discos permanentes

  1. No Cloud Shell, mude para o diretório unattached-pd:

    cd $WORKDIR/unattached-pd
    
  2. Exporte os nomes dos discos como variáveis de ambiente:

    export ORPHANED_DISK=orphaned-disk
    export UNUSED_DISK=unused-disk
    
  3. Crie os dois discos:

    gcloud beta compute disks create $ORPHANED_DISK \
       --project=$PROJECT_ID \
       --type=pd-standard \
       --size=500GB \
       --zone=us-central1-a
    gcloud beta compute disks create $UNUSED_DISK \
        --project=$PROJECT_ID \
        --type=pd-standard \
        --size=500GB \
        --zone=us-central1-a
    
  4. Confirme se os dois discos foram criados:

    gcloud compute disks list
    

    A saída é a seguinte:

    NAME                LOCATION       LOCATION_SCOPE SIZE_GB TYPE         STATUS
    orphaned-disk       us-central1-a  zone           500     pd-standard  READY
    static-ip-instance  us-central1-a  zone           10      pd-standard  READY
    unused-disk         us-central1-a  zone           500     pd-standard  READY
    

Criar uma VM e inspecionar os discos

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

    gcloud compute instances create disk-instance \
        --zone=us-central1-a \
        --machine-type=n1-standard-1 \
        --disk=name=$ORPHANED_DISK,device-name=$ORPHANED_DISK,mode=rw,boot=no
    
  2. Inspecione o disco que foi anexado à VM:

    gcloud compute disks describe $ORPHANED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    A saída é semelhante a esta:

    {
      "creationTimestamp": "2019-06-12T12:21:25.546-07:00",
      "id": "7617542552306904666",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "lastAttachTimestamp": "2019-06-12T12:24:53.989-07:00",
      "name": "orphaned-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/orphaned-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "users": [
        "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/instances/disk-instance"
      ],
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    No exemplo de código anterior, observe o seguinte:

    • users identifica a VM a que o disco está anexado.
    • lastAttachTimestamp identifica quando o disco foi anexado pela última vez a uma VM.
  3. Inspecione o disco que não foi anexado a uma VM:

    gcloud compute disks describe $UNUSED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    A saída é semelhante a esta:

    {
      "creationTimestamp": "2019-06-12T12:21:30.905-07:00",
      "id": "1313096191791918677",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "name": "unused-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/unused-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    No exemplo de código anterior, observe o seguinte:

    • O disco não tem users listado porque não está atualmente em uso por uma VM.
    • O disco não tem lastAttachedTimestamp porque nunca foi usado.
  4. Remova o disco permanente órfão da VM:

    gcloud compute instances detach-disk disk-instance \
        --device-name=$ORPHANED_DISK \
        --zone=us-central1-a
    
  5. Inspecione o disco órfão:

    gcloud compute disks describe $ORPHANED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    A saída é semelhante a esta:

    {
      "creationTimestamp": "2019-06-12T12:21:25.546-07:00",
      "id": "7617542552306904666",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "lastAttachTimestamp": "2019-06-12T12:24:53.989-07:00",
      "lastDetachTimestamp": "2019-06-12T12:34:56.040-07:00",
      "name": "orphaned-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/orphaned-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    No exemplo de código anterior, observe o seguinte:

    • O disco não tem users listado, o que indica que ele não está em uso no momento.
    • Agora há uma entrada lastDetachTimestamp, indicando quando o disco foi removido da VM pela última vez e, portanto, quando foi usado pela última vez.
    • O campo lastAttachTimestamp ainda está presente.

Revisar o código da Função do Cloud

  1. No Cloud Shell, gere a seção do código que recupera todos os discos permanentes no projeto:

    cat $WORKDIR/unattached-pd/main.py | grep "(request)" -A 12
    

    A saída é a seguinte:

    def delete_unattached_pds(request):
        # get list of disks and iterate through it:
        disksRequest = compute.disks().aggregatedList(project=project)
        while disksRequest is not None:
            diskResponse = disksRequest.execute()
            for name, disks_scoped_list in diskResponse['items'].items():
                if disks_scoped_list.get('warning') is None:
                    # got disks
                    for disk in disks_scoped_list['disks']: # iterate through disks
                        diskName = disk['name']
                        diskZone = str((disk['zone'])).rsplit('/',1)[1]
                        print (diskName)
                        print (diskZone)
    

    A função usa o método aggregatedList para conseguir todos os discos permanentes no projeto do Google Cloud em que ela é executada e faz a iteração em cada um dos discos.

  2. Gere a seção do código que verifica o campo lastAttachTimestamp e exclui o disco se ele não existir:

    cat $WORKDIR/unattached-pd/main.py | grep "handle never" -A 11
    

    A saída é a seguinte:

    # handle never attached disk - delete it
    # lastAttachedTimestamp is not present
    if disk.get("lastAttachTimestamp") is None:
           print ("disk " + diskName + " was never attached - deleting")
           deleteRequest = compute.disks().delete(project=project,
                  zone=diskZone,
                  disk=diskName)
           deleteResponse = deleteRequest.execute()
           waitForZoneOperation(deleteResponse, project, diskZone)
           print ("disk " + diskName + " was deleted")
           Continue
    

    Nesta seção, o disco será excluído se lastAttachTimestamp não estiver presente. Isso significa que esse disco nunca esteve em uso.

  3. Gere a seção do código que calcula a duração do disco, se ele for órfão, cria um snapshot dele e o excluiu:

    cat $WORKDIR/unattached-pd/main.py | grep "handle detached" -A 32
    

    A saída é a seguinte:

    # handle detached disk - snapshot and delete
    # lastAttachTimestamp is present AND users is not present AND it meets the age criterium
    if disk.get("users") is None \
        and disk.get("lastDetachTimestamp") is not None \
        and diskAge(disk['lastDetachTimestamp'])>=deleteAge:
    
        print ("disk " + diskName + " has no users and has been detached")
        print ("disk meets age criteria for deletion")
    
        # take a snapshot
        snapShotName = diskName + str(int(time.time()))
        print ("taking snapshot: " + snapShotName)
        snapshotBody = {
            "name": snapShotName
        }
        snapshotRequest = compute.disks().createSnapshot(project=project,
             zone=diskZone,
             disk=diskName,
             body=snapshotBody)
        snapshotResponse = snapshotRequest.execute()
        waitForZoneOperation(snapshotResponse, project, diskZone)
        print ("snapshot completed")
    
        # delete the disk
        print ("deleting disk " + diskName)
        deleteRequest = compute.disks().delete(project=project,
            zone=diskZone,
            disk=diskName)
        deleteResponse = deleteRequest.execute()
        waitForZoneOperation(deleteResponse, project, diskZone)
        print ("disk " + diskName + " was deleted")
        continue
    

    Esta seção do código é usada quando o disco tem users listado e lastDetachTimestamp está presente, o que significa que o disco não está em uso, mas foi usado em algum momento. Neste caso, a Função do Cloud cria um snapshot do disco para reter os dados e depois exclui o disco.

Implantar a Função do Cloud

  1. No Cloud Shell, implante a Função do Cloud:

    gcloud functions deploy delete_unattached_pds \
        --trigger-http --runtime=python37
    
  2. Defina o URL do acionador da Função do Cloud como uma variável de ambiente:

    export FUNCTION_URL=$(gcloud functions describe delete_unattached_pds \
        --format=json | jq -r '.httpsTrigger.url')
    

Agende e teste a Função do Cloud

  1. No Cloud Shell, crie uma tarefa do Cloud Scheduler para executar a Função do Cloud todos os dias às 2h:

    gcloud scheduler jobs create http unattached-pd-job \
        --schedule="* 2 * * *" \
        --uri=$FUNCTION_URL
    
  2. Teste o job:

    gcloud scheduler jobs run unattached-pd-job
    
  3. Confirme se o snapshot do disco órfão foi criado:

    gcloud compute snapshots list
    

    A saída é semelhante a esta:

    NAME                     DISK_SIZE_GB  SRC_DISK                           STATUS
    orphaned-disk1560455894  500           us-central1-a/disks/orphaned-disk  READY
    
  4. Confirme se o disco não utilizado e o órfão foram excluídos:

    gcloud compute disks list
    

    A saída é a seguinte:

    NAME                LOCATION       LOCATION_SCOPE SIZE_GB  TYPE         STATUS
    disk-instance       us-central1-a  zone           10       pd-standard  READY
    static-ip-instance  us-central1-a  zone           10       pd-standard  READY
    

Como migrar buckets de armazenamento para classes de armazenamento mais baratas

O Google Cloud oferece regras de ciclo de vida de objetos de armazenamento que podem ser usadas para mover objetos automaticamente para diferentes classes de armazenamento com base em um conjunto de atributos, como data de criação ou estado ativo. No entanto, essas regras não identificam se os objetos foram acessados. Às vezes, convém mover os objetos mais recentes para o Nearline Storage se eles não foram acessados por um determinado período.

Nesta seção, você concluirá as seguintes etapas:

  • Criar dois buckets do Cloud Storage.
  • Adicionar um objeto a um dos buckets.
  • Configurar o Monitoring para observar o acesso aos objetos do bucket.
  • Revisar o código da Função do Cloud que migra os objetos de um bucket do Regional Storage para um do Nearline Storage.
  • Implantar a Função do Cloud
  • Testar a Função do Cloud usando um alerta do Monitoring.

Criar buckets do Cloud Storage e adicionar um arquivo

  1. No Cloud Shell, mude para o diretório migrate-storage:

    cd $WORKDIR/migrate-storage
    
  2. Crie o bucket do Cloud Storage serving-bucket, que será usado posteriormente para alterar as classes de armazenamento:

    export PROJECT_ID=$(gcloud config list \
        --format 'value(core.project)' 2>/dev/null)
    gsutil mb -c regional -l us-central1 gs://${PROJECT_ID}-serving-bucket
    
  3. Torne o bucket público:

    gsutil acl ch -u allUsers:R gs://${PROJECT_ID}-serving-bucket
    
  4. Adicione um arquivo de texto no bucket:

    gsutil cp $WORKDIR/migrate-storage/testfile.txt  \
        gs://${PROJECT_ID}-serving-bucket
    
  5. Torne o arquivo público:

    gsutil acl ch -u allUsers:R gs://${PROJECT_ID}-serving-bucket/testfile.txt
    
  6. Confirme se é possível acessar o arquivo:

    curl http://storage.googleapis.com/${PROJECT_ID}-serving-bucket/testfile.txt
    

    A saída é a seguinte:

    this is a test
    
  7. Crie um segundo bucket chamado idle-bucket, que não exiba dados:

    gsutil mb -c regional -l us-central1 gs://${PROJECT_ID}-idle-bucket
    

Configurar um espaço de trabalho do Cloud Monitoring

Nesta seção, você configura o Cloud Monitoring para observar o uso do bucket para entender quando os objetos do bucket não estão sendo usados. Quando o bucket de exibição não é usado, uma Função do Cloud o migra da classe do Regional Storage para a classe do Nearline Storage.

  1. No Console do Google Cloud, acesse o Monitoring.

    Acessar o Cloud Monitoring

  2. Clique em Novo espaço de trabalho e, depois, em Adicionar.

    Aguarde a conclusão da configuração inicial.

Criar um painel do Cloud Monitoring

  1. No Monitoring, acesse Painéis e clique em Criar painel.

  2. Clique em Adicionar gráfico.

  3. No campo Nome, digite Bucket Access.

  4. Para encontrar a métrica de conteúdo da solicitação para o bucket do Cloud Storage, no campo Encontrar recurso e métrica, digite request e selecione a métrica Contagem de solicitações para o recurso gcs_bucket.

  5. Para agrupar as métricas por nome de bucket, na lista suspensa Agrupar por, clique em bucket_name.

  6. Para filtrar pelo nome do método, no campo Filtro, digite ReadObject e clique em Aplicar.

  7. Clique em Salvar.

  8. No campo do nome, digite Bucket Usage.

  9. Para confirmar se o painel está acessível, mantenha o ponteiro sobre Painéis e verifique se aparece Uso do bucket.

    Você configurou o Monitoring para observar o acesso aos objetos nos buckets. O gráfico não exibe dados porque não há tráfego para os buckets do Cloud Storage.

Gerar carga no bucket de exibição

Agora que o Monitoring está configurado, use o Apache Bench para enviar tráfego ao bucket de exibição.

  1. No Cloud Shell, envie solicitações para o objeto no bucket de exibição:

    ab -n 10000 \
        http://storage.googleapis.com/$PROJECT_ID-serving-bucket/testfile.txt
    
  2. No console do Google Cloud, acesse o Monitoring.

    Acessar o Cloud Monitoring

  3. Para selecionar o painel Uso do bucket, mantenha o ponteiro sobre Painéis e selecione Uso do bucket. Confirme se há tráfego apenas para o bucket de exibição. A série temporal request_count metric é exibida apenas para o bucket de exibição, porque o bucket inativo não tem tráfego.

Revise e implante a Função do Cloud

  1. No Cloud Shell, gere o código que usa a Função do Cloud para migrar um bucket de armazenamento para a classe do Nearline Storage:

    cat $WORKDIR/migrate-storage/main.py | grep "migrate_storage(" -A 15
    

    A saída é a seguinte:

    def migrate_storage(request):
        # process incoming request to get the bucket to be migrated:
        request_json = request.get_json(force=True)
        # bucket names are globally unique
        bucket_name = request_json['incident']['resource_name']
    
        # create storage client
        storage_client = storage.Client()
    
        # get bucket
        bucket = storage_client.get_bucket(bucket_name)
    
        # update storage class
        bucket.storage_class = "NEARLINE"
        bucket.patch()
    

    A Função do Cloud usa o nome do bucket informado na solicitação para alterar a classe de armazenamento para o Nearline Storage.

  2. Implante a Função do Cloud:

    gcloud functions deploy migrate_storage --trigger-http --runtime=python37
    
  3. Defina o URL do gatilho como uma variável de ambiente que você usará na próxima seção:

    export FUNCTION_URL=$(gcloud functions describe migrate_storage \
        --format=json | jq -r '.httpsTrigger.url')
    

Testar e validar a automação de alertas

  1. Defina o nome do bucket inativo:

    export IDLE_BUCKET_NAME=$PROJECT_ID-idle-bucket
    
  2. Envie uma notificação de teste para a Função do Cloud implantada usando o arquivo incident.json:

    envsubst < $WORKDIR/migrate-storage/incident.json | curl -X POST \
        -H "Content-Type: application/json" $FUNCTION_URL -d @-
    

    A saída é a seguinte:

    OK
    

    A saída não é encerrada com uma nova linha e, portanto, é seguida imediatamente pelo prompt de comando.

  3. Confirme se o bucket inativo foi migrado para o Nearline Storage:

    gsutil defstorageclass get gs://$PROJECT_ID-idle-bucket
    

    A saída é a seguinte:

    gs://automating-cost-optimization-idle-bucket: NEARLINE
    

Considerações sobre um ambiente de produção

Ao automatizar as otimizações de custo no seu próprio ambiente do Google Cloud, considere o seguinte:

  • Considerações gerais: reforce a segurança do Cloud Functions que tem capacidade de modificar ou excluir recursos do Google Cloud.
  • Como identificar o desperdício: neste tutorial, abordamos alguns exemplos de gastos desnecessários. Há muitos outros exemplos que geralmente se enquadram em uma destas três categorias:
    • Recursos provisionados em excesso: recursos com provisionamento maior que o necessário para uma determinada carga de trabalho, como VMs com mais capacidade de CPU e memória do que o necessário.
    • Recursos inativos: recursos totalmente não utilizados.
    • Recursos inativos por meio período: recursos usados apenas durante o horário comercial.
  • Como automatizar a limpeza: neste tutorial, foi necessário um processo de várias etapas com diversas operações assíncronas para criar um snapshot e excluir o disco. Outros recursos do Google Cloud, como endereços IP não utilizados, podem usar operações síncronas.
  • Como implantar em escala: neste tutorial, o ID do projeto do Google Cloud é definido no código da Função do Cloud. Para implantar essa solução em escala, use as APIs Cloud Billing ou Resource Manager para ver a lista de projetos com uma conta de faturamento ou uma organização. Em seguida, envie esses IDs de projeto do Google Cloud como variáveis para uma função. Nessa configuração, você precisa adicionar a conta de serviço da Função do Cloud aos projetos em que ela pode limpar ou excluir os recursos. Recomendamos o uso de um framework de implantação automatizada, como o Cloud Deployment Manager ou o Terraform (em inglês).
  • Automação de alertas: este documento mostra como usar um payload simulado de um alerta do Monitoring para acionar a migração da classe de armazenamento. As políticas de alertas do Monitoring podem ser avaliadas no máximo em 23 horas e 59 minutos. Em um ambiente de produção, essa restrição pode não ser longa o suficiente para considerar um bucket inativo antes de migrar a classe de armazenamento. Considere ativar os registros de auditoria de acesso a dados no bucket do Cloud Storage e criar um pipeline que consuma esses registros a fim de avaliar se um bucket foi usado para exibição nos últimos 30 dias. Para mais informações, consulte as noções básicas sobre os registros de auditoria e considere criar um coletor agregado para enviar os registros ao Pub/Sub e um pipeline do Dataflow para processá-los.

Limpar

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

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

A seguir