Dagger TypeScript SDK 之 DirectoryDockerBuildOpts:从目录构建 Docker 镜像的完整参数指南
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
导读
本文围绕 Dagger TypeScript SDK 中Directory.dockerBuild()方法的可选参数类型DirectoryDockerBuildOpts(定义于 DirectoryDockerBuildOpts.md)展开,讲解如何基于一个Directory(目录)对象、通过 Dockerfile 兼容方式构建出Container(容器)。读完本文,你将掌握dockerBuild的全部 7 个可选参数的语义、默认值与底层实现原理,能够用buildArgs、target、platform、secrets、ssh、noInit和dockerfile组合出实际可运行的构建流水线,并了解 Dagger 引擎在源码层面对这些参数的处理细节。
DirectoryDockerBuildOpts是 Dagger TypeScript 自动生成 API(api/client.gen)中的一个Type Alias(类型别名),类型为object,全部字段均为可选(optional),用于向dockerBuild查询传递配置。它在运行时会被序列化为 GraphQL 调用参数,最终由 Dagger 引擎的 core/schema/directory.go 中的dockerBuild解析器消费。
一、类型定义与参数总览
在 sdk/typescript/src/api/client.gen.ts 中,该类型被生成为:
export type DirectoryDockerBuildOpts = { /** * Path to the Dockerfile to use (e.g., "frontend.Dockerfile"). */ dockerfile?: string /** * The platform to build. */ platform?: Platform /** * Build arguments to use in the build. */ buildArgs?: BuildArg[] /** * Target build stage to build. */ target?: string /** * Secrets to pass to the build. * * They will be mounted at /run/secrets/[secret-name]. */ secrets?: Secret[] /** * If set, skip the automatic init process injected into containers created by RUN statements. * * This should only be used if the user requires that their exec processes be the pid 1 process in the container. Otherwise it may result in unexpected behavior. */ noInit?: boolean /** * A socket to use for SSH authentication during the build * * (e.g., for Dockerfile RUN --mount=type=ssh instructions). * * Typically obtained via host.unixSocket() pointing to the SSH_AUTH_SOCK. */ ssh?: Socket }调用方式为directory.dockerBuild(opts?: DirectoryDockerBuildOpts): Container,对应实现见 client.gen.ts,SDK 会把整个 opts 对象展开后作为dockerBuild的 GraphQL 参数提交:
dockerBuild = (opts?: DirectoryDockerBuildOpts): Container => { const ctx = this._ctx.select("dockerBuild", { ...opts }) return new Container(ctx) }| 参数 | 类型 | 必填 | 默认行为 | 作用 |
|---|---|---|---|---|
dockerfile | string | 否 | "Dockerfile" | 指定要使用的 Dockerfile 路径(如"frontend.Dockerfile") |
platform | Platform | 否 | 引擎默认平台 | 指定构建目标平台 |
buildArgs | BuildArg[] | 否 | 空数组 | 传入构建参数(对应ARG) |
target | string | 否 | 空字符串 | 指定要构建的目标构建阶段(对应--target) |
secrets | Secret[] | 否 | 空数组 | 构建期 Secret,挂载到/run/secrets/[secret-name] |
noInit | boolean | 否 | false | 是否跳过 RUN 语句自动注入的 init 进程 |
ssh | Socket | 否 | 无 | 构建期 SSH 认证 socket(对应RUN --mount=type=ssh) |
这些默认值并非凭空而来——在引擎侧的 dirDockerBuildArgs 结构体中有明确的default标记与之对应:
type dirDockerBuildArgs struct { Platform dagql.Optional[core.Platform] Dockerfile string `default:"Dockerfile"` Target string `default:""` BuildArgs []dagql.InputObject[core.BuildArg] `default:"[]"` Secrets []core.SecretID `default:"[]"` NoInit bool `default:"false"` SSH dagql.Optional[core.SocketID] }二、dockerfile:选择自定义 Dockerfile 路径
签名:dockerfile?: string
指定相对于构建上下文目录(即调用dockerBuild的那个Directory)的 Dockerfile 路径。默认值为"Dockerfile"。原文档给出的典型场景是构建上下文根目录下同时存在多个 Dockerfile 时,用该参数挑选其中一个,例如"frontend.Dockerfile"。
底层实现:dockerignore 的解析
有趣的是,dockerfile参数不仅决定了使用哪个 Dockerfile,还参与了.dockerignore的选择逻辑。引擎侧的applyDockerIgnore(见 core/schema/directory.go)遵循 Docker 官方的上下文规则(filename-and-location):
- 优先读取
<dockerfile>.dockerignore(例如传入"custom.Dockerfile"时读取custom.Dockerfile.dockerignore); - 若该文件不存在或为空,则回退读取默认的
.dockerignore; - 若仍无排除规则,直接使用原目录作为构建上下文;否则对目录执行
filter(exclude)操作,得到剔除无关文件后的精简构建上下文。
这一机制意味着:使用自定义 Dockerfile 时,你既可以配套写一份custom.Dockerfile.dockerignore精确控制该次构建的上下文,也可以复用全局.dockerignore。
实战示例:构建上下文与 Dockerfile 分离
当 Dockerfile 不在当前工作目录时,可先构造一个包含 Dockerfile 的上下文目录再构建。仓库中的官方示例 dockerfile-context/typescript/index.ts 展示了这种做法:
import { dag, Directory, File, object, func } from "@dagger.io/dagger" @object() class MyModule { @func() async build(src: Directory, dockerfile: File): Promise<string> { // 把 Dockerfile 加入构建上下文 const workspace = await dag .container() .withDirectory("/src", src) .withWorkdir("/src") .withFile("/src/custom.Dockerfile", dockerfile) .directory("/src") // 构建并发布到镜像仓库 const ref = await workspace .dockerBuild({ dockerfile: "custom.Dockerfile" }) .publish("ttl.sh/hello-dagger") return ref } }三、buildArgs:向构建传入 ARG 参数
签名:buildArgs?: BuildArg[]
对应 Docker 的--build-arg,用于向 Dockerfile 中的ARG注入构建期变量。元素类型BuildArg同样是对象类型,定义于 client.gen.ts:
export type BuildArg = { /** The build argument name. */ name: string /** The build argument value. */ value: string }使用示例:
const ctr = await src.dockerBuild({ buildArgs: [ { name: "NODE_VERSION", value: "20" }, { name: "ENV", value: "production" }, ], })引擎侧,这些参数会被collectInputsSlice(args.BuildArgs)收集后传给ctr.Build(...)(见 core/schema/directory.go),最终进入 BuildKit 的构建参数解析。注意BuildArg的name与value均为必填字符串,没有默认值,传入时二者缺一不可。
四、target:选择多阶段构建的目标阶段
签名:target?: string
对应 Docker 的--target,用于多阶段构建(multi-stage build)中只构建到某个指定阶段为止。默认值为空字符串,表示构建 Dockerfile 的最终阶段。
// 仅构建到名为 "builder" 的阶段 const ctr = await src.dockerBuild({ target: "builder" })在引擎侧,Target被原样透传给ctr.Build(core/schema/directory.go)。典型用途包括:只想拿到编译产物阶段(如golang:builder阶段)用于导出二进制,而跳过最终运行时镜像的构建,从而显著减少构建与缓存开销。
五、platform:指定构建目标平台
签名:platform?: Platform
指定构建目标平台(如linux/amd64、linux/arm64),对应 Docker 的--platform。Platform类型定义于 Platform.md。
默认值:动态注入引擎默认平台
如果不传该参数,Dagger 会在查询执行期动态注入当前引擎的默认平台。这是通过NodeFuncWithDynamicInputs与dockerBuildDynamicInputs实现的(见 core/schema/directory.go):
func (s *directorySchema) dockerBuildDynamicInputs( ctx context.Context, _ dagql.ObjectResult[*core.Directory], args dirDockerBuildArgs, req *dagql.CallRequest, ) error { if args.Platform.Valid { return nil } platform, err := currentEngineDefaultPlatform(ctx) if err != nil { return err } return req.SetArgInput(ctx, "platform", platform, false) }即:只有在platform未显式提供时,Dagger 才会调用currentEngineDefaultPlatform取回引擎默认平台并写入调用参数;一旦你显式传入platform,该逻辑直接跳过。而在解析器dockerBuild中(core/schema/directory.go),传入的平台会覆盖查询默认平台:
platform := query.Platform() if args.Platform.Valid { platform = args.Platform.Value }新容器即按该平台创建(core.NewContainer(platform))。这使 Dagger 天然支持在任意宿主机上交叉构建多平台镜像。
六、secrets:构建期 Secret 与 /run/secrets 挂载
签名:secrets?: Secret[]
向构建传入一组Secret对象。它们会被挂载到容器内的/run/secrets/[secret-name],供 Dockerfile 中以RUN --mount=type=secret,id=<name>方式使用。
实战示例:把 Secret 安全传给 Dockerfile
官方示例 secret-dockerfile/typescript/index.ts 展示了完整链路:
import { dag, object, func, Secret } from "@dagger.io/dagger" @object() class MyModule { @func() async build(source: Directory, secret: Secret): Promise<Container> { // 保证 Dagger Secret 的 name 与 Dockerfile 中 secret mount 的 id 一致 const buildSecret = dag.setSecret("gh-secret", await secret.plaintext()) return source.dockerBuild({ secrets: [buildSecret] }) } }配套 Dockerfile 中可这样消费:
RUN --mount=type=secret,id=gh-secret \ export GH_TOKEN=$(cat /run/secrets/gh-secret) && ...实现细节:按 ID 加载 Secret
引擎侧,secrets参数的类型是[]core.SecretID,在解析器中被批量加载(core/schema/directory.go):
secrets, err := dagql.LoadIDResults(ctx, srv, args.Secrets)也就是说,SDK 层的Secret对象会被解析为对应的 Secret ID,再由引擎统一Load得到真实的 Secret 内容后注入 BuildKit 构建流程。Secret 名称与挂载 id 的对应关系是约定式的——正如示例注释所强调的,dag.setSecret(name, ...)中的name必须与 Dockerfile 中--mount=type=secret,id=<name>的id保持一致,才能正确读到值。
七、ssh:构建期 SSH 认证 socket
签名:ssh?: Socket
提供一个Socket用于构建期间的 SSH 认证,典型场景是 Dockerfile 中的RUN --mount=type=ssh指令(例如从私有 Git 仓库拉取依赖)。原文档特别说明:该 socket 通常通过host.unixSocket()指向宿主机的SSH_AUTH_SOCK环境变量获得,从而把宿主机上已解锁的 SSH agent 会话带入构建过程,无需在镜像内复制私钥。
const sshAgent = await dag .host() .unixSocket("/run/host-services/ssh-auth.sock") // 或直接指向 SSH_AUTH_SOCK const ctr = await src.dockerBuild({ ssh: sshAgent, })配合 Dockerfile:
RUN --mount=type=ssh git clone git@github.com:my-org/private-repo.git实现细节:socket 的显式加载与校验
引擎侧对ssh的处理值得注意(core/schema/directory.go):它不会静默忽略无效 socket,而是先Load,再显式校验加载结果是否为 nil,失败即返回错误:
var sshSocket dagql.ObjectResult[*core.Socket] if args.SSH.Valid { sshSocket, err = args.SSH.Value.Load(ctx, srv) if err != nil { return nil, fmt.Errorf("failed to load SSH socket: %w", err) } if sshSocket.Self() == nil { return nil, fmt.Errorf("failed to load SSH socket: nil socket") } }如果传入的 socket 未正确绑定到真实的 SSH agent,构建会在这一环节直接报错,便于快速定位问题,而不是到 RUN 阶段才失败。
八、noInit:控制自动注入的 init 进程
签名:noInit?: boolean
Dagger 引擎默认会在 DockerfileRUN语句创建的容器中自动注入一个 init 进程,用于信号转发与子进程回收,避免出现僵尸进程等容器化常见问题。设置noInit: true可以跳过该注入。
原文档给出了明确的使用警告:仅在确实需要让执行进程成为容器内pid 1进程时才应开启,否则可能导致意外行为(例如信号无法正确传递到主进程、子进程残留)。
// 仅在确有必要时开启 const ctr = await src.dockerBuild({ noInit: true })从 dirDockerBuildArgs 可见其默认值为false,即默认始终注入 init 进程。因此绝大多数构建场景都不需要设置该参数,只有对进程管理有特殊要求的容器(如某些系统级或自定义 runtime 的镜像)才需要考虑。
九、完整示例:组合多个参数的一次真实构建
结合以上所有参数,一个覆盖多阶段、交叉平台、构建参数与 Secret 的完整 TypeScript 模块如下(综合自 dockerfile/typescript/index.ts 及本文各参数的用法):
import { dag, Directory, Secret, object, func } from "@dagger.io/dagger" @object() class MyModule { /** * 基于已有 Dockerfile 构建并发布多平台镜像 */ @func() async build( src: Directory, npmToken: Secret, ): Promise<string> { const ctr = src.dockerBuild({ dockerfile: "frontend.Dockerfile", // 自定义 Dockerfile target: "production", // 多阶段构建目标阶段 platform: "linux/amd64", // 目标平台 buildArgs: [ { name: "NODE_VERSION", value: "20" }, ], secrets: [dag.setSecret("npm-token", await npmToken.plaintext())], // noInit 保持默认 false,交给引擎自动注入 init 进程 }) return await ctr.publish("ttl.sh/my-app") } }十、引擎侧整体执行链路
DirectoryDockerBuildOpts中的每一个参数,最终都汇聚到引擎侧同名的解析器。完整的执行链路(基于 core/schema/directory.go)如下:
- GraphQL 路由:
dockerBuild以dagql.NodeFuncWithDynamicInputs注册到 Directory 类型上(directory.go),并标记为Dockerfile 兼容入口——其 Doc 明确指出“仅为 Dockerfile 兼容而保留,原生Container类型功能完备、支持全部 Dockerfile 特性”; - 平台解析:未显式传
platform时,由dockerBuildDynamicInputs注入引擎默认平台; - 上下文裁剪:
applyDockerIgnore依据<dockerfile>.dockerignore→.dockerignore的优先级过滤构建上下文; - 输入加载:
secrets批量LoadIDResults、ssh显式加载并校验非空; - 委托构建:
ctr.Build(ctx, parent, buildctxDirID, dockerfile, buildArgs, target, secrets, noInit, sshSocket)最终把全部参数转交给 BuildKit 完成镜像构建。
通过这条链路可以看到:DirectoryDockerBuildOpts并非一个简单的“传参对象”,而是 Dagger 将 Docker 构建语义完整映射到图查询执行引擎的桥接层——它保证了dockerBuild既能兼容存量 Dockerfile 工作流,又能无缝接入 Dagger 的缓存、平台与 Secret 体系。
相关文档与源码索引
- 类型别名定义:DirectoryDockerBuildOpts.md
- 所属 API 模块:api/client.gen README
- 宿主方法
Directory.dockerBuild():classes/Directory.md - 关联类型:BuildArg.md、Platform.md、Secret 类、Socket 类
- TypeScript 生成代码:sdk/typescript/src/api/client.gen.ts
- 引擎实现:core/schema/directory.go
- 官方示例:dockerfile 构建、自定义 Dockerfile 上下文、Dockerfile 使用 Secret
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考