O Google Cloud cobra a maior parte das despesas de nuvem dos projetos. Mas de qual projeto?
A resposta é simples para um serviço baseado em Recursos (Resource), como o Google Compute Engine — a cobrança vai para o projeto que contém o Recurso, como uma VM.
Já quando você chama uma API de um serviço do Google Cloud como Vision, Translate ou BigQuery, o modelo de cobrança é mais flexível. Parte ou todo o valor fica vinculado a um projeto "Client" definido por você, o que permite atribuir os custos a diferentes unidades de negócio ou projetos.
Neste post, você vai entender:
- O que significa o projeto "Client" e como defini-lo.
- Os principais padrões para vincular a cobrança a um projeto, considerando os diferentes tipos de serviço.
- Por que a documentação do Google quase sempre fala em "quota project" em vez de "billing project" e como os dois se relacionam.
- Como descobrir, em qualquer chamada de API, para qual projeto ela foi cobrada.
- Como contornar os desafios de atribuir custos a categorias de negócio.
Como definir o Quota/Billing Project
Quando uma chamada de API chega à infraestrutura do Google Cloud, ela percorre a hierarquia abaixo para determinar o projeto Client que, em serviços não baseados em Recursos, também é usado para a cobrança. (Detalho os conceitos de "quota project" vs "billing project" mais adiante.)
- A avaliação é feita pelo Service Infrastructure/Service Control do Google, que garante um comportamento unificado entre os serviços gerenciados pela empresa.
- Permissões: para que um projeto possa ser indicado como Client, o principal que faz a chamada — uma Service Account, um usuário, Workforce Identity Federation ou Workload Identity Federation — precisa ter o papel Service Usage Consumer nesse projeto. (Não importa se a Service Account está definida nesse projeto ou em outro.)
- Isso vale para os serviços do Google Cloud Platform, mas não necessariamente para outros serviços do Google, como Workspace ou Maps.
- Você especifica o projeto Client com as técnicas a seguir, nesta ordem de precedência.
Como especificar o Client
1. Especificado na requisição
- Cabeçalho HTTP: o cabeçalho HTTP
X-goog-user-projectpode ser passado diretamente na requisição. Útil em chamadas REST cruas, como as feitas com curl. - Configuração da biblioteca cliente: o projeto definido pelas opções de cliente nos SDKs do Google Cloud. Veja um exemplo com a biblioteca Python do Google Cloud Client.
from google.cloud import translate_v3from google.api_core.client_options import ClientOptions# 1. Define the billing projectoptions = ClientOptions(quota_project_id="your-billing-project-id")# 2. Inject it when creating the clientclient = translate_v3.TranslationServiceClient(client_options=options)2. Variável de ambiente
O valor da variável de ambiente GOOGLE_CLOUD_QUOTA_PROJECT. Definir esse valor é uma boa prática para configurar o quota project dinamicamente em ambientes em containers, sem fixá-lo no código via ClientOptions.
3. API Key
O projeto onde foi gerada a API Key usada na chamada.
4. ADC Quota Project
No ambiente local (geralmente em desenvolvimento), isso é configurado com gcloud auth application-default set-quota-project.
A armadilha do desenvolvimento local: Se você rodar
gcloud auth application-default loginsem definir um projeto Client para quota e cobrança, seus scripts locais vão autenticar a maioria das APIs usando um projeto especial e limitado (o "Cloud SDK project"764086051850). Como ele é compartilhado globalmente, o uso é fortemente restringido e erros do tipo"Quota exceeded for project 764086051850"aparecem quase de imediato. Para evitar isso, basta definir o valor do Client.
5. Token de autenticação
- Service Account: o projeto dono da Service Account que faz a requisição (incluindo Service Accounts personificadas).
- OAuth Client ID: o projeto dono do OAuth 2.0 Client ID usado para gerar o token do usuário final.
6. Workforce Identity Federation
Se o principal da API for um usuário do Workforce Identity Federation, é usado o projeto do usuário do workforce pool.
Por que o Google fala em "Quota project" e não em "Billing project"?
A documentação e os parâmetros do Google Cloud usam quase sempre o termo "quota project", e o termo "billing project" aparece pouco.
Há exceções. A documentação do gcloud, por exemplo, usa os dois termos lado a lado de uma forma confusa, mesmo se referindo ao mesmo parâmetro: billing/quota_project para a configuração persistente da ferramenta e --billing-project para a flag de linha de comando.
A explicação é a seguinte: em todo o Google Cloud, as configurações de Client fazem uma coisa só no nível da infraestrutura — definem o projeto de quota usado pelo gateway de API, enquanto a cobrança vai para o projeto do Recurso. Só que, em serviços não baseados em Recursos, o sistema de cobrança não encontra um Recurso do lado do servidor para cobrar e, por padrão, acaba usando o quota project.
Serviços baseados em Recursos vs. não baseados em Recursos
A principal diferença está entre serviços cobrados por Recursos e os que não são. Vamos começar com um resumo:
| Tipo de serviço | Driver principal de cobrança | Driver principal de quota | Exemplos |
|---|---|---|---|
| Baseado em Recursos | Projeto que contém o recurso | Projeto Client | Compute Engine, Spanner, Cloud Run |
| Baseado em Client | Projeto Client (Quota) | Projeto Client | Vision API, Translate API |
APIs baseadas em Recursos: projeto identificável no servidor.
São as APIs de infraestrutura, armazenamento e computação do Google. Elas são stateful. Quando você as chama, está pedindo ao Google para ler, alterar ou apagar um ativo ou dado específico que vive em um projeto. O billing project é onde o Recurso fica e geralmente é informado na URL. Já o quota project é determinado pela configuração do Client.
Há alguns casos especiais como Cloud Storage, Pub/Sub e BigQuery, detalhados a seguir.
Alguns exemplos:
- Compute Engine API: gerenciamento de máquinas virtuais, discos e redes.
GET https://compute.googleapis.com/compute/v1/projects/{project}/zones/{zone}/instances - Cloud Spanner API: consultas e gerenciamento de bancos de dados relacionais.
POST https://spanner.googleapis.com/v1/projects/{project}/instances/{instance}/databases/{database}/sessions - Cloud Run é "serverless", mas quem cuida do serviço Cloud Run é você, não o Google — por isso a cobrança é baseada em Recursos. A URL do serviço Cloud Run não tem projeto e não fica no domínio
googleapis.com.
Quota e cobrança baseadas em Client: sem Recurso no servidor
Para APIs stateless, que são apenas um algoritmo compartilhado globalmente, não existe Recurso em nenhum projeto e nenhum servidor aparece na URL REST. Nesses casos, a cobrança é determinada pela configuração do Client.
Alguns exemplos:
- Cloud Natural Language API: você passa um parágrafo e ela devolve a análise de sentimento.
POST https://language.googleapis.com/v1/documents:analyzeSentiment - Cloud Video Intelligence API: você passa um vídeo e ela devolve rótulos dos objetos que aparecem nele.
POST https://videointelligence.googleapis.com/v1/videos:annotate
Cloud Storage: a opção Requester Pays
O Cloud Storage é um serviço baseado em Recursos, ainda que não tenha o ID do projeto em uma URL no formato: GET https://storage.googleapis.com/storage/v1/b/{bucket}/o/{object}
Mesmo assim, ele tem um projeto do lado do servidor, identificado pelo gateway da API a partir do nome do bucket.
Assim como em outras APIs baseadas em Recursos, a cobrança vai para o projeto do bucket, e a quota fica vinculada ao Client informado.
Isso pode mudar com a opção "Requester Pays", exclusiva do Cloud Storage. Quando o dono do bucket habilita o Requester Pays, quem chama a API precisa informar um projeto cobrável (pelas configurações de Client mencionadas acima), e esse projeto passa a ser cobrado pelo egress e pelas operações de API (o dono do bucket continua pagando o armazenamento).
BigQuery: dois tipos distintos de Recurso
O BigQuery é um caso fora da curva: storage e compute podem ficar em projetos diferentes.
- Storage é cobrado do projeto dono do Recurso: o dataset com os dados armazenados.
- Processamento de Queries é cobrado do projeto onde o job da query é executado. Mesmo sendo um tipo de compute, o job é tratado como um Recurso distinto e stateful. Ele é cobrado de seu próprio projeto, que pode ser diferente do projeto de storage e do projeto de onde o job foi disparado.
Pub/Sub: Topics e Subscriptions podem estar em projetos diferentes
Assim como em outros serviços baseados em Recursos, no Pub/Sub os custos estão atrelados à propriedade do Recurso, não importa quem faça a chamada de API, e as configurações de Client servem apenas para calcular as quotas.
O que torna o Pub/Sub diferente é que os próprios Recursos podem estar distribuídos em projetos distintos:
- O Topic é o Recurso que define a cobrança da publicação de mensagens.
- Uma subscription do Pub/Sub é um Recurso à parte e pode ser criada em um projeto diferente do projeto do Topic ou do Client que faz a invocação. É ela que determina a cobrança do throughput de entrega, da transferência de dados (egress) e do armazenamento de subscription.
Como descobrir o projeto cobrado em uma invocação de serviço
Veja algumas formas de identificar o projeto cobrado em uma determinada invocação. Não existe um campo padrão "billed_project" dentro de um log de API do Google Cloud, mas, em geral, dá para chegar nessa informação.
Pré-requisito: para rastrear chamadas de API, primeiro você precisa habilitar os Data Access Audit logs da API em questão (por exemplo, Cloud Storage, BigQuery) no projeto que você suspeita estar sendo cobrado. Faça isso no console do Google Cloud em IAM & Admin -> Audit Logs.
Para serviços do Google Cloud em geral
Filtre os logs do serviço:
logName=~"cloudaudit.googleapis.com"protoPayload.serviceName="[SERVICE_NAME].googleapis.com"E, se quiser, por método também, por exemplo:
logName=~"cloudaudit.googleapis.com/data_access"protoPayload.serviceName="vision.googleapis.com"protoPayload.methodName="google.cloud.vision.v1.ImageAnnotator.AnnotateImage"Localize o campo resource.labels.project_id na entrada de log. Esse campo identifica o projeto cobrado, seja ele o projeto baseado em Recurso ou o baseado em Client. (A exceção são os buckets Requester Pays do Cloud Storage.) Essa informação aparece mesmo quando você visualiza dados de vários projetos por meio de um Log Sink multiprojeto.
Para jobs de Compute do BigQuery
Como o BigQuery separa compute de storage, você precisa olhar especificamente para os logs de execução de compute, e não para os de storage. Rode esta query no Logs Explorer e, como nos outros serviços do Google, localize o campo resource.labels.project_id.
resource.type="bigquery_project"protoPayload.methodName=("google.cloud.bigquery.v2.JobService.InsertJob" OR "google.cloud.bigquery.v2.JobService.Query")protoPayload.metadata."@type"="type.googleapis.com/google.cloud.audit.BigQueryAuditMetadata"Para Requester Pays no GCS
Nos buckets Requester Pays do Cloud Storage, os audit logs mostram o número do projeto cobrado (em hexadecimal) em protoPayload.authorizationInfo.resource, depois de "projects/", por exemplo "projects/0000004d9813b13".
A solução para a atribuição de custos
Depois de saber como expor esses logs de cobrança, o próximo desafio é mapeá-los para o seu negócio: para departamentos ou projetos específicos, por exemplo.
Meu trabalho como Cloud Architect na DoiT International é orientar clientes sobre como otimizar custos, e a DoiT oferece um conjunto poderoso de ferramentas no DoiT Cloud Intelligence para isso. O DoiT Cost Allocation, por exemplo, agrupa e atribui custos por dimensão de negócio.
Alguns serviços aceitam labels que podem ajudar na atribuição de custos:
- Em serviços baseados em Recursos, dá para alocar por Recurso, opcionalmente adicionando labels para refletir as suas categorias de negócio.
- Em um caso à parte, a chamada de API de muitos modelos de Generative AI aceita labels customizadas de custo para serem usadas na atribuição.
- Os pipelines do Vertex AI também têm um recurso exclusivo de atribuição de custos. O Pipeline em si tem um custo pequeno, mas, mais importante, ele pode criar diversos tipos de recursos. O Vertex AI anexa automaticamente a label
vertex-ai-pipelines-run-billing-idem cada Recurso que cria, o que ajuda a atribuir custos à execução do Pipeline como um todo.
No entanto, para a maioria dos serviços não baseados em Recursos, os dados de custo do GCP não vêm rotulados por usuário ou por outras informações que permitam separar categorias de negócio.
Uma saída é: crie vários projetos para servir como Client. As organizações no Google Cloud costumam usar muitos projetos, organizados em pastas. Esses projetos podem ser definidos como Client para alocar custos por categoria de negócio. Eles podem estar vazios em todo o resto, e você não precisa rodar o código cliente dentro do billing project — o que importa é o projeto Client da invocação. Assim, os próprios projetos funcionam como o "label" que identifica a unidade de negócio.