You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"]
  }
}

问题根源

  1. SSH配置未更新:local-exec执行的模板默认是追加写入~/.ssh/config,旧实例IP条目未删除,导致SSH连接时仍指向旧实例,需手动修改。
  2. User Data配置不一致:本地实例参数中指定的是bootstrap.tpl,但aws_instance里用的是userdata.tpl,配置不匹配;且User Data未添加变更触发器,重建实例时可能不执行。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:43:21