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

如何通过AWS JS SDK为EC2实例设置环境变量?

如何通过Node.js SDK为EC2实例设置持久化环境变量

核心问题

  • 尝试了多种方法(包括SSM Parameter Store、Cloud-Config写入文件、直接修改profile/bashrc),均无法为新创建的EC2实例成功设置USER_ID和SERVER_ID环境变量
  • Node.js SDK和AWS CLI执行UserData的结果一致,SSH登录后变量为空
  • cloud-init日志(/var/log/cloud-init-output.log)中无用户数据执行痕迹,无法定位失败原因
  • 接受任何能将变量绑定到新实例的方案(包括SSH方式)

尝试过的方法及结果

方法1:直接通过UserData输出环境变量

编写bash脚本输出变量,但实例中无任何执行痕迹,变量未设置。

function userDataScript(userId, serverId) {
  return `
  #!/usr/bin/bash
  echo 'export USER_ID=${userId}'
  echo 'export SERVER_ID=${serverId}'
  `;
}

// 启动EC2实例代码
exports.launchEC2 = async function(server) {
    try {
      const keyName = server.id;
      const keyPair = await EC2.createKeyPair({KeyName: keyName}).promise();
      server.key = keyPair.KeyMaterial;

      const instanceParams = {
        ImageId: imageAMI,
        InstanceType: 't2.micro',
        MinCount: 1,
        MaxCount: 1,
        KeyName: keyName,
        SecurityGroupIds: [SEC_GROUP],
        UserData: Buffer.from(userDataScript(server.userId, server.id)).toString('base64')
      };

      const data = await EC2.runInstances(instanceParams).promise();
      const instanceId = data.Instances[0].InstanceId;
      server.instanceId = instanceId;
      await server.save();

      console.log(`已启动实例 ${instanceId}`);
    } catch (err) {
      console.log(`启动实例出错: ${err.message}`);
    }
}

方法2:将变量写入文件

修改脚本将变量写入文件,结果与方法1一致,变量未生效。

方法3:使用SSM Parameter Store存储变量

先通过SDK创建参数,再在UserData中读取,但SSH登录后变量为空。

async function createParameterStoreKeys(userId, serverId) {
  const params = {
    Name: `/paramstore/${serverId}/environment-variables`,
    Type: 'String',
    Value: JSON.stringify({
      USER_ID: userId,
      SERVER_ID: serverId
    })
  };
  await SSM.putParameter(params).promise();
  console.log(`已为${serverId}创建参数存储键`);
}

async function userDataScript(identifier) {
  return `
    export USER_ID=$(aws --region=us-east-2 ssm get-parameter --name /paramstore/${identifier}/environment-variables --query 'Parameter.Value' --output text | jq -r '.USER_ID')
    export SERVER_ID=$(aws --region=us-east-2 ssm get-parameter --name /paramstore/${identifier}/environment-variables --query 'Parameter.Value' --output text | jq -r '.SERVER_ID')
  `;
}

// 启动EC2实例代码
exports.launchEC2 = async function(server) {
    try {
      await createParameterStoreKeys(server.userId, server.id);
  
      const keyName = server.id;
      const keyPair = await EC2.createKeyPair({KeyName: keyName}).promise();
      server.key = keyPair.KeyMaterial;

      const instanceParams = {
        ImageId: imageAMI,
        InstanceType: 't2.micro',
        MinCount: 1,
        MaxCount: 1,
        KeyName: keyName,
        SecurityGroupIds: [SEC_GROUP],
        UserData: Buffer.from(await userDataScript(server.id)).toString('base64')
      };

      const data = await EC2.runInstances(instanceParams).promise();
      const instanceId = data.Instances[0].InstanceId;
      server.instanceId = instanceId;
      await server.save();

      console.log(`已启动实例 ${instanceId}`);
    } catch (err) {
      console.log(`启动实例出错: ${err.message}`);
    }
}

方法4:使用Cloud-Config写入profile.d

通过cloud-config将变量写入/etc/profile.d/env.sh,SSH登录后变量仍为空。

async function userDataScript(userId, serverId) {
  return `#cloud-config
  write_files:
    - content: |
        export USER_ID=${userId}
        export SERVER_ID=${serverId}
      path: /etc/profile.d/env.sh
      owner: ubuntu:ubuntu
      permissions: '0755'
  runcmd:
    - source /etc/profile.d/env.sh
  `  
}

// 启动EC2实例代码
exports.launchEC2 = async function(server) {
    try {
      const keyName = server.id;

      const instanceParams = {
        ImageId: imageAMI,
        InstanceType: 't2.micro',
        MinCount: 1,
        MaxCount: 1,
        KeyName: keyName,
        SecurityGroupIds: [SEC_GROUP],
        UserData: Buffer.from(await userDataScript(server.userId, server.id)).toString('base64')
      };

      const data = await EC2.runInstances(instanceParams).promise();
      const instanceId = data.Instances[0].InstanceId;
      server.instanceId = instanceId;
      await server.save();

      console.log(`已启动实例 ${instanceId}`);
    } catch (err) {
      console.log(`启动实例出错: ${err.message}`);
    }
}

补充尝试:直接修改bashrc/profile

尝试将变量追加到~/.bashrc、/etc/profile、/etc/environment,无论是否用sudo,均未生效。示例代码:

function userDataScript(userId, serverId) {
  return `
  #!/usr/bin/bash
  echo "export USER_ID=${userId}" >> ~/.bashrc
  echo "export SERVER_ID=${serverId}" >> ~/.bashrc
  source ~/.bashrc
  `;
}

AWS CLI执行同样逻辑的命令也失败:

aws ec2 run-instances --image-id $AMI --count 1 --instance-type t2.micro --key-name $KP --security-group-ids $SEC_GRP --user-data '#!/bin/bash
echo export USER_ID=user123 >> /etc/profile
echo export SERVER_ID=server123 >> /etc/profile
'

排查方向与可行方案

1. 先确认UserData是否真的被执行

  • 登录实例后查看/var/log/cloud-init.log和/var/log/cloud-init-output.log,搜索user-data相关日志,确认脚本是否被加载、是否有执行错误
  • 在UserData脚本开头添加echo "Starting user data script" >> /tmp/userdata.log,登录后查看/tmp/userdata.log是否存在,验证脚本是否启动

2. 正确设置持久化环境变量

如果要让环境变量对所有SSH登录用户生效,需要写入全局配置文件,且注意脚本权限和执行用户:

function userDataScript(userId, serverId) {
  return `#!/bin/bash
# 确保以root权限执行
echo "USER_ID=${userId}" >> /etc/environment
echo "SERVER_ID=${serverId}" >> /etc/environment
`;
}

注意:/etc/environment不需要export关键字,直接写KEY=VALUE格式即可,系统登录时会自动加载。

3. SSM Parameter Store方案的正确姿势

问题可能出在实例权限上:默认EC2实例没有SSM Parameter Store的读取权限,需要给实例附加包含ssm:GetParameter权限的IAM角色。

  • 创建IAM角色,附加AmazonSSMReadOnlyAccess策略(或自定义策略仅允许读取指定参数)
  • 启动EC2时指定该IAM角色(IamInstanceProfile参数)
  • 修改UserData脚本,确保jq已安装(如果是Ubuntu系统,需要先执行apt update && apt install -y jq)

4. 替代方案:直接传递变量到启动脚本

如果后续有配置脚本需要使用这些变量,可以直接在UserData中把变量写入配置文件,或者作为参数传递给后续脚本:

function userDataScript(userId, serverId) {
  return `#!/bin/bash
# 写入配置文件供后续脚本读取
cat > /opt/server-config.env << EOF
USER_ID=${userId}
SERVER_ID=${serverId}
EOF
chmod 644 /opt/server-config.env
# 后续脚本可以通过source /opt/server-config.env获取变量
`;
}

5. 验证环境变量的正确方式

SSH登录后,不要直接echo $USER_ID,先检查配置文件是否被正确写入:

  • 查看/etc/environment内容:cat /etc/environment
  • 查看/etc/profile.d/env.sh内容:cat /etc/profile.d/env.sh
  • 重新加载配置文件后再验证:source /etc/environment && echo $USER_ID

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:00:02