Team 配额管理用于为指定 Team 设置云沙箱资源配额,限制该 Team 可使用的 CPU 和内存总量。多团队、多业务或多环境共用云沙箱时,可以通过 Team 配额做资源隔离、成本控制和容量治理。
Team 配额功能是E2B SDK之外的扩展能力,通过阿里云 POP SDK 管理。创建与访问 Sandbox 仍需云沙箱 API Key,在函数计算控制台完成;配额接口本身使用阿里云 AccessKey,不依赖 API Key。创建 Team、选择资源组与订阅计划的控制台操作,参见创建 Team。
前提条件
使用 Team 配额管理前,请先准备:
-
已开通函数计算和云沙箱。
-
已在阿里云控制台联系客服完成加白。
-
已按创建 Team在函数计算控制台创建 Team,并获取需要配置配额的 Team ID。
-
已准备用于调用 POP SDK 的阿里云 AccessKey。
-
AccessKey 所属 RAM 用户或角色具备
fcsandbox配额管理权限。 -
已确认服务 Endpoint,例如
fcsandbox.cn-beijing.aliyuncs.com。
配额模型
Team 配额以 Team ID 作为标识,通过 TagValue 传入。当前配额项包括 CPU 核数和内存 GB 数。
|
字段 |
类型 |
是否必填 |
约束 |
说明 |
|
|
|
是 |
匹配 |
配额标识,填写 Team ID。 |
|
|
|
是 |
大于等于 0 |
CPU 核数配额。 |
|
|
|
是 |
大于等于 0 |
内存 GB 配额。 |
CpuCores 或 MemoryGB 设置为 0 表示对应资源配额为 0,相当于禁止该 Team 使用对应资源。多次调用更新接口时,新值会覆盖旧值。
API 概览
|
操作 |
Go 方法 |
说明 |
|
创建或更新配额 |
|
设置 Team 的 CPU 和内存配额。 |
|
查询配额 |
|
查询指定 Team 的配额。 |
|
列出配额 |
|
列出当前账号下的配额。 |
|
删除配额 |
|
删除指定 Team 的配额。 |
RAM 授权
调用配额管理接口的 RAM 用户或角色需要具备对应权限。服务的 RAM 授权码为 fcsandbox。
|
Action |
说明 |
|
|
创建或更新配额。 |
|
|
查询指定 Team 配额。 |
|
|
列出配额。 |
|
|
删除配额。 |
完整管理权限示例:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"fcsandbox:UpdateQuota",
"fcsandbox:DescribeQuota",
"fcsandbox:ListQuota",
"fcsandbox:DeleteQuota"
],
"Resource": "*"
}
]
}
只读权限示例:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"fcsandbox:DescribeQuota",
"fcsandbox:ListQuota"
],
"Resource": "*"
}
]
}
如果需要按地域或账号收敛资源范围,可以将 Resource 从 * 调整为 acs:fcsandbox:<region>:<account-id>:*,例如 acs:fcsandbox:cn-beijing:123456789012:*。
Go SDK 使用说明
可以使用阿里云 POP Go SDK 管理团队配额。Go 版本的方法名为 PascalCase,例如 UpdateQuota、DescribeQuota、ListQuota 和 DeleteQuota。请求和响应字段均为指针类型,需要配合 tea 包的 tea.String、tea.Int32 等辅助函数进行装箱与拆箱。
安装依赖
go get github.com/alibabacloud-go/fcsandbox-20260509/client
go get github.com/alibabacloud-go/darabonba-openapi/v2/utils
go get github.com/alibabacloud-go/tea/tea
涉及的包如下:
|
包 |
导入路径 |
作用 |
|
SDK 客户端 |
|
配额管理接口。 |
|
OpenAPI 配置 |
|
客户端配置,包括 AK/SK 和 Endpoint。 |
|
tea 工具 |
|
指针装箱和拆箱辅助函数。 |
Step 1:初始化 SDK 客户端
建议通过环境变量传入 AccessKey,不要把 AK/SK 写入代码、镜像、模板或日志。
以下示例展示初始化客户端的核心代码:
import (
"log"
"os"
fcsandbox "github.com/alibabacloud-go/fcsandbox-20260509/client"
openapiutil "github.com/alibabacloud-go/darabonba-openapi/v2/utils"
"github.com/alibabacloud-go/tea/tea"
)
config := &openapiutil.Config{
AccessKeyId: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
SecurityToken: tea.String(os.Getenv("ALIBABA_CLOUD_SECURITY_TOKEN")),
Endpoint: tea.String("fcsandbox.cn-beijing.aliyuncs.com"),
}
client, err := fcsandbox.NewClient(config)
if err != nil {
log.Fatalf("init client failed: %v", err)
}
运行前设置环境变量:
export ALIBABA_CLOUD_ACCESS_KEY_ID="<your-access-key-id>"
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="<your-access-key-secret>"
# 仅使用 STS 临时凭证时需要设置。
# export ALIBABA_CLOUD_SECURITY_TOKEN="<your-security-token>"
Step 2:创建资源配额
使用 UpdateQuota 为 Team 设置 CPU 和内存配额。TagValue 填写 Team ID。
resp, err := client.UpdateQuota(&fcsandbox.UpdateQuotaRequest{
Body: &fcsandbox.Quota{
TagValue: tea.String("{team-id}"),
CpuCores: tea.Int32(32),
MemoryGB: tea.Int32(32),
},
})
if err != nil {
log.Fatalf("update quota failed: %v", err)
}
quota := resp.Body.Quota
log.Printf("quota created: cpu=%d, memory=%d",
tea.Int32Value(quota.CpuCores),
tea.Int32Value(quota.MemoryGB),
)
参数说明:
|
参数 |
类型 |
必填 |
约束 |
说明 |
|
|
|
是 |
匹配 |
配额标识,填写 Team ID。 |
|
|
|
是 |
大于等于 0 |
CPU 核数配额。 |
|
|
|
是 |
大于等于 0 |
内存 GB 配额。 |
UpdateQuota 是覆盖式更新。同一个 TagValue 多次调用时,后一次配置会替换前一次配置。
Step 3:查询配额
resp, err := client.DescribeQuota(&fcsandbox.DescribeQuotaRequest{
TagValue: tea.String("{team-id}"),
})
if err != nil {
log.Fatalf("describe quota failed: %v", err)
}
quota := resp.Body.Quota
log.Printf("quota: cpu=%d, memory=%d",
tea.Int32Value(quota.CpuCores),
tea.Int32Value(quota.MemoryGB),
)
Step 4:列出所有配额
var nextToken *string
for {
resp, err := client.ListQuota(&fcsandbox.ListQuotaRequest{
MaxResults: tea.Int32(100),
NextToken: nextToken,
})
if err != nil {
log.Fatalf("list quota failed: %v", err)
}
for _, quota := range resp.Body.Quotas {
log.Printf("quota: tagValue=%s, cpu=%d, memory=%d",
tea.StringValue(quota.TagValue),
tea.Int32Value(quota.CpuCores),
tea.Int32Value(quota.MemoryGB),
)
}
nextToken = resp.Body.NextToken
if tea.StringValue(nextToken) == "" {
break
}
}
分页参数:
-
MaxResults:每页条数。 -
NextToken:翻页令牌,从上次响应的resp.Body.NextToken获取。
Step 5:更新配额
使用同一个 UpdateQuota 接口覆盖更新:
resp, err := client.UpdateQuota(&fcsandbox.UpdateQuotaRequest{
Body: &fcsandbox.Quota{
TagValue: tea.String("{team-id}"),
CpuCores: tea.Int32(64),
MemoryGB: tea.Int32(64),
},
})
if err != nil {
log.Fatalf("update quota failed: %v", err)
}
quota := resp.Body.Quota
log.Printf("quota updated: cpu=%d, memory=%d",
tea.Int32Value(quota.CpuCores),
tea.Int32Value(quota.MemoryGB),
)
Step 6:删除配额
resp, err := client.DeleteQuota(&fcsandbox.DeleteQuotaRequest{
TagValue: tea.String("{team-id}"),
})
if err != nil {
log.Fatalf("delete quota failed: %v", err)
}
log.Printf("quota deleted: requestId=%s", tea.StringValue(resp.Body.RequestId))
删除后再次调用 DescribeQuota 查询同一个 TagValue,最终会返回 404 / ResourceQuotaNotFound。如果删除存在短暂的最终一致性延迟,业务代码应使用有上限的轮询确认。
错误处理
Go SDK 的接口错误通常为 *tea.SDKError,可通过 errors.As 读取 Code、StatusCode 和 Message。如果不是该类型,应继续记录或返回原始错误。使用以下代码时需导入 errors 包。
var sdkErr *tea.SDKError
_, err := client.DescribeQuota(&fcsandbox.DescribeQuotaRequest{
TagValue: tea.String("{team-id}"),
})
if err != nil {
if errors.As(err, &sdkErr) {
log.Printf("code=%s, statusCode=%d, message=%s",
tea.StringValue(sdkErr.Code),
tea.IntValue(sdkErr.StatusCode),
tea.StringValue(sdkErr.Message),
)
} else {
log.Printf("request failed: %v", err)
}
}
错误码含义参见下文「错误码参考」。
完整示例
下面是一个可直接运行的完整示例 main.go,依次执行创建、查询、列表、更新、删除和确认删除。
警告:该示例会两次覆盖指定 Team 的配额,并在最后删除该配额。请仅对无业务且未配置既有配额的测试 Team 执行。生产 Team 不要直接运行该完整示例;请根据实际资源需求执行对应的单个操作示例。
package main
import (
"errors"
"fmt"
"log"
"os"
"time"
fcsandbox "github.com/alibabacloud-go/fcsandbox-20260509/client"
openapiutil "github.com/alibabacloud-go/darabonba-openapi/v2/utils"
"github.com/alibabacloud-go/tea/tea"
)
const (
endpoint = "fcsandbox.cn-beijing.aliyuncs.com"
)
func main() {
ak := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
sk := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
if ak == "" || sk == "" {
log.Fatal("请设置 ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET")
}
teamID := os.Getenv("FCSANDBOX_TEAM_ID")
if teamID == "" {
log.Fatal("请设置 FCSANDBOX_TEAM_ID")
}
client, err := fcsandbox.NewClient(&openapiutil.Config{
AccessKeyId: tea.String(ak),
AccessKeySecret: tea.String(sk),
SecurityToken: tea.String(os.Getenv("ALIBABA_CLOUD_SECURITY_TOKEN")),
Endpoint: tea.String(endpoint),
})
if err != nil {
log.Fatalf("init client failed: %v", err)
}
// 1. 创建配额
createResp, err := client.UpdateQuota(&fcsandbox.UpdateQuotaRequest{
Body: &fcsandbox.Quota{
TagValue: tea.String(teamID),
CpuCores: tea.Int32(32),
MemoryGB: tea.Int32(32),
},
})
if err != nil {
log.Fatalf("create quota failed: %v", err)
}
fmt.Printf("[1] created: cpu=%d, mem=%d\n",
tea.Int32Value(createResp.Body.Quota.CpuCores),
tea.Int32Value(createResp.Body.Quota.MemoryGB))
// 2. 查询配额
getResp, err := client.DescribeQuota(&fcsandbox.DescribeQuotaRequest{
TagValue: tea.String(teamID),
})
if err != nil {
log.Fatalf("describe quota failed: %v", err)
}
fmt.Printf("[2] describe: cpu=%d, mem=%d\n",
tea.Int32Value(getResp.Body.Quota.CpuCores),
tea.Int32Value(getResp.Body.Quota.MemoryGB))
// 3. 列出所有配额
total := 0
var nextToken *string
for {
listResp, err := client.ListQuota(&fcsandbox.ListQuotaRequest{
MaxResults: tea.Int32(100),
NextToken: nextToken,
})
if err != nil {
log.Fatalf("list quota failed: %v", err)
}
for _, q := range listResp.Body.Quotas {
total++
fmt.Printf(" tagValue=%s, cpu=%d, mem=%d\n",
tea.StringValue(q.TagValue),
tea.Int32Value(q.CpuCores),
tea.Int32Value(q.MemoryGB),
)
}
nextToken = listResp.Body.NextToken
if tea.StringValue(nextToken) == "" {
break
}
}
fmt.Printf("[3] list: %d quotas\n", total)
// 4. 更新配额
updResp, err := client.UpdateQuota(&fcsandbox.UpdateQuotaRequest{
Body: &fcsandbox.Quota{
TagValue: tea.String(teamID),
CpuCores: tea.Int32(64),
MemoryGB: tea.Int32(64),
},
})
if err != nil {
log.Fatalf("update quota failed: %v", err)
}
fmt.Printf("[4] updated: cpu=%d, mem=%d\n",
tea.Int32Value(updResp.Body.Quota.CpuCores),
tea.Int32Value(updResp.Body.Quota.MemoryGB))
// 5. 删除配额
delResp, err := client.DeleteQuota(&fcsandbox.DeleteQuotaRequest{
TagValue: tea.String(teamID),
})
if err != nil {
log.Fatalf("delete quota failed: %v", err)
}
fmt.Printf("[5] deleted (requestId=%s)\n", tea.StringValue(delResp.Body.RequestId))
// 6. 确认删除,预期最终返回 404。
for attempt := 1; attempt <= 5; attempt++ {
_, err = client.DescribeQuota(&fcsandbox.DescribeQuotaRequest{
TagValue: tea.String(teamID),
})
if err == nil {
if attempt == 5 {
log.Fatal("[6] expected 404 but describe still succeeded")
}
time.Sleep(time.Duration(attempt) * time.Second)
continue
}
var sdkErr *tea.SDKError
if !errors.As(err, &sdkErr) {
log.Fatalf("confirm deletion failed: %v", err)
}
if tea.IntValue(sdkErr.StatusCode) != 404 ||
tea.StringValue(sdkErr.Code) != "ResourceQuotaNotFound" {
log.Fatalf("confirm deletion failed: statusCode=%d, code=%s",
tea.IntValue(sdkErr.StatusCode),
tea.StringValue(sdkErr.Code),
)
}
fmt.Printf("[6] confirmed deletion: statusCode=%d, code=%s\n",
tea.IntValue(sdkErr.StatusCode),
tea.StringValue(sdkErr.Code),
)
break
}
fmt.Println("ALL STEPS PASSED")
}
运行前设置环境变量:
export ALIBABA_CLOUD_ACCESS_KEY_ID="<your-access-key-id>"
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="<your-access-key-secret>"
# 仅使用 STS 临时凭证时需要设置。
# export ALIBABA_CLOUD_SECURITY_TOKEN="<your-security-token>"
export FCSANDBOX_TEAM_ID="<team-id>"
go run main.go
错误码参考
常见错误如下:
|
HTTP 状态码 |
Code |
说明 |
|
400 |
|
请求参数校验失败,例如缺少必填字段或格式不合法。 |
|
401 |
|
凭证无效或未提供。 |
|
403 |
|
无权操作。 |
|
404 |
|
查询的配额不存在。 |
|
429 |
|
超出配额限制。 |
|
500 |
|
服务内部错误,请重试。 |
常见问题
TagValue 应该填什么?
填写 Team ID。
如何获取 Team ID?
在函数计算云沙箱控制台创建 Team 后,打开左侧 Team 选择器中的管理 Team,可在列表中查看并复制 Team ID。创建 Team 和获取 Team ID 的方法参见创建 Team。
CpuCores 和 MemoryGB 可以设为 0 吗?
可以。0 表示配额为 0,相当于禁止该 Team 使用对应资源。不允许设置为负数。
多次调用 UpdateQuota 同一个 TagValue 会怎样?
UpdateQuota 是幂等的覆盖操作。每次调用都会用新值替换旧值。
删除配额后再查询会怎样?
删除后再查询同一个 TagValue 最终会返回 404 / ResourceQuotaNotFound。如果删除存在短暂的最终一致性延迟,可使用有上限的轮询确认。
使用建议
-
生产 Team、测试 Team、批处理 Team 建议分别设置配额。
-
不要让测试任务和生产任务共用同一个高配额 Team。
-
调低配额前,应先确认当前运行中的 Sandbox 和业务峰值。
-
删除配额前,应确认该 Team 不再需要独立配额。
-
配额耗尽时,业务侧应使用队列、并发上限、超时和退避重试,避免放大失败。
-
Sandbox 任务完成后仍应主动调用
sandbox.kill()释放资源。
注意事项
-
Team 配额管理使用 POP SDK 和阿里云 AK/SK,不使用云沙箱 API Key 鉴权。
-
云沙箱 API Key 仍通过函数计算控制台创建和管理。
-
不要把 AK/SK、API Key 写入代码仓库、镜像、模板、日志、截图、工单或前端页面。
-
Team 配额管理是云沙箱控制面管理能力,不是 E2B SDK 兼容 API。
-
配额只解决资源上限问题,不能替代业务侧限流、任务队列、超时控制和资源释放。