首先需要明确一点:Dagger 本质上是一个独立的 CI/CD 引擎,而不是 Go 语言生态里那种能直接用 go get 拉下来、在代码里 import 的库。官方没有提供标准的 Go SDK,社区实现的版本既不稳定也不被推荐。所以,所谓“在 Go 项目中引入 Dagger”,正确的理解是把 Dagger 当作一个外部 CLI 工具来集成——通过工作流中的 dagger do 来调用你定义好的函数,而不是在 main.go 里写 import "dagger.io/dagger"。

为什么 Dagger 不适合直接“引入”进 Go 项目
这其实是个很常见的误解。Dagger 不是 Go 的库,也不是 go mod 能管理的依赖。你没法用 go get 安装它,更不可能在代码里 import "dagger.io/dagger"。所谓“引入”,本质上是把 Dagger 当作外部工具链,集成进你的 Go 项目工作流——它位于项目之外,而不是语言级别依赖。
本地安装 Dagger CLI 并验证是否可用
所有 Dagger 流水线都依赖 dagger 这个 CLI 来驱动,所以第一步是在开发机或 CI 环境里把它装好。Go 项目本身不会感知 Dagger,但你的构建脚本和 CI 配置需要能调用它。
- macOS:Homebrew 用户直接运行
brew install dagger/tap/dagger - Linux / macOS 手动:下载二进制文件并加到
$PATH,比如curl -L https://dl.dagger.io/dagger/install.sh | sh - 验证:运行
dagger version,输出应包含版本号;再跑dagger init,看能否生成dagger.json
需要特别注意的是:Dagger CLI 依赖 Docker 或 Podman(需要后台 daemon 运行)。如果 dagger version 报错 Cannot connect to the Docker daemon,那说明容器运行时没启动,这不是 Dagger 的问题。
用 dagger init 生成基础配置并适配 Go 构建场景
dagger init 会创建 dagger.json 和一个默认的 dagger/main.go(基于 Go SDK 模板)。不过这只是个起点,你需要手动改写函数逻辑,让它真正去 build 你的 Go 服务。
- 确认
dagger/main.go中的Build函数调用的是你项目的go build命令,而不是模板里的 demo 代码 - 用
WithExec([]string{"go", "build", "-o", "./bin/app", "."})替换默认命令,路径要和你项目结构匹配 - 如果需要静态编译(比如
CGO_ENABLED=0),要显式设置环境变量:WithEnvVariable("CGO_ENABLED", "0") - Go module 路径需与
go.mod保持一致;Dagger 默认工作目录是项目根,如果go.mod在子目录(比如src/),要用WithWorkdir("src")
示例代码片段:
func (m *Main) Build(ctx context.Context) (*File, error) {
return dag.Container().
From("golang:1.22-alpine").
WithMountedDirectory("/app", dag.WorkingDirectory()).
WithWorkdir("/app").
WithEnvVariable("CGO_ENABLED", "0").
WithExec([]string{"go", "build", "-o", "./bin/app", "."}).
File("./bin/app")
}
CI 中调用 dagger do 而不是 go run
在 GitHub Actions 或 GitLab CI 里,千万别写成 go run dagger/main.go。Dagger 流水线必须通过 dagger do 触发——这是最容易踩的坑:很多人以为写个 Go 文件就能直接跑,结果 CI 报错 command not found: dagger 或 no function named 'Build'。
- 确保 CI 步骤先安装
daggerCLI(用 setup-dagger action 或手动 curl) - 用
dagger do build调用函数(函数名默认小写,除非用//+dagger:output注释覆盖) - 函数参数需要显式传入:比如
dagger do build --target-arch amd64对应func Build(ctx context.Context, targetArch string) - 输出文件用
--output ./dist/app保存,后续步骤才能拿到
复杂之处在于:Dagger 函数返回 *File 或 *Directory,这些对象只在 Dagger 执行上下文中有效,不能直接当作本地文件路径使用。想存到 CI 工作区,必须显式调用 .Export() 或用 --output 参数。