Terraform+AWS:实例重缩放时密钥对与Provisioner未执行问题求助
Terraform修改实例规格后密钥对与Provisioner异常问题解决
问题现象
首次用Terraform创建两台AWS实例正常,修改i2实例规格从t2.micro改为t3.micro并执行terraform apply后:
- 旧实例销毁重建,但新实例无法SSH连接(需手动修改
~/.ssh/config) - SSH登录后看不到bootstrap安装内容,Provisioner未执行
- 密钥对未正确关联或SSH配置未同步新实例信息
相关配置代码
本地实例参数配置
locals { instances= { i1= { size = "t2.micro", ami = data.aws_ami.ami_default.id, auth = module.ec2.keypair_id, region = "us-east-1a", user_data = "bootstrap.tpl", } i2= { size = "t2.micro", ami = data.aws_ami.ami_default.id, auth = module.ec2.keypair_id, region = "us-east-1b", user_data = "bootstrap.tpl", } } }
密钥对与实例创建代码
resource "aws_key_pair" "auth" { key_name = "auth" public_key = file("${var.key_pair}.pub") } resource "aws_instance" "instance" { for_each = var.instances size = each.value.size ami = each.value.ami key_name = aws_key_pair.auth.id vpc_security_group_ids = [aws_security_group.ec2_security_group.id] subnet_id = var.subnets[each.value.region].id user_data = file("userdata.tpl") root_block_device { volume_size = each.value.vol_size } provisioner "local-exec" { command = templatefile("${path.module}/ssh_cfg.tpl", { hostname = self.public_ip, user = "ec2-user", identityfile = var.key_pair }) interpreter = ["bash", "-c"] } }
问题根源
- SSH配置未更新:
local-exec执行的模板默认是追加写入~/.ssh/config,旧实例IP条目未删除,导致SSH连接时仍指向旧实例,需手动修改。 - User Data配置不一致:本地实例参数中指定的是
bootstrap.tpl,但aws_instance里用的是userdata.tpl,配置不匹配;且User Data未添加变更触发器,重建实例时可能不执行。 - Provisioner执行逻辑缺失:未指定Provisioner仅在实例创建时执行,且无连接就绪校验,实例重建时可能因网络未就绪导致执行失败。
解决方案
1. 修复SSH配置写入逻辑
修改local-exec命令,先删除对应实例的旧配置,再追加新配置:
provisioner "local-exec" { when = create command = <<EOT sed -i '/Host ${each.key}/d' ~/.ssh/config echo "$(templatefile("${path.module}/ssh_cfg.tpl", { hostname = self.public_ip, user = "ec2-user", identityfile = var.key_pair, host_alias = each.key }))" >> ~/.ssh/config EOT interpreter = ["bash", "-c"] }
对应的ssh_cfg.tpl需包含实例别名:
Host ${host_alias} HostName ${hostname} User ${user} IdentityFile ${identityfile}
2. 对齐User Data配置并添加触发器
将aws_instance的user_data改为引用本地实例参数中定义的文件,并添加哈希值确保重建时必执行:
resource "aws_instance" "instance" { # 保留其他配置 user_data = "${file("${each.value.user_data}")}${sha1(file("${each.value.user_data}"))}" }
3. 确保密钥对正确关联
如果需要为每个实例单独绑定密钥对(可选),修改密钥对资源为多实例模式:
resource "aws_key_pair" "auth" { for_each = var.instances key_name = "auth-${each.key}" public_key = file("${var.key_pair}.pub") } resource "aws_instance" "instance" { # 保留其他配置 key_name = aws_key_pair.auth[each.key].id }
4. 添加SSH连接就绪校验
如果有其他SSH类Provisioner,添加connection块确保网络就绪后再执行:
resource "aws_instance" "instance" { # 保留其他配置 connection { type = "ssh" user = "ec2-user" private_key = file(var.key_pair) host = self.public_ip timeout = "5m" } }
内容的提问来源于stack exchange,提问作者mike01010
相关产品推荐
相关产品推荐

