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

Terraform local-exec执行scp失败:EC2实例SSH连接被拒绝求助

问题排查与解决方案

核心原因分析

SSH连接被拒绝的本质是EC2实例的SSH服务尚未完全就绪,或者执行环境存在细微差异,固定的sleep 5不足以覆盖实例启动后的初始化耗时。以下是针对性的解决方法:

1. 替换固定延迟为动态等待SSH就绪

用循环检测代替固定sleep,确保SSH端口开放后再执行scp。修改local-exec的command:

provisioner "local-exec" {
  command = <<EOT
    until nc -z ${self.public_ip} 22; do
      echo "Waiting for SSH to be ready..."
      sleep 2
    done
    scp -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r ../ansible ubuntu@${self.public_ip}:~/playbook_dir
  EOT
}
  • 依赖nc(netcat)工具,若系统未安装可先执行apt install netcat(Debian/Ubuntu)或brew install netcat(macOS)
  • 循环每2秒检测一次22端口,直到连通再执行scp

2. 确保Terraform等待实例状态完全就绪

在aws_instance资源中添加等待条件,确保实例通过系统状态检查:

resource "aws_instance" "example" {
  # 其他实例配置...

  provisioner "local-exec" {
    # 上述动态等待的command内容
  }

  # 等待实例运行且通过状态检查
  lifecycle {
    postcondition {
      condition     = self.instance_state == "running" && self.status_checks == "ok"
      error_message = "EC2 instance failed status checks."
    }
  }
}

也可以用time_sleep资源配合实例状态,强制等待足够时长:

resource "time_sleep" "wait_for_instance" {
  create_duration = "30s"
  depends_on = [aws_instance.example]
}

resource "null_resource" "copy_files" {
  depends_on = [time_sleep.wait_for_instance]
  provisioner "local-exec" {
    command = "scp -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r ../ansible ubuntu@${aws_instance.example.public_ip}:~/playbook_dir"
  }
}

3. 检查SSH密钥路径的绝对引用

避免使用~,因为Terraform的local-exec可能运行在不同用户上下文(比如sudo执行时),改用绝对路径:

provisioner "local-exec" {
  command = "scp -i /home/your-username/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r ../ansible ubuntu@${self.public_ip}:~/playbook_dir"
}

替换/home/your-username为你的实际用户路径

4. 备选方案:改用remote-exec+file provisioner

Terraform的remote-exec会自动等待SSH连接就绪,配合file provisioner复制目录更可靠:

# 先创建目标目录
provisioner "remote-exec" {
  inline = ["mkdir -p ~/playbook_dir"]
  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file("~/.ssh/id_rsa")
    host        = self.public_ip
    timeout     = "5m"
    agent       = false
  }
}

# 复制本地目录到实例
provisioner "file" {
  source      = "../ansible"
  destination = "~/playbook_dir"
  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file("~/.ssh/id_rsa")
    host        = self.public_ip
  }
}

额外验证点

  • 确认安全组已允许你的本地IP(或Terraform运行环境的IP)访问22端口
  • 检查EC2实例的系统日志(AWS控制台→实例→监控→系统日志),确认SSH服务已正常启动
  • 若使用自定义AMI,确认AMI中已安装并启用SSH服务

内容的提问来源于stack exchange,提问作者AvallaSD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 10:50:24