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
相关产品推荐
相关产品推荐

