05-go-agent-development

TencentBlueKing's avatarfrom TencentBlueKing

Go Agent 开发指南,涵盖 Agent 架构设计、心跳机制、任务执行、日志上报、升级流程、与 Dispatch 模块交互。当用户开发构建机 Agent、实现任务执行逻辑、处理 Agent 通信或进行 Go 语言开发时使用。

⭐2.5kstars🔀514forks📁View on GitHub🕐Updated Jan 9, 2026

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.
name05-go-agent-development
descriptionGo 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()
}