!94 实现devstar可以在对应配置的k8s上添加和删除runner

* 修复runners.go中关于ctx的编译报错
* Merge branch 'main' of gitee.com:devstar/devstar into feature/runner
* 实现devstar可以在对应配置的k8s上添加和删除runner
* 实现了修改runner的标签的功能
* 单机部署环境下实现Web界面上启动和删除runner
* 启动时能够自动启动act_runner
This commit is contained in:
vecmatex
2025-08-10 03:29:09 +00:00
repo.diff.committed_by 孟宁
repo.diff.parent 68512a67c8
repo.diff.commit b9ff967366
repo.diff.stats_desc%!(EXTRA int=17, int=807, int=0)

repo.diff.view_file

@@ -0,0 +1,117 @@
package docker
import (
"context"
"io"
"os"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
// CreateDockerClient 创建Docker客户端
func CreateDockerClient(ctx context.Context) (*client.Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
return cli, nil
}
// GetDockerSocketPath 获取Docker Socket路径
func GetDockerSocketPath() (string, error) {
// 检查常见的Docker socket路径
socketPaths := []string{
"/var/run/docker.sock",
"/run/podman/podman.sock",
"$HOME/.colima/docker.sock",
"$XDG_RUNTIME_DIR/docker.sock",
"$XDG_RUNTIME_DIR/podman/podman.sock",
`\\.\pipe\docker_engine`,
"$HOME/.docker/run/docker.sock",
}
for _, path := range socketPaths {
if _, err := os.Stat(path); err == nil {
return path, nil
}
}
// 如果找不到,返回默认路径
return "/var/run/docker.sock", nil
}
// PullImage 拉取Docker镜像
func PullImage(cli *client.Client, dockerHost, imageName string) error {
ctx := context.Background()
reader, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
if err != nil {
return err
}
defer reader.Close()
// 读取并丢弃输出,确保拉取完成
_, err = io.Copy(io.Discard, reader)
return err
}
// CreateAndStartContainer 创建并启动容器
func CreateAndStartContainer(cli *client.Client, imageName string, cmd []string, env []string, binds []string, ports map[string]string, containerName string) error {
ctx := context.Background()
// 配置容器
config := &container.Config{
Image: imageName,
Env: env,
}
if cmd != nil {
config.Cmd = cmd
}
hostConfig := &container.HostConfig{
Binds: binds,
}
// 如果有端口映射配置
if ports != nil && len(ports) > 0 {
// 这里可以根据需要添加端口映射逻辑
// hostConfig.PortBindings = portBindings
}
// 创建容器
resp, err := cli.ContainerCreate(ctx, config, hostConfig, nil, nil, containerName)
if err != nil {
return err
}
// 启动容器
return cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
}
// DeleteContainer 停止并删除指定名称的容器
func DeleteContainer(cli *client.Client, containerName string) error {
ctx := context.Background()
// 首先尝试停止容器
timeout := 10
err := cli.ContainerStop(ctx, containerName, container.StopOptions{
Timeout: &timeout,
})
if err != nil {
// 如果容器已经停止或不存在,继续执行删除操作
// 这里不返回错误,因为我们的目标是删除容器
}
// 删除容器
err = cli.ContainerRemove(ctx, containerName, types.ContainerRemoveOptions{
Force: true, // 强制删除,即使容器正在运行
})
if err != nil {
return err
}
return nil
}

14
modules/setting/k8s.go Normal file
repo.diff.view_file

@@ -0,0 +1,14 @@
package setting
var K8sConfig = struct {
Enable bool
Url string
Token string
}{}
func loadK8sSettingsFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("k8s")
K8sConfig.Enable = sec.Key("ENABLE").MustBool(false)
K8sConfig.Url = sec.Key("URL").MustString("")
K8sConfig.Token = sec.Key("TOKEN").MustString("")
}

repo.diff.view_file

@@ -0,0 +1,14 @@
package setting
var Runner = struct {
AutoStart bool
Count int
Image string
}{}
func loadRunnerSettingsFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("runners")
Runner.AutoStart = sec.Key("AUTO_START").MustBool(true)
Runner.Count = sec.Key("RUNNER_COUNT").MustInt(1)
Runner.Image = sec.Key("RUNNER_IMAGE").MustString("devstar.cn/devstar/act_runner:latest")
}

repo.diff.view_file

@@ -217,6 +217,8 @@ func LoadSettings() {
loadProjectFrom(CfgProvider)
loadMimeTypeMapFrom(CfgProvider)
loadFederationFrom(CfgProvider)
loadRunnerSettingsFrom(CfgProvider)
loadK8sSettingsFrom(CfgProvider)
loadWechatSettingsFrom(CfgProvider)
}
@@ -225,6 +227,8 @@ func LoadSettingsForInstall() {
loadDBSetting(CfgProvider)
loadServiceFrom(CfgProvider)
loadMailerFrom(CfgProvider)
loadRunnerSettingsFrom(CfgProvider)
loadK8sSettingsFrom(CfgProvider)
loadWechatSettingsFrom(CfgProvider)
}