我有一个Terraform模块,可以在同事需要时在AWS上部署实例。对于我部署的每个人:
- ec2实例
- 弹性IP
- 私人安全组
为了集中一切,我对模块进行了如下组织:
.
├── README.md
├── coworker1
│ ├── main.tf
│ └── variables.tf
├── keys
├── coworker2
│ ├── main.tf
│ └── variables.tf
├── templates
│ ├── cloud-init.tpl
│ ├── pubkey_rsa.pub
│ └── strat.json
├── terraform.tf
├── terraform.tfstate
└── terraform.tfstate.backup
我在根模块中使用teraform.tf文件,并使用模块块进行引用子模块。
module "corworker1" {
source = "./coworker1"
}
我从根模块运行terraform apply
,并且正确创建了它的资源。然而,当我运行另一个terraform apply
时,它说由于更改,它将需要重新创建实例并修改弹性ip。即使我什么都没改变。
# module.coworker1.aws_instance.ec2_instance must be replaced
-/+ resource "aws_instance" "ec2_instance" {
~ arn = "arn:aws:ec2:eu-central-1:XXXXX:instance/i-0f498ac75ad66199e" -> (known after apply)
~ associate_public_ip_address = true -> (known after apply)
~ cpu_core_count = 1 -> (known after apply)
~ cpu_threads_per_core = 1 -> (known after apply)
- disable_api_termination = false -> null
- ebs_optimized = false -> null
- hibernation = false -> null
+ host_id = (known after apply)
~ id = "i-0f498ac75ad66199e" -> (known after apply)
~ instance_initiated_shutdown_behavior = "stop" -> (known after apply)
~ instance_state = "running" -> (known after apply)
~ ipv6_address_count = 0 -> (known after apply)
~ ipv6_addresses = [] -> (known after apply)
+ key_name = (known after apply)
- monitoring = false -> null
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
~ primary_network_interface_id = "eni-06debade3df83944b" -> (known after apply)
~ private_dns = "ip-172-31-12-126.eu-central-1.compute.internal" -> (known after apply)
~ private_ip = "172.31.12.126" -> (known after apply)
~ public_dns = "ec2-3-67-119-191.eu-central-1.compute.amazonaws.com" -> (known after apply)
~ public_ip = "3.67.119.191" -> (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [
- "ec2 coworker1.example.com",
] -> (known after apply)
~ subnet_id = "subnet-3e48ca72" -> (known after apply)
tags = {
"HiddenName" = "coworker1"
"Name" = "coworker1.example.com"
"Operator" = "coworker1@example.com"
}
~ tenancy = "default" -> (known after apply)
# (9 unchanged attributes hidden)
~ capacity_reservation_specification {
~ capacity_reservation_preference = "open" -> (known after apply)
+ capacity_reservation_target {
+ capacity_reservation_id = (known after apply)
}
}
- credit_specification {
- cpu_credits = "standard" -> null
}
+ ebs_block_device { # forces replacement
+ delete_on_termination = true
+ device_name = "/dev/sda1"
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ snapshot_id = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = 200
+ volume_type = (known after apply)
}
- ebs_block_device { # forces replacement
- delete_on_termination = true -> null
- device_name = "/dev/sda1" -> null
- encrypted = false -> null
- iops = 600 -> null
- snapshot_id = "snap-0d8c6e92a59dec0c9" -> null
- tags = {} -> null
- throughput = 0 -> null
- volume_id = "vol-007f3d2d27b510740" -> null
- volume_size = 200 -> null
- volume_type = "gp2" -> null
}
~ enclave_options {
~ enabled = false -> (known after apply)
}
+ ephemeral_block_device {
+ device_name = (known after apply)
+ no_device = (known after apply)
+ virtual_name = (known after apply)
}
~ metadata_options {
~ http_endpoint = "enabled" -> (known after apply)
~ http_put_response_hop_limit = 1 -> (known after apply)
~ http_tokens = "optional" -> (known after apply)
}
+ network_interface {
+ delete_on_termination = (known after apply)
+ device_index = (known after apply)
+ network_interface_id = (known after apply)
}
~ root_block_device {
~ delete_on_termination = true -> (known after apply)
~ device_name = "/dev/sda1" -> (known after apply)
~ encrypted = false -> (known after apply)
~ iops = 600 -> (known after apply)
+ kms_key_id = (known after apply)
~ tags = {} -> (known after apply)
~ throughput = 0 -> (known after apply)
~ volume_id = "vol-007f3d2d27b510740" -> (known after apply)
~ volume_size = 200 -> (known after apply)
~ volume_type = "gp2" -> (known after apply)
}
}
这是子模块的文件main.tf
data "aws_ami" "ubuntu" {
owners = ["amazon"]
filter {
name = "name"
values = ["Deep Learning Base AMI (Ubuntu 18.04) Version 38.0"]
}
}
resource "aws_eip" "lb" {
instance = aws_instance.ec2_instance.id
vpc = true
}
resource "aws_security_group" "instance_private_group" {
description = "Private security group for the ${var.username}.example.com instance"
name = "ec2 ${var.username}.example.com"
vpc_id = data.aws_vpc.debian-ec2-env.id
ingress {
description = "description"
protocol = "TCP"
from_port = 22
to_port = 22
cidr_blocks = ["XX.XX.XX.XX/32"]
}
}
data "aws_vpc" "debian-ec2-env" {
id = var.vpc_id
}
data "aws_iam_instance_profile" "instance_profile" {
name = var.instance_profile_name
}
resource "aws_instance" "ec2_instance" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.instance_private_group.id]
availability_zone = var.az
iam_instance_profile = data.aws_iam_instance_profile.instance_profile.name
user_data = templatefile("${path.root}/templates/cloud-init.tpl", { username = var.username, admins = var.admins })
ebs_block_device {
device_name = "/dev/sda1"
volume_size = var.storage_size
}
tags = {
Name = "${var.username}.example.com"
HiddenName = var.username
Operator = "${var.username}@example.com"
}
}
你认为这是什么原因造成的?
编辑1:
在调整了一些日志记录后,我试图重新运行应用程序,以减少阻止我看到重要细节的日志记录量。用户数据似乎没有更改。但我现在看到的是:
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# module.coworker1.aws_eip.lb has been changed
~ resource "aws_eip" "lb" {
id = "eipalloc-52f1ee6c"
+ tags = {}
# (12 unchanged attributes hidden)
}
# module.coworker1.aws_instance.ec2_instance has been changed
~ resource "aws_instance" "ec2_instance" {
id = "i-0f498ac75ad66199e"
~ public_dns = "ec2-18-197-141-73.eu-central-1.compute.amazonaws.com" -> "ec2-3-67-119-191.eu-central-1.compute.amazonaws.com"
~ public_ip = "18.197.141.73" -> "3.67.119.191"
tags = {
"HiddenName" = "coworker1"
"Name" = "coworker1.example.com"
"Operator" = "coworker1@example.com"
}
# (28 unchanged attributes hidden)
# (6 unchanged blocks hidden)
}
因此,如果我正确理解,在创建Elastic IP后,公共IP会发生变化,这会导致与Terraform显示的结果不同。我应该在ec2实例上依赖Elastic IP吗?
我认为在您的示例中有两类不同的令人惊讶的行为:
- EC2实例的IP地址和主机名在运行后发生了更改
- 提供者报告说,
tags
从未设置变为设置为空映射,尽管未设置和空映射对该参数的意义相同
你的问题的其余部分表明你主要对其中的第一个感兴趣,所以我将在这里重点讨论这一点。
这种情况的关键在于,在创建了一个EC2实例后,将一个Elastic IP附加到该实例会导致EC2 API开始将该Elastic IP及其相关的主机名报告为public_ip
和public_dns
。这意味着,尽管这些值在技术上并不是"零";Terraform之外的变化";,它们在CCD_ 7的定义之外进行了更改,因为对IP地址的更改发生在EC2 API报告实例已成功创建之后。
不幸的是,这种更改public_ip
的行为是在EC2实例启动后将弹性IP地址附加到EC2实例的基本行为。这是作为public_ip
文档的一部分提到的,因此这里来自Terraform的消息实际上只是加强了文档中的警告。如果您实际上没有在模块中的任何其他地方使用aws_instance.ec2_instance.public_ip
,那么这种值的更改是无害的,您可以将其视为Terraform只是更正其自己的IP地址记录。接受包含此消息的计划后,应将更新后的值提交给新的Terraform状态快照,并且除非您稍后分离弹性IP地址,否则不会再次报告更改。