如何强制Terraform重新创建aws_lightsail_instance_public_ports资源以实现单次terraform apply完成部署
你遇到的问题本质是Terraform的资源变更检测逻辑导致的:aws_lightsail_instance_public_ports的代码配置没有变化,所以Terraform默认不会主动更新它,但底层实例重建后,默认端口配置被重置(开启22、关闭443),就出现了配置不一致的情况。要实现一次terraform apply完成正确部署,我们需要让端口资源感知到实例的重建事件,自动触发自身的更新。
方法1:Terraform 1.2+ 推荐方案:replace_triggered_by
从Terraform 1.2版本开始,官方引入了replace_triggered_by生命周期参数,专门用来指定「当其他资源的某个属性变化时,强制当前资源重建」。我们可以利用实例的id属性(实例重建后id会完全变更)来触发端口资源的替换:
resource "aws_lightsail_instance" "myserver-sig" { name = "myserver-Sig" availability_zone = "eu-west-2a" blueprint_id = "ubuntu_20_04" bundle_id = "nano_2_0" key_pair_name = "LightsailDefaultKeyPair" } resource "aws_lightsail_instance_public_ports" "myserver-sig-public-ports" { instance_name = aws_lightsail_instance.myserver-sig.name port_info { protocol = "tcp" from_port = 443 to_port = 443 } port_info { protocol = "tcp" from_port = 80 to_port = 80 } # 当实例重建(id发生变化)时,强制当前端口资源重建 lifecycle { replace_triggered_by = [aws_lightsail_instance.myserver-sig.id] } }
方法2:兼容旧版本Terraform:triggers块
如果你使用的是Terraform 1.2之前的版本,可以用triggers块实现类似效果。triggers是一个键值对集合,当其中任意值发生变化时,Terraform会销毁并重新创建当前资源:
resource "aws_lightsail_instance" "myserver-sig" { name = "myserver-Sig" availability_zone = "eu-west-2a" blueprint_id = "ubuntu_20_04" bundle_id = "nano_2_0" key_pair_name = "LightsailDefaultKeyPair" } resource "aws_lightsail_instance_public_ports" "myserver-sig-public-ports" { instance_name = aws_lightsail_instance.myserver-sig.name port_info { protocol = "tcp" from_port = 443 to_port = 443 } port_info { protocol = "tcp" from_port = 80 to_port = 80 } # 绑定实例id,实例重建时id变更会触发端口资源重建 triggers = { instance_id = aws_lightsail_instance.myserver-sig.id } }
逻辑说明
两种方案的核心思路一致:当aws_lightsail_instance被重建时,它的id属性会生成全新值,这个变化会被Terraform检测到,从而触发aws_lightsail_instance_public_ports的销毁和重新创建。这样在一次terraform apply流程中,Terraform会先完成新实例的创建,紧接着在新实例上配置正确的公网端口,完全避免了中间出现端口配置错误的状态。
另外你原来配置的depends_on可以省略,因为instance_name已经引用了实例的属性,Terraform会自动推断出两者的依赖关系。
内容的提问来源于stack exchange,提问作者UEFI

