docker

package
v0.3.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: GPL-3.0 Imports: 24 Imported by: 0

README

Docker Executor

Docker Executor 使用 Docker Go SDK 实现了在 Docker 容器中执行 Workflow 节点的功能。

功能特性

  • 在 Docker 容器中执行流水线步骤
  • 支持自定义镜像(自动拉取)
  • 支持卷挂载(bind mount)
  • 支持环境变量配置
  • 支持自定义网络模式
  • 支持私有镜像仓库
  • 支持多步骤顺序执行
  • 支持 TTY 模式(模拟真实终端,支持颜色输出和交互式程序)
  • 实时流式输出执行结果

依赖

go get github.com/docker/docker/client
go get github.com/docker/docker/api/types/container
go get github.com/docker/docker/api/types/image
go get github.com/docker/docker/api/types/mount

配置示例

全局执行器配置
Executors:
  docker:
    type: docker
    config:
      host: tcp://192.168.1.10:2375  # 可选:远程 daemon 地址(tcp://… / ssh://user@host);
                                     # 未设置时读取 DOCKER_HOST 环境变量,默认本机 unix socket
      tlsVerify: true                # 可选:对 daemon 连接启用 TLS 校验(配合 host 使用)
      certPath: /etc/docker/certs    # 可选:TLS 证书目录(含 ca.pem/cert.pem/key.pem,默认 ~/.docker)
      registry: myregistry.com      # 可选:镜像仓库地址
      network: host                  # 可选:网络模式 (bridge/host/none/自定义)
      workdir: /app                  # 可选:工作目录
      tty: true                      # 可选:启用 TTY 模式(支持颜色输出和交互式程序)
      ttyWidth: 120                  # 可选:TTY 终端宽度(默认 80)
      ttyHeight: 40                  # 可选:TTY 终端高度(默认 24)
      daemonTimeout: "15s"           # 可选:daemon 控制面请求响应超时(默认 15s,支持 "15s"/秒数);
                                     # daemon 不响应时快速失败而非让节点停在 running
      volumes:                       # 可选:卷挂载列表(远程 daemon 时为远端机器路径)
        - /var/run/docker.sock:/var/run/docker.sock
        - /host/data:/container/data
      env:                           # 可选:环境变量
        GO_VERSION: "1.21"
        NODE_ENV: production

远程 daemon:配置 host 后每个执行器实例可连接不同的 Docker daemon(如 tcp://192.168.1.10:2375 或 ssh://deploy@build-server)。client 在 Prepare 阶段 惰性创建,配置变更不会残留旧连接。注意 volumes 的宿主机侧路径是 daemon 所在机器 上的路径;TLS 建议优先用 ssh://(无需在远端暴露 2375 端口)。

节点配置
Nodes:
  Build:
    executor: docker
    image: golang:1.21-alpine
    steps:
      - name: build
        run: go build -o app .
      - name: test
        run: go test ./...

  Deploy:
    executor: docker
    image: bitnami/kubectl:latest
    steps:
      - name: deploy
        run: kubectl apply -f k8s/

API 使用

基本使用
import (
    "context"
    "log"

    "github.com/LerkoX/flowx"
    "github.com/LerkoX/flowx/executor/docker"
)

func main() {
    ctx := context.Background()

    // 创建执行器
    executor, err := docker.NewDockerExecutor()
    if err != nil {
        log.Fatal(err)
    }

    // 配置执行器
    executor.SetImage("golang:1.21-alpine")
    executor.SetWorkdir("/workspace")
    executor.SetEnv("CGO_ENABLED", "0")
    executor.SetVolume("/host/go", "/go")

    // 准备环境(创建并启动容器)
    if err := executor.Prepare(ctx); err != nil {
        log.Fatal(err)
    }
    defer executor.Destruction(ctx) // 确保清理容器

    // 创建通信通道
    resultChan := make(chan any)   // 用于接收执行结果
    commandChan := make(chan any)  // 用于发送命令

    // 启动 Transfer 处理 goroutine
    go executor.Transfer(ctx, resultChan, commandChan, nil)

    // 发送步骤执行
    steps := []flowx.Step{
        {Name: "build", Run: "go build -o app ."},
        {Name: "test", Run: "go test ./..."},
    }
    commandChan <- steps

    // 接收执行结果
    for i := 0; i < len(steps); i++ {
        result := <-resultChan
        if r, ok := result.(*docker.StepResult); ok {
            if r.Error != nil {
                log.Printf("Step %s failed: %v\n", r.StepName, r.Error)
            } else {
                log.Printf("Step %s succeeded:\n%s\n", r.StepName, r.Output)
            }
        }
    }
}
使用 Bridge 和 Adapter 模式
// 创建桥接器
bridge := docker.NewDockerBridge()

// 创建适配器并配置
adapter := docker.NewDockerAdapter()
config := map[string]any{
    "registry": "myregistry.com",
    "network": "host",
    "workdir": "/app",
    "volumes": []string{
        "/var/run/docker.sock:/var/run/docker.sock",
        "/host/data:/container/data",
    },
    "env": map[string]string{
        "GO_VERSION": "1.21",
    },
}

if err := adapter.Config(ctx, config); err != nil {
    log.Fatal(err)
}

// 通过桥接器创建执行器
executor, err := bridge.Conn(ctx, adapter)
if err != nil {
    log.Fatal(err)
}

// 设置镜像并执行
if dockerExec, ok := executor.(*docker.DockerExecutor); ok {
    dockerExec.SetImage("golang:1.21-alpine")
}

接口实现

Docker Executor 实现了以下接口:

接口 实现类型 说明
flowx.Executor DockerExecutor 执行器主接口
flowx.Adapter DockerAdapter 配置适配器接口
flowx.Bridge DockerBridge 连接桥接器接口

DockerExecutor 方法

构造函数
// 使用默认 Docker 客户端创建执行器
func NewDockerExecutor() (*DockerExecutor, error)

// 使用指定的 Docker 客户端创建执行器
func NewDockerExecutorWithClient(cli *client.Client) *DockerExecutor
配置方法
func (d *DockerExecutor) SetImage(image string)           // 设置镜像
func (d *DockerExecutor) SetWorkdir(workdir string)       // 设置工作目录
func (d *DockerExecutor) SetEnv(key, value string)        // 设置环境变量
func (d *DockerExecutor) SetVolume(hostPath, containerPath string)  // 设置卷挂载
func (d *DockerExecutor) SetNetwork(network string)       // 设置网络模式
func (d *DockerExecutor) SetRegistry(registry string)     // 设置镜像仓库
func (d *DockerExecutor) SetTTY(enabled bool)             // 设置是否启用 TTY 模式(默认 false)
func (d *DockerExecutor) SetTTYSize(width, height uint)   // 设置 TTY 终端尺寸(默认 80x24)
生命周期方法
func (d *DockerExecutor) Prepare(ctx context.Context) error      // 创建并启动容器
func (d *DockerExecutor) Transfer(ctx context.Context, resultChan chan<- any, commandChan <-chan any)  // 执行命令
func (d *DockerExecutor) Destruction(ctx context.Context) error  // 停止并删除容器
TTY 使用示例
// 创建执行器
executor, err := docker.NewDockerExecutor()
if err != nil {
    log.Fatal(err)
}

// 启用 TTY 模式(支持颜色输出和交互式程序)
executor.SetTTY(true)

// 设置终端尺寸(可选,默认 80x24)
executor.SetTTYSize(120, 40)

// 设置镜像并执行
executor.SetImage("golang:1.21-alpine")

// 准备并执行
if err := executor.Prepare(ctx); err != nil {
    log.Fatal(err)
}
defer executor.Destruction(ctx)

// 现在执行的命令会像在真实终端中一样运行
// 支持:
// - 带颜色的输出(ls --color=auto)
// - 需要终端的程序(top、htop 等)
// - 正确的终端格式和换行

StepResult 结构

type StepResult struct {
    StepName   string    // 步骤名称
    Command    string    // 执行的命令
    Output     string    // 命令输出(stdout + stderr)
    Error      error     // 执行错误(如果 exit code != 0)
    StartTime  time.Time // 开始时间
    FinishTime time.Time // 结束时间
}

注意事项

  1. Docker 环境:需要主机上安装并运行 Docker,执行器通过 Docker API 与守护进程通信

  2. 权限要求:

    • 需要访问 Docker socket 的权限(通常是 /var/run/docker.sock)
    • 或者配置 Docker HTTP API 访问
  3. 容器生命周期:

    • Prepare() 创建并启动容器
    • Transfer() 在容器中执行命令
    • Destruction() 停止并删除容器
    • 建议使用 defer executor.Destruction(ctx) 确保清理
  4. 镜像拉取:

    • 如果镜像不存在,会自动拉取
    • 支持配置私有仓库(通过 SetRegistry 或配置中的 registry)
  5. Shell 选择:

    • 默认使用 /bin/bash
    • Alpine/BusyBox 镜像自动使用 /bin/sh
  6. 错误处理:

    • 命令返回非零退出码时,StepResult.Error 会包含错误信息
    • 容器启动失败会在 Prepare() 阶段返回错误

架构说明

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   DockerBridge  │────▶│  DockerAdapter  │────▶│ DockerExecutor  │
│   (连接管理)     │     │   (配置管理)     │     │   (执行管理)     │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │  Docker Client  │
                                               │  (Go SDK)       │
                                               └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │  Docker Daemon  │
                                               │  (容器管理)      │
                                               └─────────────────┘

测试

# 运行 Docker Executor 测试
go test ./executor/docker/ -v

# 运行所有测试
go test ./... -v

注意:部分测试需要 Docker 环境,如果没有 Docker 会跳过相关测试。

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConnectionInfo added in v0.3.1

type ConnectionInfo struct {
	ServerVersion string `json:"serverVersion"` // daemon 的 Docker 版本
	APIVersion    string `json:"apiVersion"`    // 协商后的 API 版本
	OS            string `json:"os"`            // daemon 所在操作系统
	Arch          string `json:"arch"`          // daemon 架构
	Name          string `json:"name"`          // daemon 节点名
	LatencyMs     int64  `json:"latencyMs"`     // Ping 往返耗时(毫秒)
}

ConnectionInfo Docker daemon 连接测试结果 用于 studio 等调用方的「连接状态测试」功能,不创建容器,仅探测 daemon 可达性。

func TestConnectionWithConfig added in v0.3.1

func TestConnectionWithConfig(ctx context.Context, config map[string]any) (*ConnectionInfo, error)

TestConnectionWithConfig 按配置项构造一个临时 Docker 执行器并测试 daemon 连接。 config 支持的键与 DockerAdapter 一致(host/tlsVerify/certPath 等,与连接无关的 image/network/volumes 等会被忽略)。不创建容器,调用方无需 Prepare/Destruction。

type DockerAdapter

type DockerAdapter struct {
	// contains filtered or unexported fields
}

DockerAdapter Docker适配器实现

func NewDockerAdapter

func NewDockerAdapter() *DockerAdapter

NewDockerAdapter 创建新的Docker适配器

func (*DockerAdapter) Config

func (a *DockerAdapter) Config(ctx context.Context, config map[string]any) error

Config 配置适配器 支持的配置项:

  • host: Docker daemon 地址 string(如 "tcp://192.168.1.10:2375"、"ssh://user@host"; 未设置时读取环境变量 DOCKER_HOST,默认本机 unix socket)
  • tlsVerify: 是否对 daemon 连接启用 TLS 校验 bool(配合 host 使用)
  • certPath: TLS 证书目录 string(含 ca.pem/cert.pem/key.pem,默认 "~/.docker")
  • image: 容器镜像 string(未设置时默认 "alpine:latest";studio 展开器会把节点的 image 字段注入到该执行器条目的 config.image,使节点声明镜像真正生效)
  • registry: 镜像仓库地址
  • network: Docker网络模式
  • volumes: 卷挂载列表 []string{"/host:/container"}(注意:远程 daemon 时为远端机器路径)
  • workdir: 工作目录
  • env: 环境变量 map[string]string
  • tty: 是否启用 TTY 模式 bool
  • ttyWidth: TTY 终端宽度 int(默认 80)
  • ttyHeight: TTY 终端高度 int(默认 24)
  • daemonTimeout: daemon 控制面请求响应超时(如 "15s" 或秒数 int/float, 默认 15s)。host 能 TCP 连上但 daemon 不响应时,无超时的请求会永久挂起, 节点停在 running;设置后此类异常在超时后快速失败。只限制响应头等待, 不影响镜像拉取流/exec attach 长连接的响应体读取。
  • streamIdleTimeout: exec 输出流空闲探测阈值(如 "3m" 或秒数 int/float,默认 3m)。 穿隧道时容器退出不传 FIN,attach 读会永久阻塞(既无 EOF 也无错误),节点永远 停在 running;到期后主动 inspect exec:已停止则关闭连接收尾,仍运行则续等。

type DockerBridge

type DockerBridge struct{}

DockerBridge Docker桥接器实现

func NewDockerBridge

func NewDockerBridge() *DockerBridge

NewDockerBridge 创建新的Docker桥接器

func (*DockerBridge) Conn

Conn 连接到Docker环境并创建执行器 adapter: 适配器,包含Docker配置 返回: Docker执行器实例

type DockerExecutor

type DockerExecutor struct {
	// contains filtered or unexported fields
}

DockerExecutor Docker执行器实现

func NewDockerExecutor

func NewDockerExecutor() (*DockerExecutor, error)

NewDockerExecutor 创建新的Docker执行器

client 不在此处创建,而是在 Prepare 时惰性创建(ensureClient): 此时 adapter 配置(host/tlsVerify/certPath 等)已应用完毕, 才能决定连接哪个 daemon。未配置 host 时回退到环境变量(FromEnv), 与历史行为一致。

func NewDockerExecutorWithClient

func NewDockerExecutorWithClient(cli *client.Client) *DockerExecutor

NewDockerExecutorWithClient 使用指定的Docker客户端创建执行器

func (*DockerExecutor) Destruction

func (d *DockerExecutor) Destruction(ctx context.Context) error

Destruction 销毁Docker环境 停止并删除容器

func (*DockerExecutor) GetContainerID

func (d *DockerExecutor) GetContainerID() string

GetContainerID 获取容器ID

func (*DockerExecutor) GetInstanceId

func (d *DockerExecutor) GetInstanceId() string

GetInstanceId 获取实例ID(容器ID)

func (*DockerExecutor) GetRuntimeInfo

func (d *DockerExecutor) GetRuntimeInfo() map[string]any

GetRuntimeInfo 获取运行时信息

func (*DockerExecutor) GetType

func (d *DockerExecutor) GetType() string

GetType 获取executor类型

func (*DockerExecutor) Prepare

func (d *DockerExecutor) Prepare(ctx context.Context) error

Prepare 准备Docker环境 1. 检查/拉取镜像 2. 创建并启动容器

func (*DockerExecutor) TestConnection added in v0.3.1

func (d *DockerExecutor) TestConnection(ctx context.Context) (*ConnectionInfo, error)

TestConnection 测试与 Docker daemon 的连接状态。 只做 Ping + ServerVersion,不拉取镜像也不创建容器;失败时返回带原因的 error。

func (*DockerExecutor) Transfer

func (d *DockerExecutor) Transfer(ctx context.Context, resultChan chan<- any, commandChan <-chan any, inputChan <-chan []byte)

Transfer 在Docker容器中执行命令 in 接收执行数据(包括步骤信息),out 发送执行结果 inputChan 用于接收交互式输入数据,可为 nil(不需要输入时)

当 ctx 被取消时,会立即停止执行新命令,并终止当前正在容器内执行的命令

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL