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的地址创建的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/8397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

银河麒麟桌面版开机后网络无法自动链接 麒麟系统开机没有连接ens33

1.每次虚拟机开机启动麒麟操作系统,都要输入账号,密码。 进入点击这个ens33 内网才连接 2. 如何开机就脸上呢? 2.1. 进入 cd /etc/sysconfig/network-scripts 2.2 修改参数 onbootyes 改为yes 2.3 重启即可 a. 直接重启机器查看是否正常&…

工程伦理课堂记录

文章目录 0. 导论0.1 工程伦理教育的意义0.2 工程伦理教育要实现的目标 1. 工程与伦理1.1 工程伦理学科的产生1.2 工程和技术1.3 工程概念的理解演进1.4 工程的过程1.5 工程的特点1.6 工程活动的七个维度总结 2. 伦理2.1 道德伦理的概念2.2 道德伦理的关系2.3 伦理规范2.4 伦理…

【吃透Java手写】2-Spring(下)-AOP-事务及传播原理

【吃透Java手写】Spring(下)AOP-事务及传播原理 6 AOP模拟实现6.1 AOP工作流程6.2 定义dao接口与实现类6.3 初始化后逻辑6.4 原生Spring的方法6.4.1 实现类6.4.2 定义通知类,定义切入点表达式、配置切面6.4.3 在配置类中进行Spring注解包扫描…

Blender动画与云渲染:创造高质量作品的未来路径

Blender作为开源的3D图形软件,在多个领域广受欢迎。但随着项目复杂度提升,传统渲染方式受限。云渲染技术的兴起突破了这些限制,为创作者提供了更自由、高效的创作环境。 一、Blender动画项目的挑战 传统上,Blender动画渲染需要依…

五、 哪些情况下需要申报数据出境安全评估?

最新发布的《跨境流动规定》适度收窄了数据出境安全评估范围。具体而言,根据《跨境流动规定》和《评估申报指南(第二版)》的规定,当数据处理者向境外提供数据不属于《跨境流动规定》下的豁免情形时,且具有下列情形之一…

Linux文件系统的目录结构

Linux文件系统的目录结构 Linux文件系统的目录结构 Linux文件系统的目录结构是一种树状结构,最顶层是根目录 /。在这个目录下可以有很多子目录和文件。下面是一些常见的目录及其含义: /bin:二进制文件,基本命令,如ls…

代码审计-php篇之某CRM系统多处sql注入

🌟 ❤️ 作者:yueji0j1anke 首发于公号:剑客古月的安全屋 字数:3516 阅读时间: 35min 声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果…

信创基础软件之信创云介绍

信创基础软件之信创云介绍 信创云概述 信创云,是指在信息技术应用创新的背景下,以国产化的CPU、操作系统为底座的自主研发的云平台,统筹利用计算、存储、网络、安全、应用支撑、信息资源等软硬件资源,发挥云计算虚拟化、高可靠性…

实战 | 实时手部关键点检测跟踪(附完整源码+代码详解)

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

苹果平板HOME键成历史,全面屏时代到来?2024平板电脑市场趋势分析

近期苹果公司在“放飞吧”发布会上推出了新款iPad Pro和iPad Air平板电脑,并下架了最后一款带有实体Home按键的iPad 9。这一变化标志着Home键在苹果iPad产品线中成为了历史,引起了不少网友的怀念和感慨。 与此同时,今年3月线上平板电脑市场迎…

邦芒忠告:人到中年在职场上千万不能做这3种事情

人在职场上的闯荡基本上只有两个时期,一个是青年时期,一个是中年时期。 ​青年时期,我们敢打敢拼,敢于一次一次尝试失败。虽然青年时期我们的阅历并不丰富,但是学习能力很强,还充斥着一股职场新人的工作热情…

【驱动】I2C读写时序

1、I2C总线 I2C使用两条线在主控制器和从机之间通信,SCL(串行时钟线)和SDA(串行数据线),这两条线需接5~10欧上拉电阻,总线空闲空闲时,SCL和SDA处于高电平,I2C总线标准模式速度可以达到100K/S,快速模式可以达到400K/S。 2、状态 I2C总线有四种状态:空闲、启动、忙碌、…

OpenFeign @PathVariable需注明参数名称

在定义 OpenFeign 的远程接口时,如果是路径拼接作为参数的远程接口,需要在PathVariable需注明参数名称,不然代码启动时会报错。 正例FeignClient(value ServiceConstants.SYSTEM, fallbackFactory RemoteFileFallbackFactory.class) publi…

Unity与C#的关系

第一,我们首先需要知道Unity与C#的关系是什么? 第二,我们要明白为什么Unity会使用C#,而不是C? 第三,我们需要知道Unity是怎么使用C#的? 第一点: 先说结论:C#是Unity用…

LabVIEW波浪发电平台浮筒取能效率数据采集系统

LabVIEW波浪发电平台浮筒取能效率数据采集系统 随着化石能源的逐渐减少以及能源价格的上升,寻找可替代的、可再生的、清洁的能源成为了世界各国的共识。波浪能作为一种重要的海洋能源,因其巨大的潜力和清洁性,近年来受到了广泛关注。开发了一…

Blender修改器

修改器 Modifier,对模型进行修改,相当于一个函数。 修改器图标是界面右下角的扳手样式 每个修改器的顶部都有如下样式,从左到右分别为:展开/折叠,修改器类型,修改器名称,编辑模式按钮&#xff…

TCP三次握手四次挥手 UDP

TCP是面向链接的协议,而UDP是无连接的协议 TCP的三次握手 三次传输过程是纯粹的不涉及数据,三次握手的几个数据包中不包含数据内容。它的应用层,数据部分是空的,只是TCP实现会话建立,点到点的连接 TCP的四次挥手 第四…

Python生成文学编程风格文档库之pycco使用详解

概要 Pycco是一个Python库,用于生成文学编程风格的文档。它受到了Docco(一个快速生成源代码文档的工具)的启发,并通过解析源代码旁边的注释来创建一个美观的文档页面,使代码的解释与代码本身并排显示。 安装 安装Pycco非常简单,可以通过Python的包管理器pip进行安装: …

docker-compose-itd和d

docker run -itd和-d的区别 前言: ​ 今天在通过docker-compose启动一基于ubuntu的镜像容器时,发现启动后,容器会一直停止。但是通过docker run -itd是可以正常运行的。基于这个区别,找了一位大神(师傅)问…