Como implantar o OpenClaw em instâncias do Cloud Run com o Terraform

1. Introdução

Visão geral

Neste laboratório, você vai implantar uma instância totalmente persistente e de nível de produção do OpenClaw, um framework de agente de IA de código aberto, em instâncias do Cloud Run usando infraestrutura como código declarativa (Terraform). Você vai provisionar instâncias do Cloud Run usando o recurso google_cloud_run_v2_instance do provedor google, montar o Google Cloud Storage via Cloud Storage FUSE para manter o estado do espaço de trabalho do agente, gerenciar as credenciais de API com segurança usando o Google Cloud Secret Manager e interagir com seu agente de IA pela interface da Web integrada do OpenClaw usando o SSH nativo das instâncias do Cloud Run para o pareamento de dispositivos seguro.

Antes de começar, consulte a documentação do OpenClaw para se familiarizar com a arquitetura, as ferramentas e os fluxos de trabalho de agentes do OpenClaw.

Atividades deste laboratório

  • Defina toda a infraestrutura de forma declarativa no Terraform (main.tf), incluindo APIs, contas de serviço, vinculações do IAM, secrets, buckets de armazenamento e instâncias do Cloud Run.
  • Implante o OpenClaw 2.0+ (ghcr.io/openclaw/openclaw:latest) usando google_cloud_run_v2_instance.
  • Gerar e armazenar automaticamente credenciais de gateway seguro no Secret Manager.
  • Monte um bucket do Cloud Storage usando o Cloud Storage FUSE e sincronize /home/node/.openclaw para estado durável, espaço de trabalho e persistência do SQLite.
  • Use gcloud beta run instances ssh para autenticar e aprovar solicitações de pareamento de dispositivos do navegador na interface da Web do OpenClaw Control.
  • (Opcional) Configure um canal de mensagens (Telegram ou WhatsApp).
  • (Opcional) Amplie os recursos do agente adicionando habilidades personalizadas ao Cloud Storage.

O que você vai aprender

  • Como declarar e implantar instâncias do Cloud Run usando o Terraform.
  • Como configurar montagens de volume do Cloud Storage FUSE no Terraform.
  • Como injetar secrets do Secret Manager com segurança como variáveis de ambiente em instâncias do Cloud Run.
  • Como gerenciar a autenticação de dispositivos do OpenClaw 2.0 usando o SSH nativo das instâncias do Cloud Run.
  • Como executar cargas de trabalho de agentes persistentes e de longa duração em instâncias do Cloud Run.

2. Configuração e requisitos

Configuração do projeto do GCP

  1. Faça login no Console do Google Cloud.
  2. Criar ou selecionar um projeto do Google Cloud.
  3. Confira se o faturamento está ativado para seu projeto do Google Cloud

Abrir o Cloud Shell

Ative o Google Cloud Shell na barra de ferramentas superior do console do Cloud. O Cloud Shell inclui o Terraform e o SDK Google Cloud pré-instalados.

Definir projeto e região

Defina o ID do projeto e a região como variáveis de ambiente e configure gcloud:

export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>

gcloud config set project $PROJECT_ID
gcloud config get project

Instalar componentes Beta da gcloud

Verifique se o componente beta está instalado (necessário para o SSH de instâncias do Cloud Run e o streaming de registros):

gcloud components install beta --quiet
gcloud components update

Verificar o Terraform

Confirme se o Terraform está instalado e atende aos requisitos de versão:

terraform version

Você vai ver o Terraform v1.5.0 ou mais recente.

3. (Opcional) Configurar integrações de mensagens (Telegram ou WhatsApp)

Você pode conectar o OpenClaw ao Telegram ou ao WhatsApp. Escolha a Opção A ou a Opção B abaixo.

Opção A: configuração do bot do Telegram

  1. Abra o Telegram e pesquise @BotFather.
  2. Envie o comando /newbot e siga as instruções para especificar um nome e um nome de usuário para o bot.
  3. Copie o token da API HTTP gerado (por exemplo, 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ).
  4. Pesquise @userinfobot no Telegram, envie /start e copie seu ID do usuário numérico (por exemplo, 8035936176).

Você vai fornecer esses valores como variáveis de entrada do Terraform no arquivo terraform.tfvars.

Opção B: configuração do WhatsApp

  1. Pegue seu número de telefone pessoal do WhatsApp no formato internacional, sem espaços ou símbolos (por exemplo, +15551234567).
  2. O OpenClaw se conecta pela política de lista de permissões do canal do WhatsApp.

4. Definir infraestrutura no Terraform

Vamos declarar toda a infraestrutura no Terraform. Isso inclui ativar as APIs necessárias do Google Cloud, criar a conta de serviço dedicada e os papéis do IAM, gerar e armazenar secrets no Secret Manager, provisionar o bucket de estado do Cloud Storage, gerar a configuração openclaw.json e implantar a instância do Cloud Run.

1. Criar um diretório do Terraform

No Cloud Shell, crie um diretório para os arquivos do Terraform e acesse-o:

mkdir openclaw-terraform && cd openclaw-terraform

2. Criar main.tf

Crie um arquivo chamado main.tf. Essa configuração usa o provedor do Google para definir todos os componentes de infraestrutura:

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 8.8.0"
    }
    random = {
      source  = "hashicorp/random"
      version = ">= 3.5.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

# 1. Enable Required APIs
resource "google_project_service" "services" {
  for_each = toset([
    "run.googleapis.com",
    "secretmanager.googleapis.com",
    "storage.googleapis.com",
    "generativelanguage.googleapis.com",
    "compute.googleapis.com"
  ])
  project            = var.project_id
  service            = each.key
  disable_on_destroy = false
}

# 2. Dedicated Service Account
resource "google_service_account" "openclaw_sa" {
  account_id   = "openclaw-sa"
  display_name = "OpenClaw Service Account"
  depends_on   = [google_project_service.services]
}

# 3. Secret Manager: Gateway Password
resource "random_password" "gateway_password" {
  length  = 32
  special = false
}

resource "google_secret_manager_secret" "gateway_password" {
  secret_id = "openclaw-gateway-password"
  replication {
    auto {}
  }
  depends_on = [google_project_service.services]
}

resource "google_secret_manager_secret_version" "gateway_password" {
  secret      = google_secret_manager_secret.gateway_password.id
  secret_data = random_password.gateway_password.result
}

resource "google_secret_manager_secret_iam_member" "sa_gateway_password" {
  secret_id = google_secret_manager_secret.gateway_password.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.openclaw_sa.email}"
}

# 4. Secret Manager: Gemini API Key
resource "google_secret_manager_secret" "gemini_api_key" {
  secret_id = "gemini-api-key"
  replication {
    auto {}
  }
  depends_on = [google_project_service.services]
}

resource "google_secret_manager_secret_version" "gemini_api_key" {
  secret      = google_secret_manager_secret.gemini_api_key.id
  secret_data = var.gemini_api_key
}

resource "google_secret_manager_secret_iam_member" "sa_gemini_api_key" {
  secret_id = google_secret_manager_secret.gemini_api_key.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.openclaw_sa.email}"
}

# 5. Optional Secret Manager: Telegram Bot Token
resource "google_secret_manager_secret" "telegram_bot_token" {
  count     = var.telegram_bot_token != "" ? 1 : 0
  secret_id = "telegram-bot-token"
  replication {
    auto {}
  }
  depends_on = [google_project_service.services]
}

resource "google_secret_manager_secret_version" "telegram_bot_token" {
  count       = var.telegram_bot_token != "" ? 1 : 0
  secret      = google_secret_manager_secret.telegram_bot_token[0].id
  secret_data = var.telegram_bot_token
}

resource "google_secret_manager_secret_iam_member" "sa_telegram_bot_token" {
  count     = var.telegram_bot_token != "" ? 1 : 0
  secret_id = google_secret_manager_secret.telegram_bot_token[0].id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.openclaw_sa.email}"
}

# 6. Cloud Storage Bucket for State Persistence
resource "google_storage_bucket" "openclaw_state" {
  name                        = "openclaw-state-${var.project_id}"
  location                    = var.region
  uniform_bucket_level_access = true
  force_destroy               = true
  depends_on                  = [google_project_service.services]
}

resource "google_storage_bucket_iam_member" "sa_storage" {
  bucket = google_storage_bucket.openclaw_state.name
  role   = "roles/storage.objectUser"
  member = "serviceAccount:${google_service_account.openclaw_sa.email}"
}

# 7. Upload openclaw.json to Cloud Storage Root
resource "google_storage_bucket_object" "openclaw_config" {
  name   = "openclaw.json"
  bucket = google_storage_bucket.openclaw_state.name
  content = jsonencode({
    gateway = {
      mode           = "local"
      port           = 18789
      trustedProxies = ["127.0.0.1", "::1", "169.254.0.0/16", "10.0.0.0/8"]
      bind           = "lan"
      auth = {
        password = "$${OPENCLAW_GATEWAY_PASSWORD}"
      }
      controlUi = {
        allowedOrigins = ["*"]
        enabled        = true
      }
    }
    memory = {
      search = {
        provider = "gemini"
      }
    }
    agents = {
      defaults = {
        model = {
          primary = "google/gemini-3.1-pro-preview"
        }
        sandbox = {
          mode = "off"
        }
      }
    }
    skills = {
      load = {
        extraDirs = ["/mnt/openclaw/skills"]
      }
    }
    channels = {
      telegram = {
        enabled        = var.telegram_bot_token != ""
        defaultAccount = "default"
        accounts = {
          default = {
            enabled   = var.telegram_bot_token != ""
            dmPolicy  = "allowlist"
            allowFrom = var.telegram_user_id != "" ? [var.telegram_user_id] : []
          }
        }
      }
    }
    plugins = {
      entries = {
        google   = { enabled = true }
        telegram = { enabled = var.telegram_bot_token != "" }
      }
    }
  })
}

# 8. Cloud Run Instance
resource "google_cloud_run_v2_instance" "openclaw" {
  name     = "openclaw-instance"
  location = var.region

  ingress              = "INGRESS_TRAFFIC_ALL"
  invoker_iam_disabled = true
  restart_policy       = "ON_FAILURE"
  service_account      = google_service_account.openclaw_sa.email

  containers {
    image = "ghcr.io/openclaw/openclaw:latest"
    args = [
      "/bin/sh",
      "-c",
      "cp /mnt/openclaw/openclaw.json /home/node/.openclaw/ && exec node /app/openclaw.mjs gateway"
    ]

    ports {
      container_port = 18789
    }

    resources {
      limits = {
        cpu    = "4"
        memory = "4Gi"
      }
    }

    env {
      name = "GEMINI_API_KEY"
      value_source {
        secret_key_ref {
          secret  = google_secret_manager_secret.gemini_api_key.secret_id
          version = "latest"
        }
      }
    }

    env {
      name = "OPENCLAW_GATEWAY_PASSWORD"
      value_source {
        secret_key_ref {
          secret  = google_secret_manager_secret.gateway_password.secret_id
          version = "latest"
        }
      }
    }

    dynamic "env" {
      for_each = toset(var.telegram_bot_token != "" ? ["telegram"] : [])
      content {
        name = "TELEGRAM_BOT_TOKEN"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.telegram_bot_token[0].secret_id
            version = "latest"
          }
        }
      }
    }

    volume_mounts {
      name       = "openclaw-storage"
      mount_path = "/mnt/openclaw"
    }
  }

  volumes {
    name = "openclaw-storage"
    gcs {
      bucket        = google_storage_bucket.openclaw_state.name
      read_only     = false
      mount_options = ["uid=1000", "gid=1000", "file-mode=0700", "dir-mode=0700"]
    }
  }

  depends_on = [
    google_project_service.services,
    google_storage_bucket_object.openclaw_config,
    google_secret_manager_secret_version.gateway_password,
    google_secret_manager_secret_version.gemini_api_key,
    google_secret_manager_secret_iam_member.sa_gateway_password,
    google_secret_manager_secret_iam_member.sa_gemini_api_key,
    google_storage_bucket_iam_member.sa_storage
  ]
}

3. Criar variables.tf

Crie um arquivo chamado variables.tf para definir as variáveis de entrada:

variable "project_id" {
  type        = string
  description = "Google Cloud Project ID"
}

variable "region" {
  type        = string
  default     = "us-west1"
  description = "Google Cloud Region for Cloud Run and Storage"
}

variable "gemini_api_key" {
  type        = string
  sensitive   = true
  description = "Gemini API Key from Google AI Studio"
}

variable "telegram_bot_token" {
  type        = string
  default     = ""
  sensitive   = true
  description = "(Optional) Telegram Bot HTTP API Token"
}

variable "telegram_user_id" {
  type        = string
  default     = ""
  description = "(Optional) Telegram User ID for allowlist policy"
}

4. Criar outputs.tf

Crie um arquivo chamado outputs.tf para expor o URL da instância implantada, a senha do gateway gerada e o nome do bucket de armazenamento:

output "instance_url" {
  description = "Public URL for OpenClaw Cloud Run Instance"
  value       = google_cloud_run_v2_instance.openclaw.urls[0]
}

output "gateway_password" {
  description = "Generated OpenClaw Gateway Password"
  value       = random_password.gateway_password.result
  sensitive   = true
}

output "storage_bucket" {
  description = "Cloud Storage bucket persisting OpenClaw state"
  value       = google_storage_bucket.openclaw_state.name
}

5. Criar terraform.tfvars

Para conseguir uma chave de API Gemini:

  1. Acesse o Google AI Studio e faça login com sua Conta do Google.
  2. Clique em Criar chave de API e selecione seu projeto do Google Cloud.
  3. Copie a chave de API gerada.

Crie um arquivo chamado terraform.tfvars com as coordenadas do projeto:

project_id     = "YOUR_PROJECT_ID"
region         = "YOUR_REGION"
gemini_api_key = "YOUR_GEMINI_API_KEY"

# Optional: Uncomment if configuring Telegram
# telegram_bot_token = "YOUR_TELEGRAM_BOT_TOKEN"
# telegram_user_id   = "YOUR_TELEGRAM_USER_ID"

5. Implantar infraestrutura com o Terraform

1. Inicializar e aplicar

Inicialize o diretório de trabalho do Terraform e faça o download dos plug-ins do provedor:

terraform init

Implante a infraestrutura:

terraform apply

Quando solicitado, revise os recursos planejados e digite yes para confirmar.

2. Extrair saídas de implantação

Exporte o URL da instância e a senha do gateway gerada do estado do Terraform:

export INSTANCE_URL=$(terraform output -raw instance_url)
export GATEWAY_PASSWORD=$(terraform output -raw gateway_password)

echo "Instance URL: ${INSTANCE_URL}"
echo "Gateway Password: ${GATEWAY_PASSWORD}"

6. Interagir pela interface da Web e autenticar pelo SSH do Cloud Run

O OpenClaw 2.0+ aplica a autenticação criptográfica de dispositivos. Ao se conectar de um novo navegador, o gateway gera uma solicitação de pareamento que você aprova diretamente pelo SSH nativo das instâncias do Cloud Run.

1. Abra a interface de controle do OpenClaw.

  1. Abra o $INSTANCE_URL no navegador da Web.
  2. Quando a autenticação for solicitada, insira a senha do gateway ($GATEWAY_PASSWORD).
  3. Como esta é uma nova sessão do navegador, a interface de controle do OpenClaw mostra uma solicitação de pareamento de dispositivo pendente com um ID de solicitação (por exemplo: b56143fc-1654-49da-a1d8-5d40479ddc66). Copie esse ID.

2. Acessar a instância do Cloud Run por SSH

No Cloud Shell, inicie um shell interativo seguro na instância em execução:

gcloud beta run instances ssh openclaw-instance --region=${REGION}

3. Aprovar o pareamento de dispositivos

Na sessão SSH, aprove a solicitação do navegador:

openclaw devices approve <REQUEST_ID> --password ${GATEWAY_PASSWORD}

4. Comandos para o agente (instâncias em ação)

Depois de aprovado, seu navegador se conecta imediatamente ao painel de controle do OpenClaw.

  1. Teste o agente do OpenClaw enviando um comando na interface de chat, como "Hello".
  2. Para testar o ciclo de vida de longa duração e o armazenamento persistente da instância do Cloud Run, peça ao agente do OpenClaw para realizar uma tarefa autônoma programada. Por exemplo, peça para ele monitorar um repositório do GitHub em busca de lançamentos e elaborar um resumo:
    Check the GitHub repository openclaw/openclaw every hour for the next 24 hours. Track any new releases, merged pull requests, and breaking changes. Save a structured markdown digest titled `daily-release-digest.md` to your workspace, and notify me in this chat with a summary whenever a new release is detected.
    
  3. Como o estado do OpenClaw, os arquivos do espaço de trabalho e os bancos de dados SQLite são mantidos diretamente no Cloud Storage pelo Cloud Storage FUSE, a tarefa programada, o histórico de conversas e os arquivos de resumo gerados sobrevivem a reinicializações de instâncias e upgrades de contêineres.

7. (Opcional) Verificar as integrações de canais de mensagens

Se você configurou o Telegram ou o WhatsApp nas etapas de configuração opcionais acima, verifique a entrega de mensagens:

  1. Verifique os registros da instância no Cloud Shell:
    gcloud beta run instances logs read openclaw-instance --region ${REGION} --limit 20
    
  2. Abra o Telegram (ou WhatsApp) e envie uma mensagem (por exemplo, /start ou Hello OpenClaw!).
  3. O bot vai autenticar seu ID do usuário com a lista de permissões em openclaw.json e responder usando o Gemini.

8. Monitorar e inspecionar registros de instâncias

As instâncias do Cloud Run capturam stdout e stderr do seu contêiner e os transmitem diretamente para o Google Cloud Logging. Use o Cloud Shell ou o console do Cloud para monitorar o tráfego do gateway e inspecionar as execuções de ferramentas do agente em tempo real.

1. Ler registros de instâncias recentes

Para buscar entradas de registro recentes da instância no Cloud Shell:

gcloud beta run instances logs read openclaw-instance \
  --region ${REGION} \
  --limit 50

2. Assinaturas de registro de chaves para observar

Ao observar o agente em execução, procure os seguintes eventos principais de registro de ambiente de execução:

  • [gateway] ready: confirma que o gateway HTTP e WebSocket do OpenClaw foi inicializado e está detectando na porta 18789.
  • [gateway] agent model: ...: mostra o modelo do Gemini ativo (por exemplo, google/gemini-3.1-pro-preview ou google/gemini-3.5-flash).
  • [agents/tool-policy]: mostra as ferramentas permitidas ou restritas de acordo com sua política.
  • [agent/embedded]: rastreia a execução e a invocação de ferramentas pelo agente.

3. Inspecionar registros no console do Google Cloud

Também é possível visualizar e filtrar registros usando a Análise de registros no console do Cloud:

resource.type="cloud_run_instance"
resource.labels.instance_name="openclaw-instance"

9. (Opcional) Ampliar o agente com habilidades

O OpenClaw oferece suporte a Habilidades, que são pacotes de recursos modulares que ensinam ao agente fluxos de trabalho específicos, ferramentas de CLI especializadas e instruções específicas de domínio.

Como as habilidades funcionam

Cada habilidade é um diretório que contém um arquivo SKILL.md. Ele começa com o frontmatter YAML especificando metadados (name e description), seguido por instruções Markdown:

---
name: summarize-logs
description: Summarize Cloud Run error logs into actionable bullet points.
---

# Log Summarizer Skill

When asked to analyze or summarize logs:
1. Parse error stack traces and group similar errors by frequency.
2. Identify root causes such as memory limits, timeouts, or permission errors.
3. Propose concrete remediation steps.
  • name: o identificador da habilidade (também pode ser chamado diretamente como um comando de barra, por exemplo, /summarize-logs).
  • description: informa ao modelo do OpenClaw quando invocar automaticamente essa habilidade em uma conversa natural.

Adicionar uma habilidade personalizada ao bucket do Cloud Storage

Como o bucket do Cloud Storage está montado em /mnt/openclaw e configurado em skills.load.extraDirs, as habilidades colocadas em gs://${BUCKET_NAME}/skills/ são carregadas e mantidas automaticamente nas reinicializações da instância:

  1. Recupere o nome do bucket:
    export BUCKET_NAME=$(terraform output -raw storage_bucket)
    
  2. Criar um diretório de habilidades local:
    mkdir -p my-skill
    cat << 'EOF' > my-skill/SKILL.md
    ---
    name: summarize-logs
    description: Summarize Cloud Run error logs into actionable bullet points.
    ---
    
    # Log Summarizer Skill
    
    When asked to analyze or summarize logs, group errors by frequency and suggest actionable fixes.
    EOF
    
  3. Faça upload da habilidade para o Cloud Storage:
    gcloud storage cp -r my-skill gs://${BUCKET_NAME}/skills/
    
  4. Use a habilidade no chat:
    • Volte para a interface da Web do OpenClaw Control.
    • Agora você pode usar /summarize-logs para dar comandos ao seu agente ou fazer perguntas em linguagem natural que correspondam à descrição da habilidade.

10. Limpeza

Para evitar cobranças contínuas na sua conta do Google Cloud pelos recursos usados neste codelab, destrua toda a infraestrutura provisionada em uma única etapa usando o Terraform:

  1. Verifique se você está no diretório openclaw-terraform:
    cd openclaw-terraform
    
  2. Destrua todos os recursos:
    terraform destroy
    
  3. Quando solicitado, revise os recursos que serão removidos e digite yes para confirmar. O Terraform vai excluir de forma limpa a instância do Cloud Run, os secrets do Secret Manager, as vinculações de política do IAM, a conta de serviço e o bucket do Cloud Storage.

11. Conclusão

Parabéns! Você implantou uma instância segura e totalmente persistente do OpenClaw nas instâncias do Cloud Run usando o Terraform declarativo, com o suporte da persistência de estado do Cloud Storage, da segurança de credenciais do Secret Manager e do SSH nativo das instâncias do Cloud Run para autenticação segura de dispositivos.