cloudrun-development — Claude Code skill for CloudBase Run deploys
Backend development rules for CloudBase Run: deploying services with long connections, VPC database access, and diagnosing container deploy failures.
npx skills add TencentCloudBase/skills --skill cloudrun-development -a claude-codeWhat cloudrun-development does
This skill walks the agent through CloudBase Run work in two modes, Function and Container. It helps decide when CloudRun is the right target and when a plain HTTP cloud function is enough: long-lived connections, SSE, WebSocket, custom system dependencies, TCP access to MySQL, PostgreSQL or Redis. There is a separate path for migrating an existing GitHub app that talks to its database through a classic DATABASE_URL.
What sits inside is a set of rules and protocols the agent reads before writing code. Sections cover the Function-versus-Container choice, VPC database access, credentials for calling CloudBase resources from the service, and a SOP for container failures: deploy_failed, a Pod that never becomes ready, failed readiness probes, a pull loop against docker.io. The skill points at sibling files through relative paths such as ../auth-tool-cloudbase/SKILL.md.
One thing to know up front: those sibling skills have to be present locally. When a referenced file is missing, the skill asks you to install the full CloudBase plugin rather than HTTP-fetching markdown into the agent context. Also, the environment must be initialized for CloudRun before the first deploy, otherwise the service quietly lands in the legacy small-tenant path. Worth checking before you ship, not after.
What it helps with
- deploy a backend that needs WebSocket or SSE on CloudBase
- migrate a GitHub app and wire it to a VPC database
- pick between CloudRun and an HTTP cloud function
- find out why a container won't start after deploy
- set up TCP access from a service to MySQL, PostgreSQL or Redis
Example prompts for the agent
- deploy my Node service to CloudBase Run with PostgreSQL access in the VPC
- the container fails with deploy_failed — walk the SOP from the skill
- migrate this GitHub app to CloudBase Run, the database is MySQL
How to install cloudrun-development
1Skills CLI (Vercel)
npx skills add TencentCloudBase/skills --skill cloudrun-development -a claude-code2Manually: put the files in place
~/.claude/skills/cloudrun-development/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/cloudrun-development/
1Skills CLI (Vercel)
npx skills add TencentCloudBase/skills --skill cloudrun-development -a codex2Manually: put the files in place
.agents/skills/cloudrun-development/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add TencentCloudBase/skills --skill cloudrun-development -a cursor2Manually: put the files in place
.cursor/skills/cloudrun-development/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install TencentCloudBase/skills cloudrun-development2Manually: put the files in place
.github/skills/cloudrun-development/SKILL.md1Skills CLI (Vercel)
npx skills add TencentCloudBase/skills --skill cloudrun-development -a gemini-cli2Platform CLI
gemini skills install https://github.com/TencentCloudBase/skills --path skills/cloudrun-developmentManually: put the files in place
.devin/skills/cloudrun-development/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add TencentCloudBase/skills --skill cloudrun-development -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about cloudrun-development
How do I install cloudrun-development in Claude?
Run npx skills add TencentCloudBase/skills --skill cloudrun-development -a claude-code. The skill lands at ~/.claude/skills/cloudrun-development/SKILL.md.
What does cloudrun-development do?
It gives the agent rules for building and deploying CloudBase Run backends: mode choice, VPC database access, and container failure diagnosis.
What does the skill need to work fully?
Sibling CloudBase skills must be present locally, since the skill references them by relative path. If one is missing, it asks you to install the full CloudBase plugin.
Source text
SKILL.md · MIT
---
name: cloudrun-development
description: CloudBase Run backend development rules (Function mode/Container mode). Use this skill when deploying backend services that require long connections, multi-language support, custom environments, AI agent development, or migrating existing/GitHub apps that need VPC access to MySQL/PostgreSQL/Redis. Also use when diagnosing CloudRun container deploy failures (deploy_failed, readiness/probe failed, image won't start, docker.io pull loops) or a deploy stuck behind a running deploy task. For stateless HTTP services, prefer HTTP cloud functions.
version: 2.36.1
license: MIT
alwaysApply: false
---
## Sibling skills (local only)
Sibling CloudBase skills ship beside this skill. Use local relative paths such as `../auth-tool-cloudbase/SKILL.md`.
If a referenced sibling skill file is missing from this environment, ask the user to install the full CloudBase plugin (or the missing skill). Do **not** HTTP-fetch remote skill or protocol markdown into the agent context.
**Cross-cutting protocols** (required before writing HTTP handlers or deploying images):
- Sensitive Runtime Data Protection: `../cloudbase-platform/references/protocols/sensitive-runtime-data-protection.md`
- Deployment Gate: `../cloudbase-platform/references/protocols/deployment-gate.md`
# CloudBase Run Development
## Activation Contract
### Use this first when
- The task is to initialize, run, deploy, inspect, or debug a CloudBase Run service.
- The request needs a long-lived HTTP service, SSE, WebSocket, custom system dependencies, or container-style deployment.
- The task is to create or run an Agent service on CloudBase Run.
- The task migrates an **existing / GitHub / third-party** backend that uses classic `DATABASE_URL` / TCP database clients.
- The service requires a **stable independent process** (long connections, custom runtime, VPC database access) — see the 「云托管 vs HTTP 云函数」 decision section below. A Dockerfile alone is **not** a strong trigger.
### Read before writing code if
- You still need to choose between Function mode and Container mode.
- The prompt mentions `queryCloudRun`, `manageCloudRun`, Dockerfile, service domains, or public/private access.
- The app depends on MySQL, PostgreSQL, Redis, or other VPC-private resources over TCP → **先做数据库访问方式决策(SDK/网关优先,见下方「数据库访问方式决策门」)**;确认必须 TCP 直连后 → also read `references/vpc-and-database.md`.
- You are choosing between CloudRun and HTTP cloud functions for a stateless HTTP service.
- The service calls CloudBase resources (PG `app.rdb()`, NoSQL, storage, functions) through an SDK → **先过「计算资源访问 CloudBase 的凭证决策门」**:凭证谁签发、怎么注入、怎么吊销,都必须在写代码之前定下来。
- Container deploy fails (`deploy_failed`, Pod not ready, readiness/probe failed, third-party `imageUrl` won't stay up) → also read `references/image-deploy-troubleshooting.md` and follow the **Container deploy failure SOP** below. Do not start by raising `InitialDelaySeconds`.
### Then also read
- Cloud functions instead of CloudRun -> `../cloud-functions/SKILL.md`
- Agent SDK and AG-UI specifics -> `../cloudbase-agent/SKILL.md`
- Web authentication for browser callers -> `../auth-web-cloudbase/SKILL.md`
- Existing app + TCP database networking -> `references/vpc-and-database.md`
- Container image deploy failure / probe / `deploy_failed` -> `references/image-deploy-troubleshooting.md`
- Service calls CloudBase resources through an SDK (credential source / injection / revocation) -> `../cloud-functions/references/http-function-credentials.md`
- Billing questions about a CloudRun charge ("why was I charged when nothing was deployed", "the free quota wasn't used up") -> `../cloud-api-operations/references/recipes/billing-charges-explained.md` (the gifted quota is a **3-month total**, and a container bills while **instance count is not 0**)
### Do NOT use for
- Simple Event Function or HTTP Function workflows that fit the function model better.
- Frontend-only projects with no backend service.
- Database-schema design tasks.
### Common mistakes / gotchas
- Choosing CloudRun when the request only needs a normal cloud function.
- **Forgetting to listen on the platform-provided `PORT` in Container mode** — and its mirror image in Function mode: calling `app.listen()` there, where the framework already owns the port and the second bind dies with `EADDRINUSE`.
- **Guessing the credential environment variable name.** `@cloudbase/node-sdk` reads `CLOUDBASE_APIKEY`; an invented name (for example `TCB_API_KEY`) is silently ignored and only shows up later as "no credentials at runtime".
- **Copying a server credential out of the local client login state** (`auth.json`, `.cloudbase/`) and injecting it into a deployed service. Issue the key with `manageAppAuth(action="createApiKey", keyType="api_key")` instead, so it has an owner, a rotation path, and a `keyId` you can revoke. See `../cloud-functions/references/http-function-credentials.md`.
- **Baking static content into the image — media files, user uploads, or assets that change on their own cadence.** Three cases, one root cause: the image is rebuilt, re-pushed and re-pulled on every deploy *and* on every scale-up, so anything large or independently-changing makes every deploy slower for no reason.
- **Media files** (`*.mp4`, large images, fonts) pulled in by a `COPY . .` — one demo video can turn a 30-second deploy into a multi-minute one. Media belongs in cloud storage, referenced by URL. Add a `.dockerignore` covering `*.mp4`, `*.mov`, `*.zip`, `*.psd`, and media directories such as `public/videos/`.
- **User uploads written to the container filesystem** — the service is stateless; anything on local disk is gone on the next deploy, restart, or scale-out. Uploads go to cloud storage.
- **Frequently-updated static resources served from the image** — if an asset changes on its own schedule, every change forces a full service redeploy. Serve it from cloud storage so the service only redeploys when the *code* changes.
- Treating CloudRun as stateful app hosting and storing important state on local disk.
- Assuming local run is available for Container mode.
- Opening public access by default when the scenario only needs private or mini-program internal access.
- **Deploying an existing app with `DATABASE_URL` / MySQL / PostgreSQL / Redis but omitting `serverConfig.VpcConf`** — deploy appears to succeed, then runtime DB connections fail.
- **新应用部署默认选 TCP 直连数据库** — 能用 SDK/网关访问的数据(PG `app.rdb()`、NoSQL、storage)不需要 `VpcConf` 也不需要数据库账号密码;仅迁移类应用(经典驱动/ORM 无法替换)才走 TCP 直连 + `VpcConf`。见「数据库访问方式决策门」。
- Confusing `OpenAccessTypes` (how users reach the service) with `VpcConf` (how the service reaches VPC databases).
- **Deploying to an environment that has not initialized CloudRun** — `CreateCloudRunServer` on an environment with no 大租户 record silently lands in the legacy 小租户 path, creating wrong small-tenant services/versions. Always ensure the environment is initialized first (`manageCloudRun(action="initEnv")`, tcbr) before the first deploy. `manageCloudRun(action="deploy")` now blocks new-service creation on uninitialized environments with guidance.
- **Using the legacy `tcb` CloudRun API** (`CreateCloudBaseRunResource` / `DescribeCloudBaseRunResource` / `DeleteCloudBaseRunResource`) — these are deprecated 小租户 open APIs and are blocked in `callCloudApi`. CloudRun always goes through `tcbr` (`CreateCloudRunEnv` / `CreateCloudRunServer`). Query a single environment's base info / whether CloudRun is enabled with `DescribeEnvBaseInfo` (`EnvId` required) — use `manageCloudRun(action="initEnv")` to open and `queryCloudRun(action="envStatus")` to poll status; query the environment list / resource info with `DescribeCloudRunEnvs` (`EnvId` optional filter).
- **Deploying `httpbin` / request-echo images or returning `req.headers` / `process.env`** — CloudBase may inject `x-cloudbase-context` (base64 temporary credentials). Echoing it leaks account cloud access. Follow `../cloudbase-platform/references/protocols/sensitive-runtime-data-protection.md`.
- **Seeing readiness probe failed / `deploy_failed` and immediately raising `InitialDelaySeconds`** — the probe window is already ~N+150s; crash loops and loopback binds are not slow-start. Follow the Container deploy failure SOP.
- **Deploying a third-party image without reading its run docs** — missing `Cmd`, bind-address env, or `VolumesConf` looks identical to a probe failure.
- **Calling `getDeployLog` for `imageUrl` deploys** — that is CODING build log; use `getProcessLog`.
- **Treating startup banners as proof the service is healthy** — pull `getProcessLog` twice and compare; a repeated boot sequence is a restart loop.
### Minimal checklist
- Choose Function mode or Container mode explicitly.
- **Confirm the environment has CloudRun initialized before the first deploy** — a brand-new environment must call `CreateCloudRunEnv` (tcbr) first; never `CreateCloudRunServer` on an uninitialized environment (it falls back to the legacy 小租户 path). `manageCloudRun(action="deploy")` validates this automatically and blocks new services on uninitialized environments. When blocked, first call `manageCloudRun(action="initEnv", envId=...)` (异步开通) and poll `queryCloudRun(action="envStatus")` until `Status=normal`, or reconsider an HTTP cloud function to bypass CloudRun entirely.
- Confirm whether the service should be public, VPC-only, or mini-program internal (**ingress**).
- If the app uses TCP databases/caches, resolve and set `VpcConf` (**egress / private network**) before deploy — see `references/vpc-and-database.md`.
- Keep the service stateless and externalize durable data.
- **Separate static from dynamic**: media files, user uploads, and frequently-updated assets live in cloud storage, not in the image. Check what the Dockerfile copies in.
- **Settle the credential path for every CloudBase SDK call before writing code** — a server API Key issued through `manageAppAuth(action="createApiKey")` and injected via `EnvParams`, never a key copied out of the local client login state.
- Use absolute paths for every local project path.
- Confirm handlers never echo `x-cloudbase-context`, full headers, or credential env vars; do not deploy httpbin-style reflectors.
- For third-party images, complete the five-item docs checklist (Cmd / port / bind env / volume / health) before deploy.
## Overview
Use CloudBase Run when the task needs a deployed backend service rather than a short-lived serverless function.
### 云托管 vs HTTP 云函数(按需求选,不按文件选)
> 核心原则:**HTTP 云函数优先**。只有需求真正需要云托管时才用云托管;有 `Dockerfile` 不等于必须上云托管。
**HTTP 云函数更合适(优先):**
- 无状态 HTTP 服务,监听 `PORT`/`9000`,只做「请求进来 → 处理 → 响应」的响应式逻辑
- 短生命周期请求,无长连接需求(SSE/WebSocket 之外的普通 API、CRUD、转发)
- 标准 runtime 够用(不需要自定义系统依赖、不需要非标准语言)——需要时也能用镜像函数(Custom Image HTTP Function)跑,仍然在函数这条线上
- 部署更快、费用更低(按请求计费,可缩容到 0)、**无需初始化云托管环境**
- 有 `Dockerfile` 但服务本质是无状态 HTTP → 优先 HTTP 云函数(HTTP Function / Custom Image HTTP Function),不必上云托管
**云托管才需要(只有以下之一才选云托管):**
- 长连接:WebSocket、SSE 长连接、服务端推送
- 需要常驻的独立进程:后台任务循环、常驻缓存 / 连接池、自管端口的服务
- VPC 内数据库 / Redis 访问(`VpcConf` 私有网络连通)
- Agent 服务(Function mode CloudRun)
- 迁移已有 / GitHub / 第三方应用
**语言不是上云托管的条件**:非标准语言(Java / Rust / C++ / PHP / .NET 等)或需要自定义系统依赖时,只要服务仍是「请求进来 → 响应」且无长连接,打成镜像用 Custom Image HTTP Function,就还是函数;只有再叠加常驻 / 长连接 / VPC 才上云托管。
**决策示例:** 一个带 `Dockerfile` 的 Go/Python HTTP API,无长连接、无自定义系统依赖、不碰 VPC 数据库 → 选 HTTP 云函数而不是云托管;同一份代码若有 WebSocket 长连接 → 才选云托管。
### 数据库访问方式决策门(部署前必答:SDK 优先,TCP 直连兜底)
> 核心原则:**能用 CloudBase SDK/网关访问的数据,一律优先 SDK 路径。** TCP 直连会引入 VPC、安全组、数据库账号密码三件套,全是部署后才暴露的问题(`ETIMEDOUT`、安全组拦截、密码注入),能不碰就不碰。
**优先:SDK / 网关路径(无需 `VpcConf`、无需数据库账号密码)**
- CloudBase PG → `app.rdb()`(js-sdk v3 / node-sdk,走 PG HTTP 网关;详见 `../postgresql-development-cloudbase/SKILL.md`)
- NoSQL → `app.database()`;对象存储 → `app.storage`
- 新应用 / CloudBase 原生数据 → 数据层直接按 SDK 路径设计,部署时完全不需要 VPC 配置;若只用到这些数据面,还可结合上一节的「HTTP 云函数优先」进一步免掉云托管
**仅当以下情况才走 TCP 直连(须完成 `references/vpc-and-database.md` 全流程):**
- 迁移已有 / GitHub / 第三方应用,数据层是经典驱动或 ORM(mysql2、pg、Prisma、SQLAlchemy、WordPress / Ghost 等),改造成 SDK 的成本高或用户明确要求保留
- 需要 SDK 不覆盖的能力(特定 SQL 方言、存储过程、Redis 原生协议等)
**决策动作:** 扫描到 `DATABASE_URL` / DB 依赖信号时,先停下来回答「这个数据访问能不能换成 SDK/网关」,再决定是否进入 VPC checklist——不要默认按 TCP 直连方案往下走。
### 计算资源访问 CloudBase 的凭证决策门(部署前必答)
> 核心原则:**SDK 路径免掉的是数据库账号密码,不是 CloudBase 资源访问凭证。** 服务代码要调 CloudBase 资源(PG `app.rdb()` / NoSQL / storage / functions)时,先把凭证来源定下来,再写代码、再部署。
三件事必须先答:
1. **谁签发** — CloudBase 服务端 API Key:`manageAppAuth(action="createApiKey", keyType="api_key", keyName="<service>-<env>")`,或 CLI `tcb env apikey create my-key -e env-xxx`。**不要**从本地客户端登录态(`auth.json` / `.cloudbase/`)里取一把来用。
2. **怎么注入** — 经 `serverConfig.EnvParams` 注入 `CLOUDBASE_APIKEY`(`@cloudbase/node-sdk` 自动读取该变量;显式字段是 `accessKey`)。变量名以官方为准,不要自造。改环境变量时保留已有键值,不要整份覆盖。
3. **怎么吊销** — 每个服务一把专用 key,记录 `keyName` 与轮换负责人;下线或轮换时 `manageAppAuth(action="deleteApiKey", keyId=...)` 并**重新部署**。轮换后旧实例里残留的副本不会报错,只会静默失效。
不要假设云托管容器已自动带上可用的 CloudBase 凭证 —— 部署后用一次真实的 SDK 读取验证(验证两次以上,不要只看进程起没起来)。完整步骤、Manager SDK 的腾讯云密钥对路径、环境变量合并的安全写法见 `../cloud-functions/references/http-function-credentials.md`。
`api_key` 是**环境级**凭证:可绕过 RLS,单环境签发数量有限。不要给每个服务灌同一把 —— 任一实例失陷即整环境失陷。
### When CloudRun is a better fit
- Long connections: WebSocket, SSE, server push
- Long-running request handling or persistent service processes
- Custom runtime environments or system libraries
- Arbitrary languages or frameworks
- Stable external service endpoints with elastic scaling
- AI Agent deployment on Function mode CloudRun
- Migrating existing containerized or multi-language apps that need VPC access to databases
## Mode selection
| Dimension | Function mode | Container mode |
| --- | --- | --- |
| Best for | Fast start, Node.js service patterns, built-in framework, Agent flows | Existing containers, arbitrary runtimes, custom system dependencies |
| Port model | The function framework binds the platform port itself — **your code must not call `app.listen()`** | App must listen on the injected `PORT` |
| Dockerfile | Not required | Required — but a Dockerfile alone does **not** mean CloudRun; first check whether the service needs long connections / custom runtime. Stateless HTTP services with a Dockerfile may fit HTTP cloud functions better. |
| Local run through tools | Supported | Not supported |
| Typical use | Streaming APIs, low-latency backend, Agent service | Custom language stack, migrated container app |
## How to use this skill (for a coding agent)
1. **Choose mode first**
- Function mode -> quickest path for HTTP/SSE/WebSocket or Agent scenarios
- Container mode -> use when Docker/custom runtime is a real requirement
2. **Follow mandatory runtime rules**
- Container mode: listen on the injected `PORT`. Function mode: the framework binds the port for you — **never** call `app.listen()`
- Settle the credential gate (who issues / how injected / how revoked) before writing any CloudBase SDK call
- Keep the service stateless
- Put durable data in DB/storage/cache
- Keep dependencies and image size small — the image carries code and dependencies only; media, user uploads and frequently-updated assets go to cloud storage (see *Common mistakes*)
- Respect resource ratio guidance: `Mem = 2 × CPU`
3. **Use the correct tools**
- Read operations -> `queryCloudRun`
- Write operations -> `manageCloudRun`
- Delete requires explicit confirmation and `force: true`
- Always use absolute `targetPath`
4. **Follow the deployment sequence**
- Initialize or download code
- For a brand-new environment, ensure CloudRun is initialized first — call `manageCloudRun(action="initEnv", envId=...)` (async, idempotent) before the first deploy; `manageCloudRun(action="deploy")` blocks new services on uninitialized environments and tells you to call `initEnv`
- For Container mode, verify Dockerfile
- **Scan for DB/cache dependency signals** (`DATABASE_URL`, docker-compose DB services, ORM configs)
- If TCP DB access is required, complete the VPC checklist in `references/vpc-and-database.md` **before** deploy
- Local run when available
- Configure ingress access model **and** egress `VpcConf` when needed
- For `imageUrl` / third-party images, complete the **five-item docs checklist** in the Container deploy failure SOP before deploy
- Deploy and verify detail output + DB connectivity
- If deploy fails, follow the Container deploy failure SOP (`references/image-deploy-troubleshooting.md`) — docs → `getProcessLog` → config; do not start with `InitialDelaySeconds`
## Tool routing
### Read operations
- `queryCloudRun(action="list")` -> list services
- `queryCloudRun(action="detail")` -> inspect one service and its latest deploy status when available
- `queryCloudRun(action="templates")` -> see available starters
- `queryCloudRun(action="getDeployLog")` -> **构建日志**(CODING / `DescribeCloudRunBuildLog`)。**仅云端源码构建有意义**;已有镜像部署(`imageUrl`)没有构建过程,不要用它诊断镜像部署失败。未登录 CODING 的账号会报错(如 `User not created or may not qcloud user`)
- `queryCloudRun(action="getProcessLog")` -> **运行日志**(`tcbr/DescribeCloudRunProcessLog`)。返回部署阶段步骤(如 `create_version_check_vpc` / `create_eks_virtual_service` / `check_eks_virtual_service`)+ 容器启动/运行日志(s6-overlay、应用进程、readiness probe 失败原因)。**镜像部署与源码构建均可用,不依赖 CODING**。参数:`detailServerName`/`serverName` + 可选 `runId`(不传则取最新部署的 `RunId`;`RunId` 也可从 `detail` / `getDeployRecords` 的 `latestDeploy.RunId` 取得)
- `queryCloudRun(action="getDeployRecords")` -> list deploy records (newest first; includes `BuildId` / `RunId` / `FlowRatio` / `Status`) — use to review release history and rollback context before a traffic operation
- `queryCloudRun(action="envStatus")` -> check whether the environment's CloudRun is opened and its provisioning status (`Status=creating` opening / `normal` opened) — use after `initEnv` to poll progress or before `deploy` to confirm readiness
- `queryCloudRun(action="getManageTask")` -> **发布任务状态**(`tcbr/DescribeServerManageTask`)。返回 `taskId` / `taskStatus` 与最新部署记录状态 `latestDeployStatus`。用于两件事:撞到「已有部署发布任务运行中」时先确认任务是否真在推进;以及部署长时间无进展时,区分「任务仍在推进」和「任务已卡住」。**不知道任务状态就不要反复重试 deploy**
### Log query SOP(构建日志 vs 运行日志)
部署失败排查时**必须区分**两类日志,不要只用 `getDeployLog`:
1. **云端源码构建**(传 `targetPath`、走 CODING 构建)
- 先 `queryCloudRun(action="getDeployLog", detailServerName=..., buildId=...)` 查**构建日志**(编译/打包失败)
- 再 `queryCloudRun(action="getProcessLog", detailServerName=..., runId=...)` 查**运行日志**(部署步骤 + 容器启动/健康检查)
2. **已有镜像部署**(传 `imageUrl`、`DeployType=image`)
- **跳过** `getDeployLog`(无构建过程;且依赖 CODING,未登录会直接失败)
- 直接 `queryCloudRun(action="detail")` 或 `getDeployRecords` 取 `latestDeploy.RunId`,再 `getProcessLog` 查运行日志
```json
{
"action": "getProcessLog",
"detailServerName": "my-svc",
"runId": "<from latestDeploy.RunId>"
}
```
### Deploy-task SOP(撞到「已有部署发布任务运行中」时)
`manageCloudRun(action="deploy")` 报「已有部署发布任务运行中」/ *already has a deploy task running* 时,**不要盲目重试,也不要反复改 Dockerfile / serverConfig** —— 先确认任务真实状态:
1. `queryCloudRun(action="getManageTask", detailServerName=...)` → 读 `taskId` / `taskStatus` / `latestDeployStatus`
2. `queryCloudRun(action="getProcessLog")` → 隔 20–40 秒对比两次拉取,确认部署阶段步骤是否还在推进
3. 按结果分支:
| 观察 | 动作 |
| --- | --- |
| `taskStatus` 仍是运行态,部署步骤有推进 | **继续等**,不要重发 deploy |
| 任务已结束(非运行态),而 deploy 仍被拒 | 才考虑重试 |
| 任务长时间停在非终态,版本也停在 `creating` 不动 | 记录 `taskId` / `latestDeployStatus` / 时间窗作为证据,不要空转重试 |
**`force=true` 不解决这个问题**:它只跳过本工具的确认提示,不会取消或覆盖服务端已有的发布任务 —— 把它当「强制覆盖」用只会白撞一次。
日志侧的排查顺序(构建日志 vs 运行日志、先日志后配置)见上面的 **Log query SOP** 与 **Container deploy failure SOP**。
### Write operations
- `manageCloudRun(action="initEnv")` -> **open (initialize) CloudRun for the environment** — async, idempotent (`Status=normal` → already opened, no re-create). Use on a brand-new environment before the first deploy, or when `deploy` is blocked with an "尚未初始化云托管" message. Params: `envId` (defaults to the configured env), `packageType` (default `Trial`). Poll `queryCloudRun(action="envStatus")` until `Status=normal`.
- `manageCloudRun(action="init")` -> create local project
- `manageCloudRun(action="download")` -> pull remote code
- `manageCloudRun(action="run")` -> local run for Function mode
- `manageCloudRun(action="deploy")` -> trigger deploy + **lightweight wait for registration** (does not hang for full build; pass `waitRegistration=false` to skip even that wait when you don't need `buildId`). Returns `buildId` / `runId` / `taskId` + **DeployType-aware `next_step`**: **source** → `getDeployLog` then `getProcessLog`; **image** (`imageUrl`, BuildId often `0`) → **skip `getDeployLog`**, use `getDeployRecords`/`detail` for `RunId` then `getProcessLog`. Follow the returned `next_step` — do not always poll build logs. Existing services: RMW preserves remote VpcConf / EnvParams keys / OpenAccessTypes; **new services automatically validate that the environment's CloudRun is initialized** — if not, deploy is blocked with guidance to call `initEnv` first
- `manageCloudRun(action="updateConfig")` -> config-only update (no code upload; VPC / EnvParams / scaling / access types)
- `manageCloudRun(action="traffic")` -> **traffic management / canary release** (aligns with `tcb cloudrun traffic`): `trafficOp="set"` adjusts the stable/canary traffic ratio (`stablePercent` + `canaryPercent` must equal 100, e.g. 90/10); `trafficOp="promote"` promotes the canary version to full release (100%, closes gray release, irreversible); `trafficOp="rollback"` rolls back to the previous stable version (stops the releasing canary). Check `queryCloudRun(action="getDeployRecords")` first to understand current versions and traffic
- `manageCloudRun(action="delete")` -> delete service
- `manageCloudRun(action="createAgent")` -> create Agent service
## Deploying an existing image (imageUrl)
> 已有一个现成镜像(本地构建好、或第三方发布)时,不需要本地源码目录,直接 `manageCloudRun(action="deploy")` 传入 `imageUrl` 即可,走 `DeployType="image"`(容器型)部署,`targetPath` 可省略。若用户明确提到使用某个镜像或无需重新构建代码,**必须传 imageUrl**,不要仅因本地有源码目录就回退到源码构建。
**决策路径(直填 vs 本地中转):**
1. **公网匿名可拉取**(如 `ccr.ccs.tencentyun.com/...`、公开 Docker Hub 镜像)→ **直填 imageUrl**:`manageCloudRun(action="deploy", serverName=..., imageUrl="ccr.ccs.tencentyun.com/ns/img:v1", serverConfig={...})`。CloudBase 会直接拉取该 registry 地址构建部署。**若 `docker.io` / Docker Hub 在节点上反复拉取失败**,不要空转重试:改用 Dockerfile `FROM <public-image>` + `targetPath` 源码构建(CODING 拉公网镜像,产物进 CCR 内网拉取)。见下方 SOP 第 4 步。
2. **私有 / 需登录的 registry**(`ghcr.io`、私有 ECR/Harbor 等)→ **本地中转到 CCR**:
```
docker pull ghcr.io/example/app:latest
docker tag ghcr.io/example/app:latest ccr.ccs.tencentyun.com/<ns>/app:latest
docker login ccr.ccs.tencentyun.com
docker push ccr.ccs.tencentyun.com/<ns>/app:latest
```
然后把 `ccr.ccs.tencentyun.com/<ns>/app:latest` 作为 `imageUrl` 传入。中转只解决拉取,**不能替代**镜像文档里的启动命令 / 环境变量 / 数据目录。
**与 initEnv 联动:** 镜像部署同样要求环境已开通云托管。新环境首次部署前先 `manageCloudRun(action="initEnv", envId=...)`,并用 `queryCloudRun(action="envStatus")` 轮询到 `Status=normal`;未开通时 `deploy` 会被拦截并引导先 `initEnv`。
**示例:**
```json
{
"action": "deploy",
"serverName": "my-image-svc",
"imageUrl": "ccr.ccs.tencentyun.com/ns/app:latest",
"serverConfig": {
"OpenAccessTypes": ["PUBLIC"],
"Cpu": 0.5,
"Mem": 1,
"MinNum": 1,
"MaxNum": 3,
"Port": 8080,
"Cmd": ["node", "server.js"],
"EnvParams": "{\"PORT\":\"8080\",\"BIND_HOST\":\"0.0.0.0\"}"
}
}
```
`Port` / `Cmd` / `EnvParams` 必须来自镜像官方文档的五要素清单,不要套用 `3000` 或省略启动命令。第三方镜像的完整对照见 `references/image-deploy-troubleshooting.md` 附录。
部署后:`manageCloudRun(deploy)` 对镜像返回的 `next_step` 默认指向 `getProcessLog`(或先 `getDeployRecords` 取 `RunId`),**不要**改去调 `getDeployLog`。也可用 `queryCloudRun(action="detail")` 查看 `imageInfo`(镜像地址与部署类型)。镜像部署失败排查走下方 SOP。
## Container deploy failure SOP
**顺序:先查镜像官方文档 → 再查运行日志 → 最后才动配置。禁止一看到 probe failed / `deploy_failed` 就调 `InitialDelaySeconds`。**
详情与案例:`references/image-deploy-troubleshooting.md`。
### 1. 部署前:从镜像官方文档确认五要素
不要靠 Docker Hub tag 或「常见默认值」猜。部署前必须确认:
1. **启动命令** EntryPoint / Cmd(进程如何前台常驻)→ `serverConfig.EntryPoint` / `Cmd`
2. **服务端口**(进程真正 bind 的端口;不要假设 80/3000,也不要假设镜像尊重 `PORT`)→ `serverConfig.Port`
3. **对外监听环境变量**(必须 `0.0.0.0` 而不是 `127.0.0.1`、功能开关默认关闭等)→ `EnvParams`
4. **数据目录挂载** → `serverConfig.VolumesConf`
5. **健康端点**(CloudRun readiness 探的是**服务端口**,不是任意 HTTP path)
缺任何一项再部署,失败看起来都会像「健康检查失败」。
### 2. 部署失败:用 `getProcessLog` 定性
镜像部署(`imageUrl`)**跳过** `getDeployLog`(那是云端源码构建的构建日志)。从 `detail` / `getDeployRecords` 取 `RunId`,再 `queryCloudRun(action="getProcessLog")`。
**启动日志存在 ≠ 服务正常运行。** banner、s6/tini 行、sidecar "listening" 都不能证明探针目标已起来。
**两次日志对比判活:** 隔 20–40 秒再拉一次 `getProcessLog`。
| 观察 | 定性 |
| --- | --- |
| 只有调度/创建步骤(`create_eks_*`),没有容器 stdout | **Pod 调度中 / 镜像拉取** |
| 同一段启动 banner / PID 1 行重复出现(时间戳在走、内容几乎一样) | **容器启动即退出 / 重启循环** |
| 进程还在,但 listen 在 `127.0.0.1` 或端口 ≠ `serverConfig.Port` | **端口 / 绑定地址问题** |
| 两次拉取是**同一条启动过程**在往后打日志,banner 不重复 | 才可能是启动慢 |
### 3. Readiness probe 真实机制(严禁先调延迟)
部署步骤完成后:先等 **N** 秒(`InitialDelaySeconds`),再大约 **每 5 秒** 探一次服务端口,连续约 **30 次全失败** 才判本次部署失败。窗口 ≈ **N+150s**。**不是**「N 秒后立即失败」。
- **禁止:** 看到 probe failed 就把 N 改成 120。崩溃循环和 loopback 绑定不会因为 N 变大而好。
- **允许调大 N 仅当:** 两次日志证明**同一个进程还在一次性初始化**(JVM 预热、迁移)且尚未 listen。
### 4. 公网镜像(`docker.io`)反复失败 → Dockerfile 源码构建
节点直连 Docker Hub 反复失败时,不要空转 `imageUrl`。写:
```dockerfile
FROM docker.io/example/app:latest
```
用 `targetPath` 走云端源码构建:CODING 构建机拉公网镜像,产物进 CCR,云托管节点内网拉取。这只解决**拉取拓扑**,不替代第 1 步的 Cmd / 环境变量 / 卷。
### 5. Supervisor 镜像(s6 / tini / supervisord)启动即退出
PID 1 往往是监督进程,不是 HTTP 应用。用两次日志找子进程重启风暴。若镜像 issue 记录了 PID 1 / `pgrep -f` 误匹配,按文档 workaround(绝对路径 Cmd、关闭 supervise),不要调探针延迟。示例见 reference 附录。
## Access guidance
- **Web/public scenarios** -> enable PUBLIC ingress intentionally and pair it with the right auth flow.
- **Mini Program** -> prefer internal direct connection and avoid unnecessary public exposure.
- **Private ingress scenarios** -> keep public access off unless the product requirement clearly needs it.
- **Database / Redis in a VPC** -> this is **not** solved by `OpenAccessTypes`. You must set `serverConfig.VpcConf` and use the database private address. Read `references/vpc-and-database.md`.
## Quick examples
### Initialize
```json
{ "action": "init", "serverName": "my-svc", "targetPath": "/abs/ws/my-svc" }
```
### Local run (Function mode)
```json
{ "action": "run", "serverName": "my-svc", "targetPath": "/abs/ws/my-svc", "runOptions": { "port": 3000 } }
```
### Deploy (no VPC-private dependencies)
```json
{
"action": "deploy",
"serverName": "my-svc",
"targetPath": "/abs/ws/my-svc",
"serverConfig": {
"OpenAccessTypes": ["PUBLIC"],
"Cpu": 0.5,
"Mem": 1,
"MinNum": 1,
"MaxNum": 5
}
}
```
### Deploy (existing app that connects to MySQL / PostgreSQL / Redis over TCP)
```json
{
"action": "deploy",
"serverName": "my-existing-app",
"targetPath": "/abs/ws/my-existing-app",
"serverConfig": {
"OpenAccessTypes": ["PUBLIC"],
"Cpu": 0.5,
"Mem": 1,
"MinNum": 1,
"MaxNum": 5,
"EnvParams": "{\"DATABASE_URL\":\"postgres://user:[email protected]:5432/app\"}",...
© TencentCloudBase · MIT · TencentCloudBase/skills