package docker import ( "context" "fmt" "io" "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" "github.com/docker/go-connections/nat" "gitee.ltd/lxh/wechat-robot/internal/config" ) // ContainerInfo 容器信息 type ContainerInfo struct { ID string `json:"id"` Name string `json:"name"` Image string `json:"image"` Status string `json:"status"` Created int64 `json:"created"` Labels map[string]string `json:"labels"` } // CreateContainer 创建容器 func CreateContainer(ctx context.Context, cfg *config.DockerConfig, name string, env []string, labels map[string]string) (string, error) { cli := GetClient() // 端口映射 portBindings := nat.PortMap{} exposedPorts := nat.PortSet{} // 创建挂载点 var mounts []mount.Mount if cfg.VolumePath != "" { mounts = append(mounts, mount.Mount{ Type: mount.TypeBind, Source: fmt.Sprintf("%s/%s", cfg.VolumePath, name), Target: "/data", }) } // 设置容器配置 containerConfig := &container.Config{ Image: cfg.ImageName, Env: env, ExposedPorts: exposedPorts, Labels: labels, } // 设置主机配置 hostConfig := &container.HostConfig{ PortBindings: portBindings, Mounts: mounts, RestartPolicy: container.RestartPolicy{ Name: "unless-stopped", }, } // 设置网络配置 networkingConfig := &network.NetworkingConfig{} if cfg.Network != "" { endpointsConfig := make(map[string]*network.EndpointSettings) endpointsConfig[cfg.Network] = &network.EndpointSettings{} networkingConfig.EndpointsConfig = endpointsConfig } // 创建容器 resp, err := cli.ContainerCreate( ctx, containerConfig, hostConfig, networkingConfig, nil, // 平台 name, ) if err != nil { return "", err } return resp.ID, nil } // StartContainer 启动容器 func StartContainer(ctx context.Context, containerID string) error { cli := GetClient() return cli.ContainerStart(ctx, containerID, types.ContainerStartOptions{}) } // StopContainer 停止容器 func StopContainer(ctx context.Context, containerID string, timeout *time.Duration) error { cli := GetClient() t := int(timeout.Seconds()) return cli.ContainerStop(ctx, containerID, container.StopOptions{Timeout: &t}) } // RemoveContainer 删除容器 func RemoveContainer(ctx context.Context, containerID string, force bool) error { cli := GetClient() return cli.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{ Force: force, }) } // ListContainers 列出容器 func ListContainers(ctx context.Context, filterArgs map[string][]string) ([]ContainerInfo, error) { cli := GetClient() // 构建过滤器 filterSet := filters.NewArgs() for k, vals := range filterArgs { for _, v := range vals { filterSet.Add(k, v) } } containers, err := cli.ContainerList(ctx, types.ContainerListOptions{ All: true, // 包括未运行的容器 Filters: filterSet, }) if err != nil { return nil, err } var containerInfos []ContainerInfo for _, c := range containers { containerInfos = append(containerInfos, ContainerInfo{ ID: c.ID, Name: c.Names[0][1:], // 去掉前面的/ Image: c.Image, Status: c.Status, Created: c.Created, Labels: c.Labels, }) } return containerInfos, nil } // GetContainerLogs 获取容器日志 func GetContainerLogs(ctx context.Context, containerID string, tail string) (string, error) { cli := GetClient() options := types.ContainerLogsOptions{ ShowStdout: true, ShowStderr: true, Tail: tail, } logs, err := cli.ContainerLogs(ctx, containerID, options) if err != nil { return "", err } defer logs.Close() // 读取日志内容 logContent, err := io.ReadAll(logs) if err != nil { return "", err } return string(logContent), nil } // GetContainerStatus 获取容器状态 func GetContainerStatus(ctx context.Context, containerID string) (string, error) { cli := GetClient() inspect, err := cli.ContainerInspect(ctx, containerID) if err != nil { return "", err } if inspect.State.Running { return "running", nil } else if inspect.State.Paused { return "paused", nil } else if inspect.State.Restarting { return "restarting", nil } else { return "stopped", nil } } // WaitForContainer 等待容器达到指定状态 func WaitForContainer(ctx context.Context, containerID string) (<-chan container.WaitResponse, <-chan error) { cli := GetClient() return cli.ContainerWait(ctx, containerID, container.WaitConditionNotRunning) }