Как развернуть OpenClaw на облачных экземплярах

1. Введение

Обзор

В этой лабораторной работе вы развернете полностью постоянный, защищенный экземпляр OpenClaw — фреймворка для создания агентов искусственного интеллекта с открытым исходным кодом — в Cloud Run Instances . Вы будете взаимодействовать со своим агентом ИИ напрямую, используя встроенный веб-интерфейс OpenClaw (с возможностью подключения каналов обмена сообщениями, таких как Telegram или WhatsApp ), создавать резервные копии его рабочего пространства в Google Cloud Storage и безопасно управлять учетными данными API с помощью Google Cloud Secret Manager .

Прежде чем начать, вы можете ознакомиться с документацией OpenClaw , чтобы понять архитектуру OpenClaw, используемые инструменты и рабочие процессы агентов.

Что вы будете делать

  • Включите необходимые API Google Cloud и создайте выделенную учетную запись службы с необходимыми разрешениями IAM.
  • Надежно храните ключи API и пароли шлюзов в Secret Manager.
  • Подготовьте конфигурационный файл openclaw.json с настройками модели Gemini и включенным пользовательским интерфейсом шлюза.
  • Подготовьте хранилище Cloud Storage для сохранения состояния контейнера.
  • (Необязательно) Загрузите плагин Cloud Run Sandbox Provider, чтобы обеспечить безопасное и изолированное выполнение кода через /usr/local/gcp/bin/sandbox .
  • Разверните OpenClaw с помощью gcloud beta run instances create .
  • Взаимодействуйте напрямую с вашим агентом OpenClaw AI, используя его встроенный веб-интерфейс.
  • (Необязательно) Настройте канал обмена сообщениями ( Telegram или WhatsApp ).
  • (Необязательно) Расширьте возможности своего агента, добавив пользовательские навыки в облачное хранилище.

Что вы узнаете

  • Как развернуть OpenClaw на облачных экземплярах с помощью встроенного веб-интерфейса управления.
  • Как подключить хранилища Cloud Storage к экземплярам Cloud Run.
  • Как безопасно внедрить секреты Secret Manager в качестве переменных среды в Cloud Run.
  • Как запускать длительные, постоянно выполняющиеся рабочие нагрузки агентов на экземплярах Cloud Run.
  • Как настроить и загрузить пользовательские навыки агента в облачное хранилище.

2. Настройка и требования

Настройка проекта GCP

  1. Войдите в консоль Google Cloud .
  2. Создайте или выберите проект Google Cloud.
  3. Убедитесь, что для вашего проекта в Google Cloud включена функция выставления счетов.

Открытая облачная оболочка

Активируйте Google Cloud Shell с верхней панели инструментов Cloud Console.

Установите бета-компонент и настройте проект.

Убедитесь, что для gcloud beta run instances установлен компонент beta :

gcloud components install beta --quiet
export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION="us-west1"

Включите необходимые API Google Cloud.

В Cloud Shell включите API Cloud Run, Secret Manager, Cloud Storage и Gemini:

gcloud services enable \
  run.googleapis.com \
  secretmanager.googleapis.com \
  storage.googleapis.com \
  generativelanguage.googleapis.com \
  compute.googleapis.com

3. (Необязательно) Настройте интеграцию с мессенджерами (Telegram или WhatsApp)

Вы можете подключить OpenClaw к Telegram или WhatsApp . Выберите вариант A или вариант B ниже.

Вариант А: Настройка Telegram-бота

  1. Откройте Telegram и найдите @BotFather .
  2. Отправьте команду /newbot и следуйте подсказкам, чтобы указать имя бота и имя пользователя.
  3. Скопируйте сгенерированный HTTP API-токен (например, 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ ).
  4. Найдите @userinfobot в Telegram, отправьте /start и скопируйте свой числовой идентификатор пользователя (например, 8035936176 ).

Вариант B: Настройка WhatsApp

  1. Получите свой личный номер телефона WhatsApp в международном формате без пробелов и символов (например, +15551234567 ).
  2. OpenClaw подключается через политику разрешенных каналов WhatsApp.

4. Создайте выделенный сервисный аккаунт.

Чтобы соблюсти принцип минимальных привилегий, создайте выделенную учетную запись службы IAM для OpenClaw:

export SERVICE_ACCOUNT_NAME="openclaw-sa"
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
  --display-name="OpenClaw Service Account"

export SERVICE_ACCOUNT="${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

5. Сохраните учетные данные в Secret Manager.

Мы будем хранить конфиденциальные учетные данные API в Google Cloud Secret Manager, чтобы Cloud Run мог безопасно внедрять их в контейнер при загрузке.

1. Получите и сохраните ключ API Gemini.

  1. Зайдите в Google AI Studio и войдите в систему, используя свою учетную запись Google.
  2. Нажмите «Создать ключ API» и выберите свой проект Google Cloud ( ${PROJECT_ID} ).
  3. Скопируйте сгенерированный ключ API.

Сохраните ключ API в Secret Manager и предоставьте учетной записи службы доступ:

echo -n "YOUR_GEMINI_API_KEY" | gcloud secrets create gemini-api-key \
  --data-file=- \
  --replication-policy="automatic"

gcloud secrets add-iam-policy-binding gemini-api-key \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/secretmanager.secretAccessor"

2. Сгенерируйте и сохраните пароль шлюза.

Для защиты общедоступного экземпляра OpenClaw сгенерируйте надежный случайный пароль и сохраните его в Secret Manager:

export OPENCLAW_GATEWAY_PASSWORD=$(openssl rand -hex 16)
echo "Generated Gateway Password: ${OPENCLAW_GATEWAY_PASSWORD}"

echo -n "${OPENCLAW_GATEWAY_PASSWORD}" | gcloud secrets create openclaw-gateway-password \
  --data-file=- \
  --replication-policy="automatic"

gcloud secrets add-iam-policy-binding openclaw-gateway-password \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/secretmanager.secretAccessor"

3. (Необязательно) Создайте секретный канал (в Telegram или WhatsApp)

  • Для Telegram :
    echo -n "YOUR_TELEGRAM_BOT_TOKEN" | gcloud secrets create telegram-bot-token \
      --data-file=- \
      --replication-policy="automatic"
    
    gcloud secrets add-iam-policy-binding telegram-bot-token \
      --member="serviceAccount:${SERVICE_ACCOUNT}" \
      --role="roles/secretmanager.secretAccessor"
    
  • Для WhatsApp :
    echo -n "YOUR_WHATSAPP_TOKEN_OR_KEY" | gcloud secrets create whatsapp-token \
      --data-file=- \
      --replication-policy="automatic"
    
    gcloud secrets add-iam-policy-binding whatsapp-token \
      --member="serviceAccount:${SERVICE_ACCOUNT}" \
      --role="roles/secretmanager.secretAccessor"
    

6. Подготовка хранилища Cloud Storage и конфигурации openclaw.json.

Для работы OpenClaw требуется конфигурационный файл openclaw.json , расположенный по адресу /home/node/.openclaw/openclaw.json .

  1. Создайте сегмент облачного хранилища и предоставьте к нему доступ :
    export BUCKET_NAME="openclaw-state-${PROJECT_ID}"
    gcloud storage buckets create gs://${BUCKET_NAME} --location=${REGION}
    
    gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
      --member="serviceAccount:${SERVICE_ACCOUNT}" \
      --role="roles/storage.objectUser"
    
  2. Создайте openclaw.json : Создайте файл с именем openclaw.json в Cloud Shell. Обновите раздел channels в соответствии с выбранным вами каналом (Telegram или WhatsApp):
    {
      "gateway": {
        "mode": "local",
        "port": 18789,
        "trustedProxies": ["0.0.0.0/0"],
        "bind": "lan",
        "auth": {
          "password": "${OPENCLAW_GATEWAY_PASSWORD}"
        },
        "controlUi": {
          "dangerouslyDisableDeviceAuth": true,
          "allowedOrigins": ["*"],
          "enabled": true
        }
      },
      "agents": {
        "defaults": {
          "model": {
            "primary": "google/gemini-3.1-pro-preview"
          },
          "sandbox": {
            "mode": "all",
            "workspaceAccess": "rw",
            "backend": "cloud-run-sandbox"
          }
        }
      },
      "channels": {
        "telegram": {
          "enabled": true,
          "defaultAccount": "default",
          "accounts": {
            "default": {
              "enabled": true,
              "dmPolicy": "allowlist",
              "allowFrom": [
                "YOUR_TELEGRAM_USER_ID"
              ]
            }
          }
        },
        "whatsapp": {
          "enabled": false,
          "defaultAccount": "default",
          "accounts": {
            "default": {
              "enabled": false,
              "dmPolicy": "allowlist",
              "allowFrom": [
                "+15551234567"
              ]
            }
          }
        }
      },
      "plugins": {
        "load": {
          "paths": [
            "/home/node/.openclaw/plugins"
          ]
        },
        "entries": {
          "google": { "enabled": true },
          "telegram": { "enabled": true },
          "whatsapp": { "enabled": false },
          "cloud-run-sandbox-provider": { "enabled": true }
        }
      }
    }
    
  3. Загрузите файл openclaw.json в корневой каталог облачного хранилища :
    gcloud storage cp openclaw.json gs://${BUCKET_NAME}/openclaw.json
    
  4. (Необязательно) Загрузите плагин Cloud Run Sandbox Provider : Когда agents.defaults.sandbox.mode установлено в значение "all" , OpenClaw по умолчанию пытается запустить локальный демон Docker для выполнения инструментов в изолированной среде. Поскольку стандартные образы контейнеров в Cloud Run не используют Docker, вы можете включить плагин Cloud Run Sandbox Provider . При развертывании с флагом --sandbox-launcher в Cloud Run платформа автоматически внедряет собственный исполняемый файл песочницы микровиртуальной машины gVisor ( /usr/local/gcp/bin/sandbox ), обеспечивая безопасное и изолированное выполнение кода внутри экземпляра примерно за 25 мс.
    • Создайте локальную директорию для плагинов:
      mkdir -p plugins/cloud-run-sandbox-provider
      
    • Создайте plugins/cloud-run-sandbox-provider/package.json :
      {
        "name": "cloud-run-sandbox-provider",
        "version": "1.0.0",
        "description": "Cloud Run Sandbox Provider for OpenClaw",
        "type": "module",
        "main": "index.mjs",
        "openclaw": {
          "extensions": [
            "./index.mjs"
          ]
        }
      }
      
    • Создайте plugins/cloud-run-sandbox-provider/openclaw.plugin.json :
      {
        "id": "cloud-run-sandbox-provider",
        "name": "Cloud Run Sandbox Provider",
        "entry": "./index.mjs",
        "kind": "tool",
        "activation": {
          "onStartup": true
        },
        "configSchema": {
          "type": "object",
          "properties": {}
        }
      }
      
    • Создайте plugins/cloud-run-sandbox-provider/index.mjs :
      import { spawn } from "node:child_process";
      import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
      import { registerSandboxBackend } from "openclaw/plugin-sdk/sandbox";
      
      const SANDBOX_BINARY_PATH = process.env.OPENCLAW_SANDBOX_BINARY_PATH || "/usr/local/gcp/bin/sandbox";
      
      function runCommandRaw(command, args, stdin = null) {
        return new Promise((resolve) => {
          const child = spawn(command, args, { env: { ...process.env } });
          let stdout = Buffer.alloc(0);
          let stderr = Buffer.alloc(0);
          child.stdout.on("data", (data) => { stdout = Buffer.concat([stdout, data]); });
          child.stderr.on("data", (data) => { stderr = Buffer.concat([stderr, data]); });
          child.on("error", (err) => {
            resolve({ code: -1, stdout, stderr: Buffer.from(err.message) });
          });
          child.on("close", (code) => {
            resolve({ code: code ?? 0, stdout, stderr });
          });
          if (stdin != null) {
            child.stdin.write(stdin);
          }
          child.stdin.end();
        });
      }
      
      async function ensureSandboxRunning(sandboxId, workspaceDir) {
        const check = await runCommandRaw(SANDBOX_BINARY_PATH, ["exec", sandboxId, "--", "/bin/true"]);
        if (check.code === 0) {
          return;
        }
      
        const runArgs = [
          "run",
          "--detach",
          "--write",
          "--mount", `type=bind,source=${workspaceDir},destination=${workspaceDir}`,
          sandboxId
        ];
      
        const start = await runCommandRaw(SANDBOX_BINARY_PATH, runArgs);
        if (start.code !== 0) {
          throw new Error(`Failed to start Cloud Run sandbox ${sandboxId}: ${start.stderr.toString("utf8")}`);
        }
      }
      
      class CloudRunSandboxHandle {
        constructor(params) {
          this.id = "cloud-run-sandbox";
          this.runtimeId = params.sessionKey;
          this.runtimeLabel = `cloud-run-sandbox:${params.sessionKey}`;
          this.workdir = params.workspaceDir;
          this.workspaceDir = params.workspaceDir;
        }
      
        async buildExecSpec(params) {
          const { command, args, workdir, env, usePty } = params;
          const positional = ["sh", ...(args || [])];
          const execArgs = ["exec"];
      
          if (env) {
            for (const [key, val] of Object.entries(env)) {
              execArgs.push("-e", `${key}=${val}`);
            }
          }
      
          const activeWorkdir = workdir || this.workdir;
          if (activeWorkdir) {
            execArgs.push("--workdir", activeWorkdir);
          }
      
          execArgs.push(
            this.runtimeId,
            "--",
            "/bin/sh", "-c", command, ...positional
          );
      
          return {
            argv: [SANDBOX_BINARY_PATH, ...execArgs],
            env: { ...process.env },
            stdinMode: usePty ? "pipe-open" : "pipe-closed"
          };
        }
      
        async runShellCommand(params) {
          await ensureSandboxRunning(this.runtimeId, this.workspaceDir);
      
          const spec = await this.buildExecSpec({
            command: params.script,
            args: params.args,
            workdir: params.workdir,
            env: params.env,
            usePty: params.usePty,
          });
      
          return new Promise((resolve, reject) => {
            const child = spawn(spec.argv[0], spec.argv.slice(1), { env: spec.env });
            let stdout = Buffer.alloc(0);
            let stderr = Buffer.alloc(0);
      
            child.stdout.on("data", (data) => { stdout = Buffer.concat([stdout, data]); });
            child.stderr.on("data", (data) => { stderr = Buffer.concat([stderr, data]); });
            child.on("error", reject);
            child.on("close", (rawCode) => {
              const code = rawCode ?? 0;
              if (code !== 0 && !params.allowFailure) {
                const stderrStr = stderr.toString("utf8");
                const summary = stderrStr.trim().split("\n").slice(-3).join(" | ").slice(0, 400);
                reject(Object.assign(
                  new Error(`Cloud Run sandbox shell exited with code ${code}: ${summary}`),
                  { code, stdout, stderr },
                ));
                return;
              }
              resolve({ code, stdout, stderr });
            });
      
            if (params.stdin != null) {
              child.stdin.write(params.stdin);
            }
            child.stdin.end();
          });
        }
      }
      
      export const cloudRunSandboxManager = {
        async describeRuntime({ entry }) {
          const check = await runCommandRaw(SANDBOX_BINARY_PATH, ["exec", entry.containerName, "--", "/bin/true"]);
          return {
            running: check.code === 0,
            actualConfigLabel: "cloud-run-sandbox",
            configLabelMatch: true,
          };
        },
        async removeRuntime({ entry }) {
          await runCommandRaw(SANDBOX_BINARY_PATH, ["delete", entry.containerName, "--force"]);
        }
      };
      
      export default definePluginEntry({
        id: "cloud-run-sandbox-provider",
        name: "Cloud Run Sandbox",
        kind: "tool",
        register(api) {
          registerSandboxBackend("cloud-run-sandbox", {
            factory: async (params) => {
              const sanitizedSessionKey = params.sessionKey.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
              await ensureSandboxRunning(sanitizedSessionKey, params.workspaceDir);
              return new CloudRunSandboxHandle({ ...params, sessionKey: sanitizedSessionKey });
            },
            manager: cloudRunSandboxManager
          });
        }
      });
      
    • Загрузите папку плагина в облачное хранилище:
      gcloud storage cp -r plugins gs://${BUCKET_NAME}/
      
    • Проверьте структуру хранилища Cloud Storage : убедитесь, что структура вашего хранилища содержит openclaw.json в корневом каталоге и файлы плагинов в plugins/cloud-run-sandbox-provider/ .
      gs://${BUCKET_NAME}/
      ├── openclaw.json
      └── plugins/
          └── cloud-run-sandbox-provider/
              ├── package.json
              ├── openclaw.plugin.json
              └── index.mjs
      

7. Разверните OpenClaw на облачных экземплярах.

Разверните OpenClaw с помощью gcloud beta run instances create :

gcloud beta run instances create openclaw-instance \
  --image ghcr.io/openclaw/openclaw:latest \
  --service-account ${SERVICE_ACCOUNT} \
  --port 18789 \
  --cpu 4 \
  --memory 4Gi \
  --public \
  --sandbox-launcher \
  --add-volume mount-path=/home/node/.openclaw,type=cloud-storage,mount-options="uid=1000;gid=1000;file-mode=0700;dir-mode=0700",bucket=${BUCKET_NAME} \
  --set-secrets GEMINI_API_KEY=gemini-api-key:latest,OPENCLAW_GATEWAY_PASSWORD=openclaw-gateway-password:latest \
  --region ${REGION}

Разбивка по ключевым параметрам:

  • --image ghcr.io/openclaw/openclaw:latest : Образ контейнера OpenClaw.
  • --service-account ... : Подключает выделенную учетную запись службы openclaw-sa .
  • --sandbox-launcher : Включает средство запуска песочницы Cloud Run, внедряя исполняемый файл /usr/local/gcp/bin/sandbox в контейнер для безопасного выполнения кода в изоляции с помощью gVisor.
  • --add-volume ... : Монтирует хранилище Cloud Storage непосредственно в /home/node/.openclaw . Использование file-mode=0700;dir-mode=0700 обеспечивает правильные права доступа для OpenClaw.
  • --set-secrets ... : Внедряет учетные данные непосредственно из Secret Manager в переменные среды. (Необязательно: если вы настроили Telegram на дополнительных шагах, добавьте ,TELEGRAM_BOT_TOKEN=telegram-bot-token:latest к --set-secrets .)
  • --public : Предоставляет публичный доступ к URL-адресу.

8. Взаимодействуйте напрямую через веб-интерфейс OpenClaw.

В OpenClaw встроен веб-интерфейс управления, позволяющий управлять вашим ИИ-агентом и общаться с ним непосредственно из браузера:

  1. Получите URL-адрес вашего экземпляра Cloud Run : В Cloud Shell выполните следующую команду:
    gcloud beta run instances describe openclaw-instance \
      --region ${REGION} \
      --format="value(status.urls[0])"
    
  2. Получите доступ к пользовательскому интерфейсу управления OpenClaw :
    • Откройте URL-адрес результата в своем веб-браузере.
    • При запросе аутентификации в пользовательском интерфейсе OpenClaw Control:
      • Введите сгенерированный пароль шлюза ( ${OPENCLAW_GATEWAY_PASSWORD} ) из Secret Manager.
      • Если во всплывающем окне входа отображаются отдельные поля «Имя пользователя» и «Пароль» , оставьте поле «Имя пользователя» пустым (или введите admin ) и укажите ${OPENCLAW_GATEWAY_PASSWORD} в поле «Пароль».
  3. Начните отправлять сообщения своему агенту :
    • После аутентификации вы увидите панель управления OpenClaw.
    • Вы можете отправлять запросы в Gemini непосредственно из интерфейса чата, просматривать активные сеансы агентов, проверять файлы постоянного рабочего пространства и управлять инструментами!

9. (Необязательно) Проверьте интеграцию каналов обмена сообщениями.

Если вы настроили Telegram или WhatsApp на дополнительных этапах настройки, описанных выше, вы можете проверить доставку сообщений:

  1. Проверьте журналы экземпляра в Cloud Shell:
    gcloud run instances logs read openclaw-instance --region ${REGION} --limit 20
    
  2. Откройте Telegram (или WhatsApp) и отправьте сообщение (например /start или Hello OpenClaw! ).
  3. Бот проверит ваш идентификатор пользователя по списку разрешенных пользователей в файле openclaw.json и ответит, используя Gemini!

10. (Необязательно) Расширьте возможности своего агента, добавив новые навыки.

OpenClaw поддерживает Skills — модульные пакеты возможностей, которые обучают вашего агента конкретным рабочим процессам, специализированным инструментам командной строки и инструкциям, специфичным для данной области.

Как работают навыки

Каждый навык представляет собой каталог, содержащий файл SKILL.md . Он начинается с метаданных в формате YAML ( name и description ), за которыми следуют инструкции в формате 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 : Идентификатор навыка (также может быть вызван напрямую как команда со слэшем, например /summarize-logs ).
  • description : Указывает модели OpenClaw , когда следует автоматически активировать этот навык в естественном разговоре.

Добавьте пользовательский навык в свой облачный накопитель.

Поскольку ваш сегмент Cloud Storage монтируется непосредственно в /home/node/.openclaw , навыки, размещенные по адресу gs://${BUCKET_NAME}/skills/ автоматически загружаются при загрузке и сохраняются после перезапуска экземпляра:

  1. Создайте локальный каталог навыков :
    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
    
  2. Загрузите навык в облачное хранилище :
    gcloud storage cp -r my-skill gs://${BUCKET_NAME}/skills/
    
  3. Используйте навык в чате :
    • Вернуться в веб-интерфейс управления OpenClaw.
    • Теперь вы можете управлять своим агентом с помощью команды /summarize-logs или задавать вопросы на естественном языке, соответствующие описанию навыка!

11. Уборка

Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этом практическом задании:

  1. Удалите экземпляр Cloud Run :
    gcloud beta run instances delete openclaw-instance --region ${REGION} --quiet
    
  2. Удалить секреты менеджера секретов :
    gcloud secrets delete gemini-api-key --quiet
    gcloud secrets delete telegram-bot-token --quiet
    gcloud secrets delete openclaw-gateway-password --quiet
    
  3. Удалить корзину облачного хранилища :
    gcloud storage rm -r gs://${BUCKET_NAME}
    
  4. Удалить выделенный сервисный аккаунт :
    gcloud iam service-accounts delete ${SERVICE_ACCOUNT} --quiet
    

12. Заключение

Поздравляем! Вы успешно развернули защищенный, полностью постоянный экземпляр OpenClaw на Cloud Run Instances, использующий Cloud Storage, Secret Manager и предпочитаемый вами канал обмена сообщениями!