05-go-agent-development
Go Agent 开发指南,涵盖 Agent 架构设计、心跳机制、任务执行、日志上报、升级流程、与 Dispatch 模块交互。当用户开发构建机 Agent、实现任务执行逻辑、处理 Agent 通信或进行 Go 语言开发时使用。
When & Why to Use This Skill
This Claude skill provides a comprehensive development guide for building Go-based CI agents, specifically tailored for the BK-CI ecosystem. It covers essential architectural components including heartbeat mechanisms, task execution logic, log reporting, and seamless interaction with dispatch modules. By following these standardized Go practices, developers can create robust, scalable, and maintainable build agents for automated CI/CD pipelines.
Use Cases
- Architecting and developing custom build machine agents from scratch using Go for enterprise CI/CD platforms.
- Implementing reliable communication protocols and heartbeat mechanisms between distributed agents and backend dispatch services.
- Designing task execution engines and pipeline processing logic to handle complex automated build jobs.
- Standardizing Go project structures and coding conventions (naming, error handling, concurrency) for large-scale agent development teams.
- Managing agent lifecycles, including automated upgrade flows, process monitoring (Daemon/Agent), and system resource cleanup.
| name | 05-go-agent-development |
|---|---|
| description | Go Agent 开发指南,涵盖 Agent 架构设计、心跳机制、任务执行、日志上报、升级流程、与 Dispatch 模块交互。当用户开发构建机 Agent、实现任务执行逻辑、处理 Agent 通信或进行 Go 语言开发时使用。 |
Skill 05: Go Agent 开发
概述
BK-CI 的构建代理(Agent)使用 Go 语言编写,负责与后端服务通信、执行构建任务。
技术栈
| 组件 | 版本 | 用途 |
|---|---|---|
| Go | 1.19+ | 编程语言 |
| go.mod | - | 依赖管理 |
| agentcommon/logs | - | 日志框架 |
项目结构
src/agent/
├── agent/ # 主代理
│ └── src/pkg/
│ ├── api/ # API 调用
│ ├── config/ # 配置管理
│ ├── collector/ # 数据采集
│ ├── job/ # 任务执行
│ ├── pipeline/ # 流水线处理
│ └── util/ # 工具函数
├── agent-slim/ # 轻量版代理
└── common/ # 通用库
命名规范
包命名
- 小写单词,不使用下划线
- 示例:
agent,api,config,collector,job,pipeline,util
结构体命名
使用 PascalCase:
type ThirdPartyAgentStartInfo struct {
HostName string `json:"hostname"`
HostIp string `json:"hostIp"`
DetectOs string `json:"detectOS"`
MasterVersion string `json:"masterVersion"`
SlaveVersion string `json:"version"`
}
type ThirdPartyBuildInfo struct {
ProjectId string `json:"projectId"`
BuildId string `json:"buildId"`
ToDelTmpFiles []string `json:"-"` // 不序列化字段
}
常量定义
const (
KeyProjectId = "devops.project.id"
KeyAgentId = "devops.agent.id"
KeySecretKey = "devops.agent.secret.key"
KeyDevopsGateway = "landun.gateway"
)
枚举类型
type BuildJobType string
const (
AllBuildType BuildJobType = "ALL"
DockerBuildType BuildJobType = "DOCKER"
BinaryBuildType BuildJobType = "BINARY"
)
配置管理
// config/config.go
type AgentConfig struct {
Gateway string
ProjectId string
AgentId string
SecretKey string
ParallelTaskCount int
}
var GAgentConfig *AgentConfig
func Init() {
GAgentConfig = &AgentConfig{
Gateway: getConfigValue(KeyDevopsGateway),
ProjectId: getConfigValue(KeyProjectId),
AgentId: getConfigValue(KeyAgentId),
SecretKey: getConfigValue(KeySecretKey),
}
}
func GetGateWay() string {
return GAgentConfig.Gateway
}
API 调用模式
// api/api.go
func buildUrl(url string) string {
return config.GetGateWay() + url
}
func AgentStartup() (*httputil.DevopsResult, error) {
url := buildUrl("/ms/environment/api/buildAgent/agent/thirdPartyAgent/startup")
startInfo := &ThirdPartyAgentStartInfo{
HostName: systemutil.GetHostName(),
HostIp: systemutil.GetAgentIp(),
DetectOs: systemutil.GetOsName(),
MasterVersion: config.AgentVersion,
SlaveVersion: config.WorkerVersion,
}
return httputil.NewHttpClient().Post(url).Body(startInfo, false).
SetHeaders(config.GAgentConfig.GetAuthHeaderMap()).Execute(nil).IntoDevopsResult()
}
错误处理模式
标准错误检查
if err != nil {
logs.WithError(err).Error("init third_components error")
systemutil.ExitProcess(1)
}
重试模式
_, err := job.AgentStartup()
if err != nil {
logs.WithError(err).Error("agent startup failed")
for {
_, err = job.AgentStartup()
if err == nil {
break
}
logs.WithError(err).Error("agent startup failed")
time.Sleep(5 * time.Second)
}
}
Panic 恢复
defer func() {
if err := recover(); err != nil {
logs.Error("agent collect panic: ", err)
}
}()
日志记录规范
// 日志级别使用
logs.Debug("do Collect")
logs.Info("agent collector off")
logs.Infof("collect ip change data: %s", ipData.Data)
logs.Error("agent collect panic: ", err)
logs.WithError(err).Error("init third_components error")
并发模式
启动 goroutine
go collector.Collect()
go cron.CleanJob()
使用 defer 清理资源
defer config.EBus.Unsubscribe(config.IpEvent, eBusId)
Channel 通信
// 创建 channel
done := make(chan bool)
// 发送数据
done <- true
// 接收数据
<-done
测试规范
测试文件命名
*_test.go
测试示例
// build_test.go
package job
import (
"testing"
)
func TestBuildJob(t *testing.T) {
// 测试逻辑
}
func TestParseJobType(t *testing.T) {
tests := []struct {
input string
expected BuildJobType
}{
{"ALL", AllBuildType},
{"DOCKER", DockerBuildType},
{"BINARY", BinaryBuildType},
}
for _, tt := range tests {
result := ParseJobType(tt.input)
if result != tt.expected {
t.Errorf("ParseJobType(%s) = %v, want %v", tt.input, result, tt.expected)
}
}
}
HTTP 客户端封装
type HttpClient struct {
client *http.Client
request *http.Request
}
func NewHttpClient() *HttpClient {
return &HttpClient{
client: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *HttpClient) Get(url string) *HttpClient {
req, _ := http.NewRequest("GET", url, nil)
c.request = req
return c
}
func (c *HttpClient) Post(url string) *HttpClient {
req, _ := http.NewRequest("POST", url, nil)
c.request = req
return c
}
func (c *HttpClient) SetHeaders(headers map[string]string) *HttpClient {
for k, v := range headers {
c.request.Header.Set(k, v)
}
return c
}
func (c *HttpClient) Execute(body interface{}) *HttpResponse {
resp, err := c.client.Do(c.request)
// 处理响应
return &HttpResponse{resp: resp, err: err}
}
系统工具函数
// util/systemutil/systemutil.go
func GetHostName() string {
hostname, _ := os.Hostname()
return hostname
}
func GetAgentIp() string {
addrs, _ := net.InterfaceAddrs()
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return ""
}
func GetOsName() string {
return runtime.GOOS
}
func ExitProcess(code int) {
os.Exit(code)
}
进程管理
Agent 由两个进程组成:
- DevopsDaemon:守护进程,负责启动和监控 Agent
- DevopsAgent:主进程,负责与服务端通信和执行任务
// 启动 Worker 进程
func StartWorker(buildInfo *ThirdPartyBuildInfo) error {
cmd := exec.Command(workerPath, buildInfo.BuildId)
cmd.Dir = workDir
cmd.Env = os.Environ()
return cmd.Start()
}