ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何开通第一个 Cua Cloud Fleet:申领 Linux 桌面、运行命令、保存截图并清理云端资源?

如何开通第一个 Cua Cloud Fleet:申领 Linux 桌面、运行命令、保存截图并清理云端资源? 如何开通第一个 Cua Cloud Fleet申领 Linux 桌面、运行命令、保存截图并清理云端资源【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua这篇文章对应 Cua 仓库中的教程 Your first Cloud Fleet在run.cua.ai上开通一个单沙箱的Cloud Fleet申领其中的 Linux 桌面在桌面里执行uname -a把桌面截图保存到本地最后删除 Fleet 释放云端资源。Cua Sandbox SDK 把 Fleet 表示为一个Pool而一块活跃桌面是该池上的一次 claim申领。开始前需要准备三样东西Python3.11,3.14、uv 运行时以及一个有权限管理 sandbox pool 的 Fleet 凭据。注意replicas1的 pool 在你删除它之前会一直保持一个云端沙箱处于 warm 状态云端资源可能产生计费所以本文最后一步清理是必做项。准备环境并创建 Fleet API keyFleet SDK 接受 OAuth 用户 API key 或 Fleet bearer access token但cua auth login保存的交互式 CLI 会话不会导出这两种凭据给 SDK 使用不能代替下面的 key 创建步骤参见 Set up Fleet credentials。在浏览器中完成 API key 创建登录 Cua Fleethttps://run.cua.ai在导航中打开API keys页面。在Create API key下输入一个描述性名称例如first-fleet-tutorial。Allowed Namespaces (optional)保持默认的All namespaces (no restriction)因为本教程要创建一个全新的 pool namespace。选择Create key在API key created弹窗中把Client ID和Client Secret复制到你的密钥管理器再点I have copied the credentials——Client Secret 只显示这一次。如果无法登录、页面提示API keys are unavailable或创建被拒绝先联系 Cua 支持确认账号访问权限再继续。另外 pool 创建可能要求账号已绑定支付方式如果 Fleet 显示Payment method required进入Settings用Add payment method添加并先确认计价条款因为本教程会创建可计费资源。拿到 key 后在同一个 shell 中导出环境变量。CUA_CLIENT_ID和CUA_CLIENT_SECRET分别替换为你刚才复制的 Client ID 与 Client SecretCUA_TOKEN_URL是run.cua.ai的默认 token 端点控制台弹窗中不会显示它export CUA_CLIENT_IDyour-client-id export CUA_CLIENT_SECRETyour-client-secret export CUA_TOKEN_URLhttps://auth.cua.ai/realms/cyclops-cs/protocol/openid-connect/token unset FLEETS_TOKENFLEETS_TOKEN的优先级高于 client credentials如果你已经有一个有效的 Fleet access token也可以只设置FLEETS_TOKEN并在整个清理流程结束前保持它有效改用 user key 时务必unset它。先做只读访问检查在同一 shell 里用下面这条检查命令验证凭据它用 user key 换一个短期 access token然后请求GET /api/namespaces只打印返回的 namespace 数量uv run --with httpx0.27,1 python - PY import os import httpx with httpx.Client(timeout30) as client: token_response client.post( os.environ[CUA_TOKEN_URL], auth(os.environ[CUA_CLIENT_ID], os.environ[CUA_CLIENT_SECRET]), data{grant_type: client_credentials}, ) token_response.raise_for_status() access_token token_response.json()[access_token] response client.get( https://run.cua.ai/api/namespaces, headers{Authorization: fBearer {access_token}}, ) response.raise_for_status() print(fFleet access verified: {len(response.json())} namespace(s).) PY成功时输出形如Fleet access verified: 0 namespace(s).文档示例数量取决于你的账号。返回零个 namespace 对没有 pool 的账号是合法的。这一步只验证了认证和 namespace 列表读取pool 创建仍然取决于账号权限、准入规则和资源可用性。如果 token 请求失败检查 client ID、secret 和 token 端点如果 Fleet 请求返回401或403先解决账号访问问题再去开通资源。创建工作目录并保存 Fleet 脚本为这次运行单独建一个目录脚本和它的输出都放在里面mkdir first-cloud-fleet cd first-cloud-fleet脚本会先预留一个随机命名的新 namespace前缀first-fleet-再创建 pool。预留使用独占创建cloud-fleet-run.json已存在时直接报错而不是覆盖遇到已存在的 namespace 名称会拒绝而不是修改它。namespace 名称和创建时间戳保存在cloud-fleet-run.json中——不要编辑这个记录也不要把这个 namespace 复用到其他工作因为清理会删除该 namespace 及其全部资源。把教程中的完整脚本保存为first_cloud_fleet.py内联元数据声明了 Python 版本与固定依赖版本# /// script # requires-python 3.11,3.14 # dependencies [ # cua-sandbox0.4.3, # cua-fleet0.1.14, # ] # /// import asyncio import json import os import sys from pathlib import Path from uuid import uuid4 from cua_sandbox import Image, Pool from fleet_sdk import ( CyclopsClient, CyclopsConfiguration, CyclopsCredentials, CyclopsTokenProviderConfiguration, ) IMAGE ( public.ecr.aws/k5j5w0x5/cua-ubuntu-24.04 sha256:c1e601dbb748fdc467c663136f7592e308a91a3c19c309b75261544432826a57 ) RECORD Path(cloud-fleet-run.json) def fleet_client(): configuration dict( base_urlos.environ.get(CUA_FLEET_BASE_URL, https://run.cua.ai), pool_poll_interval_ms2000, pool_poll_limit300, claim_poll_interval_ms2000, claim_poll_limit300, ) token os.environ.get(FLEETS_TOKEN) if token: return CyclopsClient.connect_with_access_token_and_native_http_client( CyclopsTokenProviderConfiguration(**configuration), token ) return CyclopsClient.connect_with_native_http_client(CyclopsConfiguration( **configuration, token_urlos.environ[CUA_TOKEN_URL], credentialsCyclopsCredentials( os.environ[CUA_CLIENT_ID], os.environ[CUA_CLIENT_SECRET] ), )) async def find_namespace(client, name): # A direct lookup outside an owned namespace can return 403, even when # the resource does not exist. Use a successful account inventory instead. namespaces await client.list_namespaces() return next((item for item in namespaces if item.name name), None) async def delete_namespace(client, name, created_at): current await find_namespace(client, name) if current is None: print(fNamespace no longer in account inventory: {name}) return if not created_at or current.created_at ! created_at: raise RuntimeError(Namespace identity changed; refusing cleanup.) await client.delete_namespace(name) for _ in range(60): if await find_namespace(client, name) is None: print(fNamespace no longer in account inventory: {name}) return await asyncio.sleep(2) raise TimeoutError(Namespace is still visible. Retry cleanup after it terminates.) async def cleanup(): record json.loads(RECORD.read_text()) if not record.get(created_at): raise RuntimeError( Creation was not confirmed. Check this runs name in Fleet before deleting anything. ) await delete_namespace(fleet_client(), record[name], record[created_at]) async def run(): pool_name ffirst-fleet-{uuid4().hex} # Exclusive creation prevents overwriting an earlier runs cleanup record. with RECORD.open(x) as output: json.dump({name: pool_name, created_at: None}, output) client fleet_client() # Only HTTP 201 confirms reservation. A collision (409) or denied request # stops here, without reconciling or deleting another namespaces resources. namespace await client.create_namespace(pool_name) try: RECORD.write_text(json.dumps({ name: pool_name, created_at: namespace.created_at, })) if not namespace.created_at: raise RuntimeError(Namespace creation timestamp missing; inspect Fleet before cleanup.) print(fProvisioning Cloud Fleet: {pool_name}) pool await Pool.apply( Image.from_registry(IMAGE), namepool_name, replicas1, cpu4, memory_mb4096, services{server: 8000}, ttl_seconds_after_created3600, ) async with pool.claim( namefirst-claim, serviceserver, time_to_start900, ) as sandbox: print(fConnected to sandbox: {sandbox.name}) result await sandbox.shell.run(uname -a) if not result.success: raise RuntimeError(result.stderr) print(result.stdout.strip()) screenshot Path(cloud-fleet.png) screenshot.write_bytes(await sandbox.screenshot()) print(fScreenshot saved to {screenshot.resolve()}) finally: print(fDeleting Cloud Fleet: {pool_name}) await delete_namespace(client, pool_name, namespace.created_at) if __name__ __main__: if sys.argv[1:] [run]: asyncio.run(run()) elif sys.argv[1:] [cleanup]: asyncio.run(cleanup()) else: raise SystemExit(Usage: first_cloud_fleet.py run|cleanup)脚本里几个影响运行的取值镜像是固定 digest 的cua-ubuntu-24.04pool 参数为replicas1、cpu4、memory_mb4096、服务端口{server: 8000}ttl_seconds_after_created3600是一小时的 pool TTL作为清理失败时的兜底过期claim 的time_to_start900是沙箱就绪等待上限。脚本同时提供run和cleanup两个子命令cleanup只读本地记录并删除 namespace。运行脚本并核对结果在同一 shell、同一目录下运行uv run first_cloud_fleet.py runuv会读取文件头部的内联元数据在隔离环境中安装cua-sandbox0.4.3及其要求的 Fleet SDKcua-fleet0.1.14。首次运行可能需要几分钟期间 Fleet 在云端开通 Linux 沙箱。成功时的判断依据终端打印出 sandbox 名称和uname -a输出的 Linux 内核信息shell.run返回successFalse时脚本会抛出RuntimeError并仍然进入清理当前目录生成cloud-fleet.png终端打印Screenshot saved to 绝对路径文档示例claim 代码块退出后SDK 释放已申领的沙箱finally块请求删除预留的 namespace其中包含 pool、template 和 sandbox 资源并轮询账号清单直到该 namespace 不再出现。这里要注意两个边界403不被解释为“资源已不存在”删除请求本身不能证明所有资源已经终止。如果清理失败或超时按下一节的流程处理并到 Fleet 控制台核对这次运行留下的资源。这次运行实际发生了什么Fleet SDK 为本次运行独占预留了一个 namespacePool.apply()在其中创建命名 pool 和 Linux 沙箱 templatepool.claim()预留一个沙箱并把 SDK 连接到它的server服务端口8000。这个server服务是沙箱的 computer server不是 Cua Driver MCP 端点shell 与截图调用都指向被申领的云端桌面。脚本本身只做连接检查和保存图片不运行 AI agent也不连接本地 Cua Driver 会话。中断运行后的清理如果进程在开通之后被杀掉或丢失连接finally块可能没有执行到 Fleet。恢复网络和对同一账号的有效 Fleet 凭据后在同一个目录下运行只删除不执行的命令uv run first_cloud_fleet.py cleanup它读取cloud-fleet-run.json确认记录的 namespace 仍带有相同的创建时间戳后才删除它不会调用Pool.apply()、不会 claim 沙箱、不会重复执行工作负载也能处理“预留了 namespace 但创建 pool 之前就失败”的情况。全程使用同一个账号另一个账号清单里看不到该 namespace 不能当作清理成功的证据。删除会销毁沙箱及其全部状态需要保留的远端文件请在清理前取回脚本确认的是账号清单中 namespace 消失不是对底层 guest 终止的独立检查。两种会拒绝删除的情形记录里没有创建时间戳created_at为空说明 namespace 预留从未确认可能源于名称冲突409、请求被拒或响应中断。此时命令拒绝删除。正确做法是到 Fleet UI 里找到记录中的确切名称人工核实这次运行是否创建了任何资源再决定是否移除。不要为了绕开访问或计费错误去删除一个已存在的 pool。namespace 身份变化当前created_at与记录不一致脚本抛出Namespace identity changed; refusing cleanup.说明该名称下现在指向另一个 namespace同样不能直接删。本地保留cloud-fleet.png作为这次运行的结果。要再跑一次请换一个新目录让前一次的清理记录仍然可用。常见失败与边界以下判断来自仓库中的凭据指南和 Troubleshoot Fleet pools and claims401/ token 交换失败确认凭据没有过期或被吊销且进程使用的是预期的 Fleet 与 token 端点按凭据设置流程修正后先重试对已存在资源的查询再尝试创建。403且响应体提示需要支付方式需要账号所有者处理计费设置换一个 pool 名称或反复重试都无法满足该要求。403访问已知 pool 被拒确认凭据属于被授权访问该 pool 的账号不要把403解释为资源不存在或清理已成功。claim 迟迟不就绪在 Fleet 控制台用记录的 namespace 和 claim 名依次核对 pool、template、claim 三个阶段。缩容到零的 pool 可能需要冷启动template 缺失、镜像不可用或容量耗尽不能靠延长 guest 服务超时解决。Python 示例预期server服务监听端口8000。名称本地校验错误pool/namespace 名用小写 DNS label小写字母、数字、连字符首尾为字母或数字最长 63 字符。下一步教程给出的延伸路径均在仓库文档中Create a reusable sandbox pool with PythonConfigure a sandbox pool with TerraformExpire pools and claims automaticallyChoose a Fleet imageSandbox SDK API reference【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表