Terraform模块重构

2024-05-06 07:52
文章标签 模块 重构 terraform

本文主要是介绍Terraform模块重构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本节介绍的通过moved块进行模块重构的功能是从Terraform v1.1开始被引入的,如果要在之前的版本进行这样的操作,必须通过terraform state mv命令来完成。

对一些旨在被人复用的老模块来说,最初的模块结构和资源名称可能会逐渐变得不再合适。例如,可能发现将以前的一个子模块分割成两个单独的模块会更合理,这需要将现有资源的一个子集移动到新的模块中。Terraform将以前的状态与新代码进行比较,资源与每个模块或资源的唯一地址相关联。因此,默认情况下,移动或重命名对象会被Terraform理解为销毁旧地址的对象并在新地址创建新的对象。

当在代码中添加moved块以记录移动或重命名对象过去的地址时,Terraform会将旧地址的现有对象视为现在属于新地址。

moved块语法

moved块只包含fromto参数,没有名称:

moved {from = aws_instance.ato   = aws_instance.b
}

如上例子演示了模块先前版本中的aws_instance.a如今以aws_instance.b的名字存在。

在为aws_instance.b创建新的变更计划之前,Terraform会首先检查当前状态中是否存在地址为aws_instance.a的记录。如果存在该记录,Terraform会将之重命名为aws_instance.b然后继续创建变更计划。最终生成的变更计划中该对象就好像一开始就是以aws_instance.b的名字被创建的,防止它在执行变更时被删除。

fromto的地址使用一种特殊的地址语法,该语法允许选定模块、资源以及子模块中的资源。

不同重构场景下的语法

重命名一个资源

考虑模块代码中这样一个资源:

resource "aws_instance" "a" {count = 2
}

第一次应用该代码时Terraform会创建资源aws_instance.a[0]以及aws_instance.a[1]
如果随后修改了该资源的名称,并且把旧名字记录在一个moved块里:

resource "aws_instance" "b" {count = 2
}moved {from = aws_instance.ato   = aws_instance.b
}

当下一次应用使用了该模块的代码时,Terraform会把所有地址为aws_instance.a的对象看作是一开始就以aws_instance.b的名字创建的:aws_instance.a[0]会被看作是aws_instance.b[0]aws_instance.a[1]会被看作是aws_instance.b[1]
新创建的模块实例中,因为从来就不存在aws_instance.a,于是会忽略moved块而像通常那样直接创建aws_instance.b[0]以及aws_instance.b[1]

为资源添加count或for_each声明

一开始代码中有这样一个单实例资源:

resource "aws_instance" "a" {# 资源属性配置
}

应用该代码会使得Terraform创建了一个地址为aws_instance.a的资源对象。

随后想要在该资源上添加for_each来创建多个实例,为了保持先前关联到aws_instance.a的资源对象不受影响,必须添加一个moved块来指定新代码中原先的对象实例所关联的键是什么:

locals {instances = tomap({big = {instance_type = "m3.large"}small = {instance_type = "t2.medium"}})
}resource "aws_instance" "a" {for_each = local.instancesinstance_type = each.value.instance_type# (other resource-type-specific configuration)
}moved {from = aws_instance.ato   = aws_instance.a["small"]
}

上面的代码会防止Terraform在变更计划中销毁已经存在的aws_instance.a对象,并且将其看作是以aws_instance.a["small"]的地址创建的。

moved块的两个地址中的至少一个包含实例键时,如上例中的 [“small”],Terraform将这两个地址理解为引用资源的特定实例而不是整个资源,这意味着可以使用moved在键之间切换以及在countfor_each之间切换时添加和删除键。

下面的例子演示了几种其他类似的记录了资源实例键变更的合法moved块:

moved {from = aws_instance.b["small"]to   = aws_instance.b["tiny"]
}moved {from = aws_instance.c[0]to   = aws_instance.c["small"]
}
moved {from = aws_instance.c[1]to   = aws_instance.c["tiny"]
}moved {from = aws_instance.d[2]to   = aws_instance.d
}

注意:当在原先没有声明count的资源上添加count时,Terraform会自动将原先的对象移动到第0个位置,除非通过一个moved块显式声明该资源。然而,建议使用moved块显式声明资源的移动,使得读者在未来阅读模块的代码时能够更清楚地了解到这些变更。

重命名对模块的调用

可以用类似重命名资源的方式来重命名对模块的调用。
假设开始用以下代码调用一个模块:

module "a" {source = "../modules/example"
}

当应用该代码时,Terraform会在模块内声明的资源路径前面加上一个模块路径前缀module.a。例如模块内的aws_instance.example的完整地址为module.a.aws_instance.example

如果随后打算修改模块名称,可以直接修改module块的标签,并且在一个moved块内部记录该变更:

module "b" {source = "../modules/example"
}moved {from = module.ato   = module.b
}

当下一次应用包含该模块调用的代码时,Terraform会将所有路径前缀为module.a的对象看作从一开始就是以module.b为前缀创建的,即:module.a.aws_instance.example会被看作是module.b.aws_instance.example

该例子中的moved块中的两个地址都代表对模块的调用,而Terraform识别出将原模块地址中所有的资源移动到新的模块地址中。如果该模块声明时使用了count或是for_each,那么该移动也将被应用于所有的实例上,不需要逐个指定。

为模块调用添加count或for_each声明

考虑一下单实例的模块:

module "a" {source = "../modules/example"q
}

应用该段代码会导致Terraform创建的资源地址都拥有module.a的前缀。
随后如果可能需要再通过添加count来创建多个资源实例。为了保留先前的aws_instance.a实例不受影响,可以添加一个moved块来设置在新代码中该实例的对应的键。

module "a" {source = "../modules/example"count  = 3
}moved {from = module.ato   = module.a[2]
}

上面的代码引导Terraform将所有module.a中的资源看作是从一开始就是以module.a[2]的前缀被创建的。结果就是Terrafor 生成的变更计划中只会创建module.a[0]以及module.a[1]

moved块的两个地址中的至少一个包含实例键时,例如上面例子中的[2]那样,Terraform会理解将这两个地址理解为对模块的特定实例的调用而非对模块所有实例的调用。这意味着可以使用moved块在不同键之间切换来添加或是删除键,该机制可用于countfor_each,或删除模块上的这种声明。

将一个模块分割成多个模块

随着模块提供的功能越来越多,最终模块可能变得过大而不得不将之拆分成两个独立的模块。
如下示例:

resource "aws_instance" "a" {
}resource "aws_instance" "b" {
}resource "aws_instance" "c" {
}

可以将该模块分割为三个部分:

  • aws_instance.a现在归属于模块”x”。
  • aws_instance.b也属于模块”x”。
  • aws_instance.c现在归属于模块”y”。

要在不替换绑定到旧资源地址的现有对象的情况下实现此重构,需要:

  1. 编写模块”x”,将属于它的两个资源拷贝过去。
  2. 编写模块”y”,将属于它的一个资源拷贝过去。
  3. 编辑原有模块代码,删除这些资源,只包含有关迁移现有资源的非常简单的配置代码。

新的模块”x”和”y”应该只包含resource块:

# 模块"x"
resource "aws_instance" "a" {
}resource "aws_instance" "b" {
}
# 模块"y"
resource "aws_instance" "c" {
}

而原有模块则被修改成只包含有向下兼容逻辑的垫片,调用两个新模块,并使用moved块定义哪些资源被移动到新模块中去了:

module "x" {source = "../modules/x"
}module "y" {source = "../modules/y"
}moved {from = aws_instance.ato   = module.x.aws_instance.a
}moved {from = aws_instance.bto   = module.x.aws_instance.b
}moved {from = aws_instance.cto   = module.y.aws_instance.c
}

当一个原模块的调用者升级模块版本到这个“垫片”版本时,Terraform会注意到这些moved块,并将那些关联到老地址的资源对象看作是从一开始就是由新模块创建的那样。

该模块的新用户可以选择使用这个垫片模块,或是独立调用两个新模块。需要通知老模块的现有用户老模块已被废弃,他们将来的开发中需要独立使用这两个新模块。
多模块重构的场景是不多见的,因为它违反了父模块将其子模块视为黑盒的典型规则,不知道在其中声明了哪些资源。这种妥协的前提是假设所有这三个模块都由同一个人维护并分布在一个模块包中。

为避免独立模块之间的耦合,Terraform只允许声明在同一个目录下的模块间的移动。换句话讲,Terraform不允许将资源移动到一个source地址不是本地路径的模块中去。

Terraform使用定义moved块的模块实例的地址来解析moved块中的相对地址。例如,如果上面的原模块已经是名为module.original的子模块,则原模块中对module.x.aws_instance.a的引用在根模块中将被解析为module.original.module.x.aws_instance.a。一个模块只能针对它自身或是它的子模块中的资源声明moved块。

如果需要引用带有countfor_each元参数的模块中的资源,则必须指定要使用的特定实例键以匹配资源配置的新位置:

moved {from = aws_instance.exampleto   = module.new[2].aws_instance.example
}

删除moved块

随着时间的推移,一些老模块可能会积累大量moved块。
删除moved块通常是一种破坏性变更,因为删除后所有使用旧地址引用的对象都将被删除而不是被移动,强烈建议保留历史上所有的moved块来保存用户从任意版本升级到当前版本的升级路径信息。

如果决定要删除moved块,需要谨慎行事。对于组织内部的私有模块来说删除moved块可能是安全的,因为我们可以确认所有用户都已经使用新版本模块代码运行过terraform apply了。

如果需要多次重命名或是移动一个对象,建议使用串联的moved块来记录完整的变更信息,新的块引用已有的块:

moved {from = aws_instance.ato   = aws_instance.b
}moved {from = aws_instance.bto   = aws_instance.c
}

像这样记录下移动的序列可以使aws_instance.a以及aws_instance.b两种地址的资源都得到成功更新,Terraform会将他们视作从一开始就是以aws_instance.c的地址创建的。

这篇关于Terraform模块重构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/963814

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

python内置模块datetime.time类详细介绍

​​​​​​​Python的datetime模块是一个强大的日期和时间处理库,它提供了多个类来处理日期和时间。主要包括几个功能类datetime.date、datetime.time、datetime.datetime、datetime.timedelta,datetime.timezone等。 ----------动动小手,非常感谢各位的点赞收藏和关注。----------- 使用datet

C8T6超绝模块--EXTI

C8T6超绝模块–EXTI 大纲 控制流程结构体分析EXTI实现按键 具体案例 控制流程 这里是流程框图,具体可以去看我STM32专栏的EXTI的具体分析 结构体分析 typedef struct {uint32_t EXTI_Line; // 中断/事件线EXTIMode_TypeDef EXTI_Mode; // EXTI 模式EXTITrigger_TypeDef EXTI_

1、创建多模块的maven springboot项目

现在的java的项目都是多模块的,这次也跟个风。 目标:实现下述结构 项目AcedBoot, 子模块:         aced-api 对外提供接口,         aced-web 给前端提供接口,         aced-service 服务层,         aced-dao 数据底层,包含数据库mapper和实体类entity,         aced-commo

Vue2电商项目(二) Home模块的开发;(还需要补充js节流和防抖的回顾链接)

文章目录 一、Home模块拆分1. 三级联动组件TypeNav2. 其余组件 二、发送请求的准备工作1. axios的二次封装2. 统一管理接口API----跨域3. nprogress进度条 三、 vuex模块开发四、TypeNav三级联动组件开发1. 动态展示三级联动数据2. 三级联动 动态背景(1)、方式一:CSS样式(2)、方式二:JS 3. 控制二三级数据隐藏与显示--绑定styl

PrestaShop免费模块/插件/扩展/工具下载

PrestaShop免费模块/插件/扩展/工具下载 PrestaShop免费模块 适用于您的电子商务网站的PrestaShop模块 现有超过3,000个PrestaShop模块可帮助您自定义在线商店,增加流量,提高转化率并建立客户忠诚度。 使您的电子商务网站成功! 下载(超过142+之多的PrestaShop官网认证的免费模块) 标签PrestaShop免费, PrestaShop免费工

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现