Terraform 插件协议详解:基于 gRPC 的 Provider 插件传输协议与版本兼容策略

Terraform 插件协议详解:基于 gRPC 的 Provider 插件传输协议与版本兼容策略 Terraform 插件协议详解基于 gRPC 的 Provider 插件传输协议与版本兼容策略【免费下载链接】terraformTerraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.项目地址: https://gitcode.com/GitHub_Trending/te/terraform本篇技术指南围绕 Terraform 仓库中 docs/plugin-protocol 目录的协议文档展开讲解 Terraform Core 与 Provider 插件之间的 gRPC 物理传输协议wire protocol、其主/次版本演进策略、Core/SDK/Provider 三方兼容规则以及如何基于.proto规范文件为 Terraform 构建 SDK。读完后你将理解插件进程模型、版本协商机制并能按照协议规范独立完成 stub 代码生成与协议版本升级。协议文档的适用对象与权威性边界Terraform 插件协议是 Terraform Core 用于与 provider 插件通信的物理传输协议。仓库中 docs/plugin-protocol 目录专门存放该协议的文档与协议定义文件包括README.md协议总体说明、进程模型与版本策略即本文主体来源object-wire-format.mdDynamicValue消息在 MessagePack / JSON 两种格式下的序列化规则tfplugin5.proto 与 tfplugin6.proto两个主要大版本协议的 protobuf 权威定义releasing-new-version.md新协议版本的发布流程说明。文档首先明确了读者定位大多数 provider 并不直接面向本协议开发而是使用实现了该协议的 SDK如 terraform-plugin-sdk、terraform-plugin-framework面向 SDK 的 API 编写 provider。本文档的真正受众是开发 Terraform SDK 的人而非开发插件的人。关于定义的权威性文档强调了一个关键约束只有随 Terraform 发布 tag 一起发布的.proto文件才是正式的协议版本。如果阅读的是main分支或其他开发分支上的文件其中可能包含尚未定稿、在最终发布前仍会变更的协议定义。这一点在当前仓库中可以直接验证tfplugin5.proto 与 tfplugin6.proto 的文件头注释都写明Terraform Plugin RPC protocol version 5.10 / 6.10式的具体次版本号且 tfplugin5.proto 的注释明确要求插件开发者应取最近发布 tag 中的 proto 文件而不是main分支的版本。自 Terraform v0.12.0 起插件协议构建在 gRPC 之上v0.12 之前的版本不遵循本文所述的版本策略。RPC 插件模型经回环接口的客户端-服务器进程对协议文档描述的插件运行模型可以概括为Terraform 插件是普通的可执行程序启动后在**回环接口loopback interface**上暴露 gRPC 服务Terraform Core 负责发现并启动插件进程等待插件在stdout上打印握手信息handshake然后按照握手信息中指示的端口号以 gRPC 客户端身份连接因此社区约定把 Terraform Core 称为插件的client把插件程序称为插件的server。这两个进程都在本地运行server 进程在进程树上表现为 client 的子进程Terraform Core 控制这些 server 进程的生命周期不再需要时会将其终止。文档同时坦承启动与握手协议目前尚无正式文档官方计划在后续于该目录或外部文档中补充说明。这意味着若你正在实现 SDK握手部分通常需要参考现有 SDK如 Go 生态中插件服务层的实现的行为而非依赖协议文档本身。从仓库源码结构看协议在 Core 一侧的落地位置与文档描述一致internal/tfplugin5与internal/tfplugin6两个包分别包含 protoc 生成的tfplugin5.pb.go、tfplugin5_grpc.pb.go以及 v6 对应文件而协议实现层位于 internal/plugin 与 internal/plugin6。版本策略tfpluginX.proto 命名与主/次版本语义协议的每个版本在docs/plugin-protocol/目录下以一个 Protocol Buffers 服务定义文件作为权威定义文件命名模式为tfpluginX.proto其中 X 是主版本号。当前仓库中的实际文件头为协议主版本定义文件当前次版本文件头注释5tfplugin5.proto5.106tfplugin6.proto6.11该版本策略自协议版本 5.0Terraform v0.12引入目标是既允许渐进式增强并保持兼容又允许阶段性地引入较大破坏性变更同时让新旧插件在一段时间内可以混用。次版本minor可选的、可被忽略的新功能次版本号在每次引入可选的新功能时递增前提是旧版本实现可以安全地忽略这些变更。文档给出的例子是若在某个 response 消息中新增一个字段只要 Terraform Core 在该字段未填充时能提供某种默认行为这就可以是一次次版本发布。次版本差异不直接体现在线协议上而是依赖功能检测feature-detection机制它主要是一个面向人类的沟通工具用来描述某软件支持哪些特性。主版本major破坏性变更与协商选择任何导致兼容性破坏的显著变更都会使主版本号递增。但 Terraform Core 与 SDK 都可以选择同时支持多个主版本插件握手过程中包含一个协商步骤客户端与服务器共同选择一个双方都支持的主版本。主版本号被编码进 protobuf 包名主版本 5 使用包名tfplugin5主版本 6 使用包名tfplugin6可以对比 tfplugin5.proto 的package tfplugin5;与 tfplugin6.proto 中的package tfplugin6;。这种命名方式允许一个插件 server 通过导出多个 gRPC 服务来同时实现多个主版本——Terraform 仓库自身正是这样做的internal/tfplugin5与internal/tfplugin6两个包并行存在且各自的.proto文件是以符号链接方式指向docs/plugin-protocol/下的权威定义文件如internal/tfplugin5/tfplugin5.proto - ../../docs/plugin-protocol/tfplugin5.proto保证生成物与文档定义始终同源。Core、SDK 与 Provider 的版本兼容规则Terraform Core 一侧特定版本的 Terraform Core 具有一个要求的最低次版本minimum minor version一个支持的最高主版本maximum major version可能还支持可选地利用更新的次版本新特性可用时使用不可用时回退到旧行为。Provider 一侧每个 provider 插件发布版本兼容一组协议版本表示为主/次版本对列表。例如4.0, 5.2表示该 provider 支持主版本 4 的基线特性支持主版本 5 且包含次版本 1 和 2 的增强。因此它与一个仅支持协议 5.0 的 Terraform Core 版本是兼容的——主版本 5 被支持而可选的 5.1、5.2 增强会被忽略。不兼容时的报错行为当 Terraform Core 与插件没有任何共同支持的主版本时terraform init在安装插件阶段会返回错误。文档区分了两种场景从 Terraform Registry 安装时Registry API 能让 Core 感知每个 provider 发布的协议兼容性因此可以给出可操作的升级/降级建议Provider aws v1.0.0 is not compatible with Terraform v0.12.0. Provider version v2.0.0 is the earliest compatible version. Select it with the following version constraint: version ~ 2.0.0Provider aws v3.0.0 is not compatible with Terraform v0.12.0. Provider version v2.34.0 is the latest compatible version. Select it with the following constraint: version ~ 2.34.0 Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases.手动安装到本地插件目录时Core 无法建议具体的升级/降级版本错误信息更为通用The installed version of provider example is not compatible with Terraform v0.12.0. This provider was loaded from: /usr/local/bin/terraform-provider-example_v0.1.0值得注意的是这些报错示例均以 Terraform v0.12.0 为背景属于文档撰写时的典型用例实际版本数字会随 Core 与 provider 的具体发布而不同但列出最早/最晚兼容版本并给出版本约束建议的机制保持一致。SDK 增删主版本支持对 provider 语义化版本的影响插件支持的主版本集合由其使用的 SDK 决定。SDK 会随时间新增对新主版本的支持、并逐步淘汰旧主版本的支持这些能力与约束会传递给所有使用该 SDK 的 provider进而影响 provider 的 semver 版本编号SDK 升级新增对某个新 provider 协议的支持通常视为新功能对应 provider 的**次版本minor**发布SDK 升级移除对某个旧 provider 协议的支持永远是破坏性变更要求 provider 进行**主版本major**发布。因此 SDK 开发者必须在发布说明中清晰标注主版本支持的增减。Terraform Core 在生成可操作的错误提示时还做了一个假设某个协议主版本的兼容范围在一个 provider 发布序列中是连续的、无空洞的区间——这正是上面最早/最晚兼容版本提示能够成立的前提。在 SDK 中使用 protobuf 规范文件如果你要为 Terraform 插件构建 SDK早期步骤之一是把本目录中的一个或多个.proto文件按你要支持的协议版本拷贝进你自己的仓库然后用protoc带 gRPC 扩展为目标语言生成 RPC stub 与类型。文档给出的 Python 目标示例protoc --python_out. --grpc_python_out. tfplugin5.1.proto需要注意当前仓库中的实际文件名是 tfplugin5.proto / tfplugin6.proto单一文件承载该主版本的当前次版本次版本号记录在文件头注释中文档示例中的tfplugin5.1.proto是早期文件组织方式的写法。各目标语言的protoc用法可参照 gRPC 官方 Quick Start 指南。几条关键规则已发布即不可变某个版本的 protobuf 规范一旦被纳入至少一个 Terraform 发布之后即不可变更。任何变更都必须通过新建.proto文件、确立新协议版本来完成。包名包含主版本号建议把协议主版本写入生成的模块/包名如主版本 5 就叫tfplugin5以便将来能并发支持多个版本。仓库自身的 Go 包名即遵循此约定tfplugin5.proto的go_package为github.com/hashicorp/terraform/internal/tfplugin5。升级次版本把新.proto文件拷贝到旧版本所在位置、删除旧版本、重新运行 protoc 即可——因为次版本向后兼容可以原地更新 stub不必并排保留。支持新的主版本创建新的包/模块把对应.proto文件拷入生成一套独立的 stub使 SDK 原则上可以同时支持两个主版本。文档建议在主版本升级期间同时支持前一个与当前主版本一段时间让用户不必同时升级 Terraform Core 和所有 provider移除对旧版本支持后即可删除旧 stub。关于旧注释的说明部分.proto文件中残留minor 版本会原地更新此文件之类的注释这反映的是早期已不再沿用的版本管理策略。当前流程是每个新次版本都视为新定义、所有已打 tag 的定义不可变那些过时注释被保留只是为了维持不可变承诺的形式一致性其内容现已不准确。当前协议的实际形态Provider gRPC 服务结合权威定义文件可以看到两个主版本的具体服务面。tfplugin5.proto 中声明service Provider其 RPC 大致分为几组元信息GetMetadata预取服务器能力与类型清单避免实例化全部 schema、GetSchema、PrepareProviderConfig、ValidateResourceTypeConfig、ValidateDataSourceConfig、UpgradeResourceState、GetResourceIdentitySchemas、UpgradeResourceIdentity一次性初始化Configure受管资源生命周期ReadResource、PlanResourceChange、ApplyResourceChange、ImportResourceState、MoveResourceState、ReadDataSource、GenerateResourceConfig临时资源Ephemeral Resource生命周期ValidateEphemeralResourceConfig、OpenEphemeralResource、RenewEphemeralResource、CloseEphemeralResource资源列表ListResource服务端流式返回事件、ValidateListResourceConfigProvider 函数GetFunctions、CallFunction动作ActionsPlanAction、InvokeAction流式、ValidateActionConfig优雅停机Stop。主版本 6 的 service Provider 在此基础上有一批重命名与新增如GetProviderSchema替代GetSchema、ValidateProviderConfig/ValidateResourceConfig/ValidateDataResourceConfig、ConfigureProvider、StopProvider并新增了完整的**状态存储state store**RPC 族——ValidateStateStoreConfig、ConfigureStateStore、ReadStateBytes流式读取状态字节、WriteStateBytes流式写入、LockState、UnlockState、GetStates、DeleteState。这类跨版本新增一组 RPC正是前述版本策略的体现新能力作为主版本演进的一部分由握手机制完成新旧实现之间的兼容协商。所有请求/响应中承载 Terraform 语言类型值的字段统一使用DynamicValue消息tfplugin5.proto 中定义为bytes msgpack 1; bytes json 2;其 MessagePack 与 JSON 的完整映射规则、未知值unknown value的扩展类型编码等详见同目录的 object-wire-format.md——它是实现协议 server 端解码/编码逻辑时的必读文档。在 Terraform Core 中更新插件协议贡献者流程本节面向 Terraform 的贡献者而非 SDK 开发者。Terraform Core 的新特性经常需要更新插件协议这些变更体现为协议的新次版本。规则是Terraform 的每个新次版本发布只应引入一个新次版本的插件协议两者次版本号不要求一致但应保持一一对应关系。具体操作步骤来自 README.md 末尾章节编辑docs/plugin-protocol/下协议 5 和协议 6 的.proto文件。如果是某次 Terraform 发布后的第一批较大变更可以考虑在文件头提升次版本协议版本号提交变更运行make protobuf。该目标会利用internal/tfplugin*目录中的符号链接访问最新次版本的.proto文件见 Makefile该目标实际执行go run ./tools/protobuf-compile .。你应该能在internal/tfplugin5/tfplugin5.pb.go与internal/tfplugin6/tfplugin6.pb.go中看到 diff运行make generate。你应该能在internal/plugin/mock_proto/mock.go与internal/plugin6/mock_proto/mock.go中看到 diffmock 文件随接口变化重新生成。这一流程与文档前文的原则形成闭环docs/plugin-protocol/是唯一权威定义源internal/tfplugin*中的 Go 生成物通过符号链接 生成步骤与之保持同步而 mock 实现则保障基于新接口的测试代码同步更新。小结Terraform 插件协议以 gRPC 为传输基础以tfpluginX.proto文件为权威定义通过主版本编码进包名 握手协商实现多主版本共存通过次版本可选增强 功能检测实现渐进式演进。对 SDK 开发者而言掌握.proto的拷贝-生成流程、包命名约定与不可变原则就能基于本协议构建任意语言的工具链对 provider 开发者而言理解协议版本兼容规则则能正确解读terraform init的兼容性报错并合理安排版本约束对 Core 贡献者而言docs/plugin-protocol→make protobuf→make generate的链路就是协议演进的完整工作流。【免费下载链接】terraformTerraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.项目地址: https://gitcode.com/GitHub_Trending/te/terraform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考