尧图精选

Dagger Container.withoutDirectory 详解:类型别名 ContainerWithoutDirectoryOpts 与目录移除的完整指南

🕒 发布时间:2026/9/17 23:29:04 📁 来源:尧图网络
Dagger Container.withoutDirectory 详解类型别名 ContainerWithoutDirectoryOpts 与目录移除的完整指南【免费下载链接】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版本 0.21TypeScript SDK 中的Container.withoutDirectory()方法与类型别名ContainerWithoutDirectoryOpts展开说明如何在容器文件系统中安全移除指定目录、通过expand参数实现环境变量展开并结合源码core/schema/container.go 等剖析其底层实现原理。读完本文你将掌握withoutDirectory的完整签名、参数语义、环境变量展开规则、错误边界以及它在构建流程中的典型应用。概述Type AliasContainerWithoutDirectoryOpts在 Dagger 的 TypeScript SDK 中Container对象代表一个可运行的容器镜像及文件系统快照。withoutDirectory是容器 API 中用于从容器文件系统移除一个目录的操作而ContainerWithoutDirectoryOpts则是它第二个参数的类型别名。根据参考文档 docs/versioned_docs/version-0.21/reference/typescript/api/client.gen/type-aliases/ContainerWithoutDirectoryOpts.md该类型别名定义如下ContainerWithoutDirectoryOptsobject它是一个普通对象类型目前只包含一个可选属性属性类型说明expand?boolean是否在path的值中根据容器当前定义的环境变量替换${VAR}或$VAR例如/$VAR/foo。与 SDK 生成代码的对应关系该类型别名由 Dagger 的代码生成管线自动生成。在 sdk/typescript/src/api/client.gen.ts 中withoutDirectory方法签名如下/** * Return a new container snapshot, with a directory removed from its filesystem * param path Location of the directory to remove (e.g., .github/). * param opts.expand Replace ${VAR} or $VAR in the value of path according to the current environment variables defined in the container (e.g. /$VAR/foo). */ withoutDirectory ( path: string, opts?: ContainerWithoutDirectoryOpts, ): Container { const ctx this._ctx.select(withoutDirectory, { path, ...opts }) return new Container(ctx) }关键信息path要移除的目录在容器文件系统中的位置例如.github/opts可选类型为ContainerWithoutDirectoryOpts返回值一个新的Container快照——Dagger 采用不可变对象模型withoutDirectory不会修改原容器而是返回移除目录后的新容器。方法签名与类型定义参数语义withoutDirectory(path: string, opts?: ContainerWithoutDirectoryOpts): Containerpath: string必填——容器文件系统中待删除目录的路径如/app/node_modules或.github/。路径语义与 GraphQL schema 中的String!参数对应见 core/schema/testdata/base_schema.graphqls 中withoutDirectory(path: String!, expand: Boolean! false)的定义。opts.expand?: boolean可选默认false——控制路径字符串中$VAR/${VAR}的展开行为。默认关闭开启后按容器内环境变量展开。默认值expand参数在服务端带有默认值false。从 core/schema/container.go 中对应的参数结构体可以确认type containerWithoutDirectoryArgs struct { Path string Expand bool default:false }因此即使客户端不传opts也不会因为缺少参数而报错。expand参数详解环境变量展开机制expand是ContainerWithoutDirectoryOpts中唯一、也是最有技术含量的参数。开启后Dagger 会在执行移除操作之前将路径中的$VAR或${VAR}替换为容器当前环境中定义的环境变量值。展开规则与来源该行为由 core/schema/container.go 的expandEnvVar函数实现func expandEnvVar(ctx context.Context, parent *core.Container, input string, expand bool) (string, error) { if !expand { return input, nil } cfg, err : parent.ImageConfig(ctx) if err ! nil { return , err } secretEnvs : []string{} for _, secret : range parent.Secrets { secretEnvs append(secretEnvs, secret.EnvName) } volatileEnvs : []string{} core.WalkEnv(parent.VolatileEnv, func(name, _, _ string) { volatileEnvs append(volatileEnvs, name) }) var secretEnvFoundError error expanded : os.Expand(input, func(k string) string { // set error if its a secret env variable if slices.Contains(secretEnvs, k) { secretEnvFoundError fmt.Errorf(expand cannot be used with secret env variable %q, k) return } if slices.Contains(volatileEnvs, k) { secretEnvFoundError fmt.Errorf(expand cannot be used with volatile env variable %q, k) return } v, _ : core.LookupEnv(cfg.Env, k) return v }) if secretEnvFoundError ! nil { return , secretEnvFoundError } return expanded, nil }从源码可以得出以下事实expand为false时直接返回原始路径不做任何替换展开基于容器自身的镜像配置环境变量parent.ImageConfig(ctx)中的Env而不是宿主机或进程的环境变量——这正是according to the current environment variables defined in the container的含义使用 Go 标准库os.Expand进行替换天然支持$VAR与${VAR}两种语法例如/$VAR/foo或/${VAR}/foo未定义的环境变量会被替换为空字符串core.LookupEnv未命中时返回空值因此/$UNDEFINED/foo会变成/foo。安全边界secret 与 volatile 环境变量expand的展开范围被刻意限制不能用于 Secret 环境变量和 Volatile 环境变量。源码在替换回调中显式检查若路径引用了 Secret 环境变量通过withSecretVariable等 API 注入的变量名返回错误expand cannot be used with secret env variable VAR若路径引用了 Volatile 环境变量易失/运行时变量返回错误expand cannot be used with volatile env variable VAR。这意味着即使容器中有名为$TOKEN的 Secret也不能通过expand把它展开进路径字符串从而避免敏感信息被写入查询路径或日志。这是一条重要的安全边界实践中不应试图绕过。调用链withoutDirectory的完整实现见 core/schema/container.gofunc (s *containerSchema) withoutDirectory(ctx context.Context, parent dagql.ObjectResult[*core.Container], args containerWithoutDirectoryArgs) (inst dagql.ObjectResult[*core.Container], err error) { srv, err : core.CurrentDagqlServer(ctx) if err ! nil { return inst, fmt.Errorf(failed to get server: %w, err) } path, err : expandEnvVar(ctx, parent.Self(), args.Path, args.Expand) if err ! nil { return inst, err } ctr, _, err : cloneContainerForSchemaChild(ctx, parent) if err ! nil { return inst, err } ctr.Lazy core.ContainerWithoutPathLazy{ LazyState: core.NewLazyState(), Parent: parent, Path: path, } return dagql.NewObjectResultForCurrentCall(ctx, srv, ctr) }实现要点先展开、后克隆expandEnvVar的结果作为实际要删除的路径不可变克隆通过cloneContainerForSchemaChild复制父容器包括文件系统、配置、挂载、Secrets、Sockets、Ports、Services 等见 core/schema/container.go 的克隆逻辑原容器不受影响惰性执行新容器挂载ContainerWithoutPathLazy定义于 core/container.gowithoutDirectory是惰性操作真正删除目录的动作推迟到该容器被实际求值如export、publish、stdout等下游操作时才执行。在 GraphQL Schema 中的定义withoutDirectory并非 TypeScript 独有它是 Dagger 核心 API 的通用能力在 GraphQL schema 中以 field 形式暴露。从 core/schema/testdata/base_schema.graphqls 可以看到其 schema 形态containerWithoutDirectoryArgs对应的字段定义其中expand参数标注为Boolean! false与 Go 结构体中的default:false一致。除了Container目录与 Workspace 类型也提供同名方法sdk/typescript/src/api/client.gen.ts 中Directory.withoutDirectory(path: string): Directory第 7315 行附近同一文件中Workspace.withoutDirectory(path: string): Workspace第 16941 行附近。Container版本的独特之处在于支持expand选项Directory与Workspace版本目前不接收 opts 参数。与同类方法的对比方法作用是否支持expandContainer.withoutDirectory(path, { expand })从容器文件系统移除一个目录是Container.withoutFile(path, { expand })从容器文件系统移除一个文件是Container.withoutFiles(paths, { expand })批量移除多个文件内部串行调用withoutFile是Directory.withoutDirectory(path)从目录移除一个子目录否从 core/schema/container.go 的实现可以看出withoutFile、withoutFiles与withoutDirectory共用同一套expandEnvVar与ContainerWithoutPathLazy机制行为一致withoutFiles则在服务端循环调用withoutFile逐个删除。实战示例示例一基本用法不展开环境变量import { connect } from dagger.io/dagger connect(async (client) { // 基于 alpine 镜像创建容器 const ctr client .container() .from(alpine:3.20) .withExec([sh, -c, mkdir -p /app/src /app/node_modules /app/dist echo hi /app/index.js]) // 移除 /app/node_modules返回新容器快照 const slim ctr.withoutDirectory(/app/node_modules) // 验证列出 /app 下的内容 const listing await slim .withExec([ls, -1, /app]) .stdout() console.log(listing) })输出中应不再包含node_modules。注意原ctr仍然存在且未受影响——withoutDirectory的不可变语义。示例二使用expand展开环境变量import { connect } from dagger.io/dagger connect(async (client) { const ctr client .container() .from(alpine:3.20) .withEnvVariable(APP_DIR, /opt/myapp) .withExec([sh, -c, mkdir -p $APP_DIR/cache]) // expand 开启/$APP_DIR/cache 会被展开为 /opt/myapp/cache 再删除 const cleaned ctr.withoutDirectory(/$APP_DIR/cache, { expand: true }) await cleaned.export(./cleaned.tar) })expand的典型价值在于当路径依赖容器内运行时才确定的环境变量时无需在客户端手工拼接字符串避免宿主机与容器环境不一致导致的路径错误。示例三结合withoutFile/withoutFiles清理构建产物import { connect } from dagger.io/dagger connect(async (client) { const ctr client .container() .from(node:20-alpine) .withDirectory(/app, client.host().directory(.)) const cleaned ctr .withoutDirectory(/app/.git) // 移除版本控制目录 .withoutDirectory(/app/node_modules) // 移除依赖目录 .withoutFiles([/app/package-lock.json, /app/.npmrc]) // 移除敏感/冗余文件 await cleaned.export(./deploy.tar) })错误场景对 Secret 环境变量启用 expandimport { connect } from dagger.io/dagger connect(async (client) { const secret client.setSecret(MY_TOKEN, super-secret-value) const ctr client .container() .from(alpine:3.20) .withSecretVariable(MY_TOKEN, secret) // 运行时会报错expand cannot be used with secret env variable MY_TOKEN const bad ctr.withoutDirectory(/$MY_TOKEN/foo, { expand: true }) await bad.stdout() })该调用会在执行阶段以错误终止这是 Dagger 防止 Secret 泄露进入路径/日志的刻意设计。常见问题与注意事项为什么withoutDirectory看起来没生效因为它是惰性操作只有在下游求值export、stdout、publish、entries等时才会真正执行。若仅构建了新容器而不消费它删除不会发生。expand默认关闭因此路径中的$VAR会被当作字面量处理若路径本身包含美元符号但不想展开保持默认false即可。展开的是容器环境不是宿主机环境。/etc/hostname、宿主机$HOME等不会被带入容器想用宿主机变量需先在客户端自行展开或通过withEnvVariable注入。未定义变量展开为空字符串可能产生意外的路径拼接如/$FOO/x→/x生产代码建议对关键路径先做校验。不要对 Secret / Volatile 环境变量使用expand运行时会返回明确的错误信息这是特性而非缺陷。扩展阅读参考文档原始定义docs/versioned_docs/version-0.21/reference/typescript/api/client.gen/type-aliases/ContainerWithoutDirectoryOpts.md客户端生成代码sdk/typescript/src/api/client.gen.tswithoutDirectory方法及ContainerWithoutDirectoryOpts类型服务端实现与参数解析core/schema/container.gocontainerWithoutDirectoryArgs、withoutDirectory、expandEnvVar惰性状态定义core/container.goContainerWithoutPathLazyGraphQL schema 定义core/schema/testdata/base_schema.graphqlswithoutDirectory(path: String!, expand: Boolean! false)核心 API 其余容器操作可参阅 core/schema/README.md【免费下载链接】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),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →