cnb提供了一些api的sdk,有go、python类型的,这里使用cnb/sdk/go-cnb:
go get cnb.cool/cnb/sdk/go-cnb # 获取 go-cnb 的最新 tag 代码 go get cnb.cool/cnb/sdk/go-cnb@v1.0.0 # 获取 go-cnb 的特定 tag 代码 go mod tidy
import "cnb.cool/cnb/sdk/go-cnb/cnb"
创建一个 CNB Client, 然后使用一系列的服务来访问 CNB 的 API。
client, _ = cnb.NewClient(nil).WithAuthToken("...your cnb token...").WithURLs("...cnb base url...")
repo, rsp, err := client.Repositories.GetRepo(ctx, repoName)
对于需要鉴权的 URL, 可以在 CNB 的 个人设置 -> 访问令牌中申请合适权限的 TOKEN。BaseURL 的规则为
api.前缀加主域名,比如https://api.cnb.cool/
➜ /workspace git:(main) ✗ tree . ├── Makefile ├── go.mod ├── go.sum ├── icnb │ └── client.go └── main.go
package icnb
import (
"os"
"cnb.cool/cnb/sdk/go-cnb/cnb"
)
var Client *cnb.Client
func init() {
var err error
token := os.Getenv("CNB_TOKEN")
if token == "" {
token = "xxxxxxx"
}
baseUrl := os.Getenv("CNB_BASE_URL")
if baseUrl == "" {
baseUrl = "https://api.cnb.cool/"
}
Client, err = cnb.NewClient(nil).WithAuthToken(token).WithURLs(baseUrl)
if err != nil {
panic(err)
}
}
package main
import (
"context"
"fmt"
"log"
"os"
"cnb-custom-env/icnb"
"cnb.cool/cnb/sdk/go-cnb/cnb"
)
func main() {
// 从命令行参数获取模式
if len(os.Args) < 2 {
fmt.Println("用法: cce <mode> [args...]")
fmt.Println("模式:")
fmt.Println(" default <repo-slug> [branch] - 启动默认工作空间")
fmt.Println(" custom - 启动自定义环境(固定参数)")
fmt.Println("示例:")
fmt.Println(" cce default sumu.k/cnb-custom-env main")
fmt.Println(" cce custom")
os.Exit(1)
}
mode := os.Args[1]
switch mode {
case "default":
// 启动默认工作空间
if len(os.Args) < 3 {
fmt.Println("用法: cce default <repo-slug> [branch]")
fmt.Println("示例: cce default sumu.k/cnb-custom-env main")
os.Exit(1)
}
repoSlug := os.Args[2]
branch := "main"
if len(os.Args) >= 4 {
branch = os.Args[3]
}
if err := StartDefaultWorkspace(repoSlug, branch); err != nil {
log.Fatalf("启动开发环境失败: %v", err)
}
case "custom":
// 启动自定义环境(测试)
if err := StartCustomEnvironment(); err != nil {
log.Fatalf("启动自定义环境失败: %v", err)
}
default:
fmt.Printf("未知模式: %s\n", mode)
fmt.Println("可用模式: default, custom")
os.Exit(1)
}
}
/**
* @brief 启动默认云原生开发环境
*
* 镜像和配置来源:CNB 服务端会读取目标仓库指定分支下的 .cnb.yml 配置文件
* 例如:repoSlug="sumu.k/cnb-custom-env", branch="main" 时,读取该仓库 main 分支的 .cnb.yml
* .cnb.yml 中定义了开发环境镜像 (docker.image)、服务 (services)、启动脚本 (stages) 等配置
*
* @param repoSlug 仓库标识,格式为 "用户名/仓库名",如 "sumu.k/cnb-custom-env"
* @param branch 分支名称,默认使用 "main"
* @return 成功返回 nil,失败返回 error
*/
func StartDefaultWorkspace(repoSlug, branch string) error {
log.Printf("🚀 正在启动开发环境: %s (分支: %s)", repoSlug, branch)
rst, rsp, err := icnb.Client.Workspace.StartWorkspace(context.TODO(), repoSlug, &cnb.StartWorkspaceRequest{
Branch: branch,
Ref: fmt.Sprintf("refs/heads/%s", branch),
})
if err != nil {
log.Printf("❌ 启动失败: %v", err)
return err
}
if rsp.StatusCode != 200 {
log.Printf("❌ 启动失败, 状态码: %d", rsp.StatusCode)
return fmt.Errorf("启动失败, 状态码: %d", rsp.StatusCode)
}
log.Printf("🎉 开发环境启动成功!")
log.Printf("📡 访问地址: %s", rst.Url)
log.Printf("📋 构建日志: %s", rst.BuildLogUrl)
log.Printf("🔢 工作空间 SN: %s", rst.Sn)
if rst.Message != "" {
log.Printf("💬 消息: %s", rst.Message)
}
return nil
}
/**
* @brief 生成配置 YAML
*
* 根据镜像、CPU 核数和集群标签生成构建配置 YAML
*
* @param image 镜像地址
* @param cpus CPU 核数
* @param tag 集群标签
* @return 配置 YAML 字符串
*/
func generateConfigYAML(image string, cpus int, tag string) string {
return fmt.Sprintf(`.vscode: &vscode
api_trigger_sumu:
clouddev:
docker:
image: %s
runner:
cpus: %d
tags:
- %s
services:
- vscode
- docker
pipeline:
runner:
cpus: %d
tags:
- %s
include:
- config:
$: *vscode
- path: .cnb.yml
ignoreError: true`, image, cpus, tag, cpus, tag)
}
/**
* @brief 启动自定义环境(简化版)
*
* 使用固定参数启动自定义构建环境,镜像和集群配置预定义
*
* @return 成功返回 nil,失败返回 error
*/
func StartCustomEnvironment() error {
// 固定参数配置
repoSlug := "W3C/sumu/cnb-demo"
branch := "main"
image := "docker.cnb.cool/sumu.k/docker-learning/embedded-env"
cpus := 8
tag := "cnb:arch:amd64"
log.Printf("🚀 Preparing to start custom environment for %s on branch %s", repoSlug, branch)
// 显示配置摘要
log.Printf("📊 Environment configuration:")
log.Printf(" Repository: %s", repoSlug)
log.Printf(" Branch: %s", branch)
log.Printf(" Image: %s", image)
log.Printf(" Cluster: %s (AMD64架构通用集群)", tag)
log.Printf(" Architecture: amd64")
log.Printf(" CPU cores: %d", cpus)
// 生成配置 YAML
configYaml := generateConfigYAML(image, cpus, tag)
log.Printf("⏳ Starting build process...")
rst, rsp, err := icnb.Client.Build.StartBuild(context.TODO(), repoSlug, &cnb.StartBuildRequest{
Branch: branch,
Config: configYaml,
Env: map[string]string{},
Event: "api_trigger_sumu",
Sha: "",
Sync: "",
Tag: "",
})
if err != nil {
log.Printf("❌ Error starting custom environment: %v", err)
return err
}
if rsp.StatusCode != 200 {
log.Printf("❌ Failed to start custom environment. Status: %d", rsp.StatusCode)
return fmt.Errorf("failed to start custom environment, status code: %d", rsp.StatusCode)
}
log.Printf("🎉 Successfully started custom environment!")
log.Printf("📝 Build log URL: %v", rst.BuildLogUrl)
log.Printf("📊 Final resource allocation: %d CPUs on %s cluster", cpus, tag)
// 提供使用提示
log.Printf("💡 Usage tips:")
log.Printf(" • You're using AMD64 architecture - suitable for most development scenarios")
log.Printf(" • CPU range: 1-64 cores (default: 8)")
log.Printf(" • Environment initialization may take a few minutes")
log.Printf(" • Check the build logs for detailed progress information")
return nil
}
# 项目名称
TARGET := cce
# 成果物目录
BIN_DIR := bin
# 成果物路径
BINARY := $(BIN_DIR)/$(TARGET)
# 源码文件(自动匹配)
SRC_FILES := $(wildcard *.go **/*.go)
# 编译(使用隐含规则,自动判断是否需要重新编译)
$(BINARY): $(SRC_FILES)
@mkdir -p $(BIN_DIR)
go build -o $@ .
# 运行
run: $(BINARY)
./$(BINARY) W3C/sumu/cnb-demo
# 测试默认工作空间
env_default: $(BINARY)
./$(BINARY) default W3C/sumu/cnb-demo
# 测试自定义环境
env_custom: $(BINARY)
./$(BINARY) custom
# 清理
clean:
rm -rf $(BIN_DIR)
.PHONY: run env_default env_custom clean
module cnb-custom-env
go 1.26.1
require cnb.cool/cnb/sdk/go-cnb v1.18.8
require github.com/google/go-querystring v1.1.0 // indirect
安装模块后会自动更新这个文件,我们还需要同步代码依赖项:
go mod tidy
make # 编译 make env_default # 使用指定仓库的.cnb.yml启动默认云原生开发环境 make env_custom # 使用自定义参数(测试程序内部固定了)启动云原生开发环境
参考项目:znb/start-custom-environment
参考资料: