package runner import ( "context" "fmt" "net" "strings" "time" actions_module "code.gitea.io/gitea/models/actions" docker_module "code.gitea.io/gitea/modules/docker" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) func RegistGlobalRunner(ctx context.Context) error { log.Info("获取全局RunnerToken...") actionRunnerToken, err := actions_module.NewRunnerToken(ctx, 0, 0) if err != nil { return fmt.Errorf("获取全局RunnerToken失败:%v", err) } runnerCount := setting.Runner.Count for i := 0; i < runnerCount; i++ { err := RegistRunner(ctx, actionRunnerToken.Token) if err != nil { return fmt.Errorf("注册Runner失败:%v", err) } } return nil } func RegistRunner(ctx context.Context, token string) error { log.Info("开始注册Runner...") cli, err := docker_module.CreateDockerClient(&ctx) if err != nil { return fmt.Errorf("Docker client创建失败:%v", err) } log.Info("[RegistRunner]Docker client创建成功") defer cli.Close() //拉取act_runner镜像 dockerHost, err := docker_module.GetDockerSocketPath() if err != nil { return fmt.Errorf("获取docker socket路径失败:%v", err) } // 拉取镜像 err = docker_module.PullImageSync(cli, dockerHost, setting.Runner.Image) if err != nil { return fmt.Errorf("拉取act_runner镜像失败:%v", err) } //获取本机IP ips, err := getLocalIP() if err != nil { return fmt.Errorf("获取本机IP失败:%v", err) } //获取InstanceUrl conntype := strings.Split(setting.AppURL, "://")[0] port := setting.HTTPPort instanceURL := conntype + "://" + ips[0] + ":" + port timestamp := time.Now().Format("20060102150405") //Runner配置 env := []string{ "GITEA_INSTANCE_URL=" + instanceURL, "GITEA_RUNNER_REGISTRATION_TOKEN=" + token, "GITEA_RUNNER_NAME=runner-" + timestamp, } binds := []string{ "/var/run/docker.sock:/var/run/docker.sock", } containerName := "runner-" + timestamp //创建并启动Runner容器 opts := &docker_module.CreateDevcontainerOptions{ Name: containerName, Image: setting.Runner.Image, Binds: binds, ContainerEnv: env, } _, err = docker_module.CreateAndStartContainer(cli, opts) if err != nil { return fmt.Errorf("创建并注册Runner失败:%v", err) } return nil } func DeleteRunnerByName(ctx context.Context, runnerName string) error { log.Info("开始停止并删除容器: %s", runnerName) // 创建Docker客户端 cli, err := docker_module.CreateDockerClient(&ctx) if err != nil { return fmt.Errorf("Docker client创建失败:%v", err) } log.Info("[StopAndRemoveContainer]Docker client创建成功") defer cli.Close() err = docker_module.DeleteContainer(cli, runnerName) if err != nil { return fmt.Errorf("Runner创建失败:%v", err) } return nil } func getLocalIP() ([]string, error) { var ips []string interfaces, err := net.Interfaces() if err != nil { return nil, err } for _, iface := range interfaces { if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { continue } addrs, err := iface.Addrs() if err != nil { continue } // 遍历地址列表 for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP case *net.IPAddr: ip = v.IP } if ip == nil || ip.IsLoopback() { continue } ip = ip.To4() if ip == nil { continue // 非IPv4地址 } ips = append(ips, ip.String()) } } if len(ips) == 0 { return nil, fmt.Errorf("no valid IP address found") } return ips, nil }