如何使用Pulumi将EFS挂载到EC2实例并使用UserData?

huangapple go评论72阅读模式
英文:

How to Mount EFS to EC2 Instance with UserData using Pulumi?

问题

我一直在努力通过UserData字段在创建EC2实例时能够挂载EFS卷。我正在使用Pulumi的Go库,我的代码如下所示:


// ... 上面创建了具有适当安全组和挂载目标的EFS ...

dir := configuration.Deployment.Efs.MountPoint
availabilityZone := configuration.Deployment.AvailabilityZone
region := configuration.Deployment.Region

userdata := args.Efs.ID().ToStringOutput().ApplyT(func(id string) (string, error) {
	script := `
			#!/bin/bash -xe
			exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1

			mkdir -p %s
			echo "%s.%s.%s.amazonaws.com:/ %s nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0" | tee -a /etc/fstab
			mount -a
			`
	return fmt.Sprintf(script, dir, availabilityZone, id, region, dir), nil
}).(pulumi.StringOutput)


ec2, err := ec2.NewInstance(ctx, fmt.Sprintf("%s_instance", name), &ec2.InstanceArgs{
    // ... (其他字段) ...
    UserData: userdata,
    // ... (其他字段) ...
})

但是当我使用Pulumi创建所有资源时,UserData脚本根本不运行。我猜测问题可能是EFS ID在创建EC2实例时还没有被解析出来,但我认为Pulumi会自动处理依赖关系的顺序,因为EC2实例现在依赖于EFS卷。我还添加了一个显式的DependsOn()来查看是否是这个问题,但没有帮助。

我做错了什么吗?任何帮助将不胜感激,谢谢!

我尝试了上面示例的几个变体。我查看了这个示例:https://stackoverflow.com/questions/69972268/pulumi-efs-id-output-to-ec2-launchconfiguration-userdata?newreg=cd8c2e39996e43aebd334a157c4e6467

但是也无法使其工作。

英文:

I've been struggling to be able to mount an EFS volume to an EC2 instance on creation with the UserData field. I'm using Pulumi's Go library and what I have looks like the following:


// ... EFS with proper security groups and mountTarget created above ...

dir := configuration.Deployment.Efs.MountPoint
availabilityZone := configuration.Deployment.AvailabilityZone
region := configuration.Deployment.Region

userdata := args.Efs.ID().ToStringOutput().ApplyT(func(id string) (string, error) {
	script := `
			#!/bin/bash -xe
			exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1

			mkdir -p %s
			echo "%s.%s.%s.amazonaws.com:/ %s nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0" | tee -a /etc/fstab
			mount -a
			`
	return fmt.Sprintf(script, dir, availabilityZone, id, region, dir), nil
}).(pulumi.StringOutput)


ec2, err := ec2.NewInstance(ctx, fmt.Sprintf("%s_instance", name), &ec2.InstanceArgs{
    // ... (other fields) ...
    UserData: userdata,
    // ... (other fields) ...
})

But when I create all the resources with Pulumi, the UserData script doesn't run at all. My assumption is that the EFS ID isn't resolved in time by the time the EC2 instance is created, but I thought that Pulumi would handle the dependency ordering automatically since the EC2 instance is now dependent on the EFS volume. I also added an explicit DependsOn() to see if that could be the issue, but it didn't help.

Is there something that I am doing wrong? Any help would be appreciated, thank you!

I've tried several variations of the above example. I looked at this example: https://stackoverflow.com/questions/69972268/pulumi-efs-id-output-to-ec2-launchconfiguration-userdata?newreg=cd8c2e39996e43aebd334a157c4e6467

But couldn't get that to work either.

答案1

得分: 1

我已经弄清楚了,问题最终解决了几个方面:

1)内联脚本的格式化不应该有制表符。
2)pulumi.Sprintf() 比使用 ApplyT() 更好用。
3)当尝试执行 mount -a 时,EFS 卷还没有准备好挂载。

综合起来,现在的代码如下所示:

instanceArgs := &ec2.InstanceArgs{
    // ... 参数字段 ...
}
script := `#!/bin/bash
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
mkdir -p %s
echo "%s.efs.%s.amazonaws.com:/ %s nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0" >> /etc/fstab
EFS_STATUS="unknown"
WAIT_TIME=10
RETRY_CNT=15
while [[ $EFS_STATUS != "\"available\"" ]]; do
  echo "Waiting for EFS to start..."
  sleep $WAIT_TIME
  EFS_STATUS=$(aws efs describe-file-systems | jq '.FileSystems | map(select(.FileSystemId == "%s")) |  map(.LifeCycleState) | .[0]')
done
while true; do
  mount -a -t nfs4
  if [ $? = 0 ]; then
    echo "Successfully mounted EFS to instance."
    break
  fi;
  if [ $RETRY_CNT -lt 1 ]; then
    echo "EFS could not mount after $RETRY_CNT retries."
  fi;
  echo "EFS could not mount, retrying..."
  ((RETRY_CNT--))
  sleep $WAIT_TIME
done`

userData := pulumi.Sprintf(script, mountDir, Efs.ID(), region, mountDir, Efs.ID())
instanceArgs.UserData = userData

ec2, err := ec2.NewInstance(ctx, fmt.Sprintf("%s_instance", name), instanceArgs)
英文:

I was able to figure it out, the issue ended up being a couple things:

  1. The formatting on the inlined script needed to not have tabs.
  2. pulumi.Sprintf() ended up working better than using ApplyT().
  3. The EFS volume wasn't ready to mount when it tried to do mount -a.

Put together, it now looks like this:

instanceArgs := &ec2.InstanceArgs{
    // ... arg fields ...
}
script := `#!/bin/bash
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
mkdir -p %s
echo "%s.efs.%s.amazonaws.com:/ %s nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0" >> /etc/fstab
EFS_STATUS="unknown"
WAIT_TIME=10
RETRY_CNT=15
while [[ $EFS_STATUS != "\"available\"" ]]; do
  echo "Waiting for EFS to start..."
  sleep $WAIT_TIME
  EFS_STATUS=$(aws efs describe-file-systems | jq '.FileSystems | map(select(.FileSystemId == "%s")) |  map(.LifeCycleState) | .[0]')
done
while true; do
  mount -a -t nfs4
  if [ $? = 0 ]; then
    echo "Successfully mounted EFS to instance."
	break
  fi;
  if [ $RETRY_CNT -lt 1 ]; then
    echo "EFS could not mount after $RETRY_CNT retries."
  fi;
  echo "EFS could not mount, retrying..."
  ((RETRY_CNT--))
  sleep $WAIT_TIME
done`

userData := pulumi.Sprintf(script, mountDir, Efs.ID(), region, mountDir, Efs.ID())
instanceArgs.UserData = userData

ec2, err := ec2.NewInstance(ctx, fmt.Sprintf("%s_instance", name), instanceArgs)

huangapple
  • 本文由 发表于 2022年11月10日 02:15:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/74379601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定