tcb deploy
读取项目根目录的 cloudbaserc.json,按依赖顺序一次性编排部署云函数、静态托管、网关路由和数据库迁移,无需逐个调用单资源命令。
tcb deploy 自 v3.8.0 起支持声明式部署。自 v3.9.0 起只部署不构建,且不再接受位置参数与 app 专属选项(tcb deploy <serviceName>、--framework、--build-command、--output-dir 等会报 INVALID_PARAM),云端构建改用 tcb app deploy。
语法
tcb deploy [options]
参数
| 参数 | 必填 | 说明 | 默认值 |
|---|---|---|---|
-e, --env-id <envId> | 否 | 环境 ID,优先级最高 | 配置文件 envId |
--mode <mode> | 否 | 应用 envOverrides.<mode> 与 .env.<mode> 覆盖 | — |
--only <types> | 否 | 只部署指定资源类型,逗号分隔 | 全部 |
--skip <types> | 否 | 跳过指定资源类型,逗号分隔 | — |
--dry-run | 否 | 输出变更计划,不实际部署 | false |
--yes | 否 | 覆盖已存在函数时直接放行,不询问 | false |
--concurrency <n> | 否 | 同类型资源的并发数,上限 20 | 5 |
--continue-on-error | 否 | 单个资源失败后继续部署其余资源 | false |
--only / --skip 的可选类型:database / functions / app / hosting / gateway。
示例
# 部署全部资源
tcb deploy
# 只预览变更计划
tcb deploy --dry-run
# 只部署云函数
tcb deploy --only=functions
# 只部署静态托管和网关
tcb deploy --only=hosting,gateway
# 跳过网关
tcb deploy --skip=gateway
# 跳过 app,配合 tcb app deploy 云端构建
tcb deploy --skip app
# 指定环境并跳过覆盖确认
tcb deploy --env-id=xxx --yes
# 按环境覆盖配置
tcb deploy --mode=production
# 同类型资源并发 3 个
tcb deploy --concurrency 3
# 某个资源失败也继续部署其余
tcb deploy --continue-on-error
完整工作流
从零到一的标准流程:初始化配置 → 部署前校验 → 本地构建 → 预览变更 → 实际部署。
| 步骤 | 命令 | 作用 | 完成标志 |
|---|---|---|---|
| 1 初始化配置 | tcb config init | 智能检测项目资源(云函数目录 / 前端框架 / 静态托管目录),生成 cloudbaserc.json | 项目目录生成合法配置 |
| 2 部署前校验 | tcb validate | 校验 Schema 版本、envId、资源目录与引用一致性 | 退出码 0,输出资源概览 |
| 3 本地构建 | tcb app build | 构建 app 与 hosting[] 产物写入各自 outputDir;只有配了 buildCommand 的项需要,纯静态可跳过 | 产物生成于 outputDir |
| 4 预览变更 | tcb deploy --dry-run | 输出字段级差异(from → to)与 database 迁移计划 | 变更计划符合预期 |
| 5 实际部署 | tcb deploy | 按 database → functions → app → hosting → gateway 顺序编排(只上传产物,不构建) | 部署成功 |
选项详解
--dry-run
只输出变更计划,不实际部署:
tcb deploy --dry-run
输出字段级变更(from → to)与 database 迁移计划。
--only / --skip
tcb deploy --only=functions # 只部署云函数
tcb deploy --only=hosting,gateway # 只部署静态托管和网关
tcb deploy --skip=gateway # 跳过网关
tcb deploy --skip app # 跳过 app(配合 tcb app deploy 云端构建)
只接受逗号分隔的 5 个资源类型,非法值直接报错,不会被静默忽略:
tcb deploy --only fn # ✗ 无效的资源类型 fn
tcb deploy --only "functions hosting" # ✗ 空格分隔不被识别,须用逗号
tcb deploy --only functions,hosting # ✓
--mode / --env-id
tcb deploy --mode=production # 应用 envOverrides.production + .env.production
tcb deploy --env-id=xxx # 指定环境(优先级最高)
--concurrency
默认 5。同类型的多个资源实例并行部署;跨资源类型仍按 database → functions → app → hosting → gateway 串行,不破坏依赖关系。
tcb deploy --concurrency 3 # 多个函数 / 多个托管站点之间并行,最多同时 3 个
- 只作用于同类型连续实例之间(多个 hosting 站点、多个函数);函数与托管之间、托管与网关之间始终串行
- 上限
20,避免对后端 API 造成过大压力
--continue-on-error
默认 fail-fast:任一资源部署失败即中断后续资源,进程以非零退出码结束,便于 CI/CD 感知。加 --continue-on-error 先跑完所有资源,最后统一看失败数:
tcb deploy --continue-on-error # 某个资源失败也继续部署其余
database失败始终强制中断,无论是否加这个参数——后续资源可能依赖新建的 Schema。
部署行为
| 维度 | tcb deploy | tcb fn deploy / tcb hosting deploy 等 |
|---|---|---|
| 配置源 | 一份 cloudbaserc.json 声明全部资源 | 每个命令各自传参 |
| 编排 | database → functions → app → hosting → gateway 自动排序 | 单资源 |
| 依赖处理 | 函数依赖新 Schema(database 先行)、网关依赖函数 / hosting | 不感知 |
| 幂等 | 云端存在性判断,每次部署均执行 | 每次全量执行 |
| 覆盖确认 | 已存在函数覆盖更新前确认(--yes 放行) | --force |
覆盖确认:云端已存在的函数(update 场景)先确认是否覆盖,--yes 直接放行;交互模式逐项确认;无确认机制时保守跳过,不擅自覆盖线上。声明式部署的语义对齐 tcb fn deploy --force。
构建与部署分离
tcb deploy 只负责部署,不执行任何构建与依赖安装。
| 资源 | 在 tcb deploy 中的构建行为 | 起始版本 |
|---|---|---|
hosting[] | 不构建、不安装依赖,直接上传 outputDir | v3.8.2 |
app | 不云端构建,产物直传并写部署记录 | v3.9.0 |
functions[] | 仍按 buildStrategy(zip / cloud / local / image)执行 | — |
buildCommand 已配置但产物目录不存在或为空时,部署报 BUILD_OUTPUT_NOT_FOUND 并提示先执行 tcb app build:
tcb app build # 本地构建 app 与 hosting[](产物写入各自 outputDir)
tcb deploy # 上传产物并编排部署其余资源
需要云端构建前端应用时,用 --skip app 把 app 交给 tcb app deploy:
tcb deploy --skip app # 部署 hosting + functions + gateway,跳过 app
tcb app deploy <serviceName> # 单独部署 app,云端构建
配置示例
最小 cloudbaserc.json:
{
"envId": "your-env-id",
"functions": [
{ "name": "pay-common", "type": "Event", "handler": "index.main" }
],
"app": {
"serviceName": "web",
"root": "web",
"framework": "vite",
"buildCommand": "npm run build",
"outputDir": "dist",
"deployPath": "/",
"envVariables": { "VITE_API_BASE": "/api" }
},
"hosting": [
{
"name": "docs",
"root": "docs",
"framework": "static",
"outputDir": ".",
"deployPath": "/docs"
}
],
"gateway": {
"routes": [
{ "path": "/api", "target": "function:pay-common" },
{ "path": "/docs", "target": "hosting:docs" }
]
}
}
对应的项目目录结构:
project/
├── cloudbaserc.json
├── functions/
│ └── pay-common/
│ └── index.js
├── web/ # app:带版本记录的主站
│ └── dist/ # 构建产物(由 tcb app build 生成)
└── docs/ # hosting:纯静态附属站点,产物直接上传
└── index.html
app 与 hosting[] 怎么选
app | hosting[] | |
|---|---|---|
| 数量 | 单应用 | 多站点(数组) |
| 版本记录 | 有,可 tcb app versions list 查看与回滚 | 无,直传覆盖 |
| 网关挂载 | 通过自己的域名访问,不进 gateway.routes | 可被 target: hosting:<name> 引用 |
| 适用 | 主站 | 文档站、落地页等附属资源 |
两者可以同时配置,但不要指向同一个 root —— 会重复上传同一份产物。
先构建,再部署
tcb deploy 只上传产物,不执行 buildCommand / installCommand。首次部署前先本地构建:
tcb app build # 构建 app 与 hosting[],产物写入各自 outputDir
tcb deploy # 仅上传产物并编排其余资源
产物目录不存在或为空会直接抛 BUILD_OUTPUT_NOT_FOUND。想先确认再部署,用 tcb deploy --dry-run --json,从 plan[].buildHint 读取 buildCommand / outputDir / artifactReady。
完整目录结构约定见项目目录结构,数据库迁移默认放在 cloudbase/migrations/。
资源配置
各资源的完整配置字段见对应文档:
| 资源 | 配置字段 | 关键说明 | 详细文档 |
|---|---|---|---|
| 数据库迁移 | database | 仅 postgresql;迁移文件 14位时间戳_名称.sql,默认目录 cloudbase/migrations/;冲突时中断部署 | 配置文件-数据库 |
| 云函数 | functions | Event / HTTP 双类型;zip 代码包或镜像部署(buildStrategy);HTTP 函数支持 public 匿名访问与 gatewayPath 网关路由 | 云函数配置 · 部署云函数 |
| 静态托管应用 | app | 不构建,直传 outputDir 产物并写部署记录;outputDir 未配置时按构建配置推断,纯静态回退项目根。需云端构建改用 tcb app deploy | 应用部署 |
| 静态托管 | hosting | 数组多站点;先 tcb app build 本地构建,tcb deploy 仅上传产物 | 静态网站托管 · tcb app build |
| 网关路由 | gateway.routes | target 为 function:<name> / hosting:<name>;pathRewrite 自动生成 | 配置文件-网关 |
| 环境覆盖 | envOverrides | 按 --mode 合并覆盖 | 配置文件 |
网关路由的 target: function:<name> 支持两种函数类型:HTTP 型创建为 WEB_SCF 路由,Event 型创建为 SCF 路由(网关把 HTTP 请求包装为事件转发给函数)。CLI 自动查询函数详情判断类型。
数据库迁移
按 database.migrations 目录下的 SQL 文件顺序应用 PostgreSQL 迁移:
| 维度 | 说明 |
|---|---|
| 支持类型 | 仅 type: postgresql(type: nosql 仅透传、不编排) |
| 迁移文件 | 命名 14位时间戳_小写名称.sql(如 20260101120000_init.sql),默认目录 cloudbase/migrations/ |
计划(--dry-run) | 聚合为单条变更项:pending → create |
| 冲突处理 | 目标库已存在同名迁移时中断部署 |
| 失败策略 | database 失败始终强制中断(即便 --continue-on-error),后续资源可能依赖新建 Schema |
database 排在编排最前,一旦失败后续资源不再执行。先用 tcb deploy --dry-run 确认迁移计划无误。
项目目录结构
推荐目录形态:
vibe-app/
├── cloudbaserc.json # 声明式配置(核心契约)
├── .env # 密钥(不入 Git;--mode <mode> 时读 .env.<mode>)
├── .env.example # 密钥模板(入 Git)
├── cloudbase/migrations/ # 数据库迁移(SQL,默认目录)
│ ├── 20260101120000_init.sql
│ └── 20260102150000_add_users.sql
├── functions/ # 云函数代码(functionRoot 默认 ./functions)
│ ├── task-runner/ # Event 函数:exports.main(event, context)
│ └── api-server/ # HTTP 函数:需 scf_bootstrap 启动脚本
├── web/ # 前端代码(hosting[].root 指向)
└── Dockerfile # HTTP 函数镜像部署用(可选,放函数目录内)
各路径的解析规则:
| 资源 | 配置字段 | 默认 / 解析规则 |
|---|---|---|
| 数据库迁移目录 | database.migrations | cloudbase/migrations/(相对项目目录) |
| 函数根目录 | functionRoot | functions/ |
| 函数代码目录 | dir / functionRoot + name | 显式 dir → {cwd}/{dir}(独立于 functionRoot);否则 {cwd}/{functionRoot}/{name} |
| 前端站点 | hosting[].root | 相对项目目录 |
常见问题
1. app.outputDir 未配置时上传哪个目录?
tcb deploy 不构建,outputDir 用来确定从哪里上传,app 与 hosting[] 规则一致:
outputDir | 判定结果 |
|---|---|
配了非空字符串("." 也算) | 用配置值,不参与推断 |
未配置 / "" / 纯空白串 | 推断:显式 buildCommand → dist;由 framework 或 package.json 推导出构建命令 → 框架默认产物目录(未命中回退 dist);无构建命令(纯静态)→ root |
| 非字符串(数组、数字等) | 报 INVALID_PARAM |
纯静态项落到项目根是合法形态,终端会打印实际上传目录并提示:
[my-app] 上传产物:项目根(/path/to/project)
纯静态站点可保持此配置;前端项目建议用 app.outputDir 指定产物目录(如 dist),并先执行 tcb app build
前端项目建议显式写 outputDir,否则源码(含 .env)会被当作产物上传:
{
"app": {
"serviceName": "my-app",
"outputDir": "dist"
}
}
产物目录不存在或为空时,部署阶段报 BUILD_OUTPUT_NOT_FOUND,提示先执行 tcb app build;--dry-run 下只标记该资源产物未就绪。
tcb app deploy的取值顺序不同:--output-dir>app.outputDir> 自动检测 > 交互询问 / 默认值(有构建步骤./dist,无构建步骤./)。
2. gateway.routes 校验失败(should NOT have additional properties)
cloudbaserc.json 不允许额外字段。例如 cdnType 不是合法路由字段,应移除;CDN 接入方式用 accessType(DIRECT / CDN / CUSTOM / EO)控制:
{ "path": "/web", "target": "hosting:web", "accessType": "DIRECT" }
3. HTTP 函数依赖安装规则
| 函数类型 | 运行时 | 依赖安装方式 |
|---|---|---|
| Event | 任意 | 云端在线安装(默认) |
| HTTP | Node.js | 云端在线安装(默认) |
| HTTP | 非 Node.js(Python / Php / Java / Go) | 必须本地安装后随代码包上传 |
HTTP 非 Node.js 函数需确保本机已安装依赖(如 Python pip install 到函数目录)。
4. 已存在函数是否覆盖?
云端已存在的函数默认需要确认,--yes 放行。
5. 网关路由在已绑定域名上,域名级字段不生效
certId / protocol / accessType 是域名级字段,同一域名所有路由共享。在已存在的域名上创建路由时,这些字段不会覆盖域名原值(如域名已绑定 HTTP_AND_HTTPS,配置 protocol: "HTTPS" 不生效),避免影响同域名下其他业务路由。它们只在首次创建域名时生效。
6. 网关路由幂等语义
网关路由是幂等收敛(create / update / skip):
- 路由不存在 → 创建
- 路由已存在且显式声明的字段一致 → 跳过
- 路由已存在但显式声明的字段不一致 → 更新(调用
modifyHttpServiceRoute)
只比较显式声明的字段(enableAuth / enablePathTransmission 显式配置才比较,qpsPolicy / pathRewrite 本地有值才比较),未声明的字段不会覆盖云端配置。重复路径不会被当作错误(与命令式 tcb routes add 的 INVALID_PARAM 不同)。字段定义见配置文件-网关。