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加载外部脚本文件,确保内容正确解析:
- 创建外部脚本文件
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
- 在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
相关产品推荐
相关产品推荐

