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

Terraform创建EC2实例时user_data不执行问题求助

EC2 User Data未执行问题排查与解决

核心问题分析

从调试输出可定位两个关键异常:

  • user_data的计划值为哈希字符串(858c462aa8a14896b64953424d1d0c5e2f79e122),与配置的脚本内容不匹配,说明Terraform对user_data的解析或处理出现异常
  • 重复出现.user_data_replace_on_change: planned value cty.False,该属性默认值为true,若被强制设为false,会导致user_data变更时不重建实例,旧脚本无法重新执行

针对性修复步骤

1. 修正脚本语法与缩进问题

原user_data中#!/bin/bash前有多余空格,会导致系统无法识别脚本解释器,直接失效;同时脚本内ECR域名存在拼写错误(us-east-q需改为us-east-1)。调整后的Terraform代码:

resource "aws_instance" "ec2nginx1" {
  ami                    = nonsensitive(data.aws_ssm_parameter.ami.value)
  instance_type          = var.instance_type
  subnet_id              = aws_subnet.prisubnet1.id
  vpc_security_group_ids = [aws_security_group.nginx_ec2sg.id]
  depends_on             = [null_resource.building_docker_image]

  # 强制开启user_data变更时重建实例
  user_data_replace_on_change = true

  # 使用<<-EOF自动去除行首缩进,避免脚本命令前出现多余空格
  user_data = <<-EOF
#!/bin/bash
# 合并yum安装命令,提升执行效率
sudo yum install -y openssh-server aws-cli docker curl
# 确保docker开机自启并立即启动
sudo systemctl enable --now docker
sudo aws configure set aws_access_key_id ${var.ACCESS_KEY}
sudo aws configure set aws_secret_access_key ${var.SECRET_KEY}
sudo aws configure set default.region us-east-1
# 修正ECR域名拼写错误
sudo aws ecr get-login-password --region us-east-1 | sudo docker login --username AWS --password-stdin ${aws_ecr_repository.myrepo.registry_id}.dkr.ecr.us-east-1.amazonaws.com
sudo docker pull ${aws_ecr_repository.myrepo.repository_url}:latest
sudo docker container run --network host ${aws_ecr_repository.myrepo.repository_url}:latest
EOF
}

2. 解决Terraform用户数据哈希不匹配问题

若仍出现计划值为哈希的情况,说明Terraform可能将user_data识别为敏感数据,或插值过程存在异常。可改用templatefile加载外部脚本文件,确保内容正确解析:

  1. 创建外部脚本文件user_data.sh:
#!/bin/bash
sudo yum install -y openssh-server aws-cli docker curl
sudo systemctl enable --now docker
sudo aws configure set aws_access_key_id ${ACCESS_KEY}
sudo aws configure set aws_secret_access_key ${SECRET_KEY}
sudo aws configure set default.region us-east-1
sudo aws ecr get-login-password --region us-east-1 | sudo docker login --username AWS --password-stdin ${REGISTRY_ID}.dkr.ecr.us-east-1.amazonaws.com
sudo docker pull ${REPOSITORY_URL}:latest
sudo docker container run --network host ${REPOSITORY_URL}:latest
  1. 在Terraform中引用该脚本:
resource "aws_instance" "ec2nginx1" {
  # ... 保留原有其他配置 ...
  user_data_replace_on_change = true
  user_data = templatefile("${path.module}/user_data.sh", {
    ACCESS_KEY     = var.ACCESS_KEY
    SECRET_KEY     = var.SECRET_KEY
    REGISTRY_ID    = aws_ecr_repository.myrepo.registry_id
    REPOSITORY_URL = aws_ecr_repository.myrepo.repository_url
  })
}

3. 替换硬编码密钥(最佳实践)

不要在user_data中硬编码AWS密钥,建议为EC2实例附加具备ECR访问权限的IAM角色,无需配置密钥即可拉取ECR镜像:

# 创建EC2可假定的IAM角色
resource "aws_iam_role" "ec2_ecr_role" {
  name = "ec2-ecr-access-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

# 附加ECR只读权限策略
resource "aws_iam_role_policy_attachment" "ecr_access" {
  role       = aws_iam_role.ec2_ecr_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

# 创建实例配置文件
resource "aws_iam_instance_profile" "ec2_ecr_profile" {
  name = "ec2-ecr-access-profile"
  role = aws_iam_role.ec2_ecr_role.name
}

# 在EC2实例中引用实例配置文件,并移除user_data中的aws configure命令
resource "aws_instance" "ec2nginx1" {
  # ... 保留原有其他配置 ...
  iam_instance_profile = aws_iam_instance_profile.ec2_ecr_profile.name
  user_data_replace_on_change = true
  user_data = <<-EOF
#!/bin/bash
sudo yum install -y openssh-server aws-cli docker curl
sudo systemctl enable --now docker
sudo aws ecr get-login-password --region us-east-1 | sudo docker login --username AWS --password-stdin ${aws_ecr_repository.myrepo.registry_id}.dkr.ecr.us-east-1.amazonaws.com
sudo docker pull ${aws_ecr_repository.myrepo.repository_url}:latest
sudo docker container run --network host ${aws_ecr_repository.myrepo.repository_url}:latest
EOF
}

4. 验证脚本执行状态

登录EC2实例后,通过以下命令查看cloud-init日志,确认脚本执行情况:

# 查看脚本输出日志
cat /var/log/cloud-init-output.log
# 查看cloud-init详细执行日志
cat /var/log/cloud-init.log

若日志中存在错误(如yum安装失败、docker启动失败等),可针对性排查环境依赖问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:24:46