尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Dagger ServiceEndpointOpts 完全指南:掌握 TypeScript 服务端点的 port 与 scheme 配置

Dagger ServiceEndpointOpts 完全指南:掌握 TypeScript 服务端点的 port 与 scheme 配置 Dagger ServiceEndpointOpts 完全指南掌握 TypeScript 服务端点的 port 与 scheme 配置【免费下载链接】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导读ServiceEndpointOpts是 Dagger TypeScript SDKdagger.io/dagger中用于配置服务端点Service Endpoint查询参数的类型别名。在 Dagger 中Container可以被转换为可提供 TCP 连接的Service而Service.endpoint()方法则负责返回客户端可用于访问该服务的地址。ServiceEndpointOpts正是该方法的核心入参通过port指定目标端口通过scheme决定返回 URL 还是host:port地址对。读完本文你将掌握该类型的所有字段语义、默认行为、底层实现原理并能在 Go / TypeScript 模块中写出可运行的端点消费代码。ServiceEndpointOpts 是什么在 docs/versioned_docs/version-0.19/reference/typescript/api/client.gen/type-aliases/ServiceEndpointOpts.md 中ServiceEndpointOpts被定义为ServiceEndpointOptsobject它是一个对象类型用于描述调用Service.endpoint()时可选的配置项。该类型由 Dagger 的代码生成器从 GraphQL API 的serviceEndpointArgs参数自动生成其真实定义可以在 sdk/typescript/src/api/client.gen.ts#L2824-L2834 中查看export type ServiceEndpointOpts { /** * The exposed port number for the endpoint */ port?: number /** * Return a URL with the given scheme, eg. http for http:// */ scheme?: string }其中两个字段均为可选optional。这正是 Dagger 声明式引擎设计理念的体现所有输入都有合理的默认行为调用方只需在需要精确控制时显式传入参数。字段详解port?: number —— 端点暴露的端口号属性说明字段名port类型number是否必填否可选语义端点对应的暴露端口号port用于指定要返回的服务端口。如果不传该字段Dagger 会回退到第一个暴露的端口the first exposed port即服务上通过withExposedPort()设置端口列表中的第一个端口如果服务没有暴露任何端口则会返回错误no ports exposed。这一行为在 core/service.go#L390-L396 的引擎端实现中有直接体现if port 0 { if len(svc.Container.Self().Ports) 0 { return , fmt.Errorf(no ports exposed) } port svc.Container.Self().Ports[0].Port }从源码结构看当port为 0即未指定时引擎会优先读取容器自身已暴露的端口列表取第一个端口作为默认值。因此在使用endpoint()之前务必先通过Container.withExposedPort()声明端口否则会得到错误。port参数在 GraphQL 层的定义位于 core/schema/service.go#L118-L121属于endpoint节点的serviceEndpointArgstype serviceEndpointArgs struct { Port dagql.Optional[dagql.Int] Scheme string default: }注意Scheme有默认值空字符串而Port是可选的Optional。scheme?: string —— 端点 URL 的协议前缀属性说明字段名scheme类型string是否必填否可选语义返回带指定协议的 URL例如http对应http://scheme用于控制返回值的格式传入 scheme如http、https、tcp等endpoint()返回一个完整 URL格式为scheme://host:port不传 schemeendpoint()返回一个host:port地址对如127.0.0.1:8080。这一格式化的实现位于 core/service.go#L433-L438endpoint : fmt.Sprintf(%s:%d, host, port) if scheme ! { endpoint scheme :// endpoint } return endpoint, nil也就是说scheme本质上是在host:port前面拼接scheme://前缀。文档中的示例注释 eg. http for http:// 精确描述了这一行为。Service.endpoint()ServiceEndpointOpts 的消费方ServiceEndpointOpts唯一的直接消费场景就是 Service 类 的endpoint()方法。其 TypeScript 签名如下endpoint(opts?: ServiceEndpointOpts): Promisestring官方文档对该方法的语义描述为Retrieves an endpoint that clients can use to reach this container. If no port is specified, the first exposed port is used. If none exist an error is returned. If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned.翻译过来即获取一个客户端可用于访问该容器的端点未指定端口时使用第一个暴露的端口若无暴露端口则报错指定 scheme 时返回 URL否则返回host:port地址对。在 sdk/typescript/src/api/client.gen.ts#L14168-L14178 中可以看到其实现方法会将整个opts对象透传给 GraphQL 查询的endpoint字段由引擎计算后返回字符串endpoint async (opts?: ServiceEndpointOpts): Promisestring { if (this._endpoint) { return this._endpoint } const ctx this._ctx.select(endpoint, { ...opts }) const response: Awaitedstring await ctx.execute() return response }Service 类中的相关方法为了更好理解endpoint()在服务生命周期中的位置可以参考 Service 类文档 中与之配套的常用方法hostname()获取客户端可用于访问该容器的主机名Promisestringports()获取服务提供的端口列表PromisePort[]start()启动服务并等待健康检查通过PromiseServicestop(opts?)停止服务PromiseServiceup(opts?)创建隧道将调用方网络流量转发到该服务PromisevoidwithHostname(hostname)为当前会话内的客户端配置访问该容器的主机名。其中hostname()与endpoint()的关系最为密切endpoint()返回的地址中的host部分正是通过服务的主机名解析得到的。在引擎端 core/service.go#L384-L388当服务基于容器时会先调用svc.Hostname(ctx, dig)取得主机名case svc.Container.Self() ! nil: host, err svc.Hostname(ctx, dig)实战如何正确使用 ServiceEndpointOpts下面给出官方文档配套的完整可运行示例。该示例位于 docs/versioned_docs/version-0.19/extending/modules/snippets/services/use-endpoint/typescript/index.ts演示了启动 NGINX 服务 → 获取端点 → 发起 HTTP 请求的完整链路import { dag, object, func } from dagger.io/dagger object() export class MyModule { func() async get(): Promisestring { // start NGINX service let service dag.container().from(nginx).withExposedPort(80).asService() service await service.start() // wait for service to be ready const endpoint await service.endpoint({ port: 80, scheme: http }) // send HTTP request to service endpoint return await dag.http(endpoint).contents() } }步骤拆解构建服务dag.container().from(nginx).withExposedPort(80).asService()拉取nginx镜像、暴露 80 端口并将其转换为Service。注意withExposedPort(80)是必需的它决定了后续endpoint()能查到哪些端口启动服务await service.start()显式启动服务并等待健康检查通过。文档特别指出绑定到Container上的服务无需手动启动而这里因为是独立服务所以需要显式调用获取端点await service.endpoint({ port: 80, scheme: http })—— 这里显式传入了ServiceEndpointOpts的两个字段port: 80指定端口scheme: http要求返回http://开头的 URL。最终结果形如http://hostname:80消费端点dag.http(endpoint).contents()使用返回的 URL 发起 HTTP 请求并读取响应内容。对比不传 opts 的默认行为如果调用service.endpoint()不传任何选项则端口回退为第一个暴露端口即上面例子中的 80返回host:80这样的地址对而不是 URL。此时若直接丢给dag.http()使用会因为缺少协议前缀而失败。这正是scheme字段存在的意义在需要 URL 型地址如 HTTP 客户端时显式指定scheme让返回值可直接使用。其它语言的等价用法ServiceEndpointOpts不仅在 TypeScript SDK 中存在同名结构也被 Dagger 的代码生成器输出到各个 SDK 中例如sdk/go/dagger.gen.goGo SDKsdk/python/runtime/internal/dagger/dagger.gen.goPython SDKsdk/java/runtime/internal/dagger/dagger.gen.goJava SDKsdk/rust/crates/dagger-sdk/src/gen.rsRust SDKsdk/elixir/runtime/internal/dagger/dagger.gen.goElixir SDKsdk/php/runtime/internal/dagger/dagger.gen.goPHP SDK。以官方 Go 版示例 docs/versioned_docs/version-0.19/extending/modules/snippets/services/use-endpoint/go/main.go 为例用法完全对应package main import ( context dagger/my-module/internal/dagger ) type MyModule struct{} func (m *MyModule) Get(ctx context.Context) (string, error) { // Start NGINX service service : dag.Container().From(nginx).WithExposedPort(80).AsService() service, err : service.Start(ctx) if err ! nil { return , err } // Wait for service endpoint endpoint, err : service.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: http, Port: 80}) if err ! nil { return , err } // Send HTTP request to service endpoint return dag.HTTP(endpoint).Contents(ctx) }可以看到Go 中通过结构体字面量dagger.ServiceEndpointOpts{Scheme: http, Port: 80}传参字段语义与 TypeScript 完全一致。底层原理端口回退与 scheme 拼接从引擎实现core/service.go#L375-L439看endpoint()的完整逻辑可归纳为以下流程确定 host根据服务类型分支处理——容器型服务通过svc.Hostname(ctx, dig)取得主机名隧道型服务TunnelUpstream从已启动的隧道实例中取得tunnel.Host主机 socket 型服务HostSockets同样使用主机名并从第一个 socket 的端口转发中推导端口其它类型返回 unknown service type 错误。确定 port若传入port 0则直接使用否则取服务端口列表中的第一个端口列表为空则报错。拼装结果先组成host:port若scheme非空则在前面拼接scheme://。值得注意的实现细节是endpoint节点在 GraphQL 层被标记为DoNotCache见 core/schema/service.go#L113-L117原因正如注释所说——A tunnel services endpoint can change if tunnel service is restarted隧道服务重启后端点可能变化因此该查询不会被缓存每次调用都会重新计算。常见问题与注意事项未暴露端口就调用 endpoint()会得到no ports exposed错误。务必先用withExposedPort()声明端口或将port参数显式传入。不传 scheme 时返回的是地址对而非 URL若下游消费方如dag.http()、fetch()需要完整 URL必须显式传scheme。端口必须是已暴露的端口即使显式传入了port若该端口并未通过withExposedPort()暴露不同服务类型下的行为可能不同最稳妥的做法是保证port与withExposedPort声明一致。endpoint()不会被缓存由于隧道类服务重启后端点可能变化每次调用都会实时计算这保证了获取到的地址始终是最新的运行状态。总结ServiceEndpointOpts是 Dagger 服务网络能力中一个轻量但关键的配置类型port?: number控制端点端口缺省时回退到第一个暴露端口scheme?: string控制返回格式缺省返回host:port传入后返回scheme://host:port它与Container.withExposedPort()、Service.start()、Service.hostname()等 API 紧密配合是启动服务 → 获取可访问地址 → 消费服务这一经典链路中不可或缺的一环。无论是编写 Dagger 模块TypeScript / Go / Python / Java / Rust / Elixir / PHP SDK 通用还是在集成测试中动态获取被测服务地址理解ServiceEndpointOpts的字段语义与默认行为都能帮助你写出更健壮、可预期的服务消费代码。【免费下载链接】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),仅供参考
返回列表