如何通过Terraform将EC2实例挂载到AWS EFS

36次阅读
没有评论

问题描述

正在尝试使用Terraform创建一些EC2实例,并希望自动化挂载它们的文件系统到EFS的步骤。手动运行这些命令的步骤如下:

$ sudo mkdir /var/www/html/efs-mount-point
$ sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${module.efs_mount.file_system_dns_name}:/ /var/www/html/efs-mount-point

从字符串插值中可以看出,用户已经尝试在创建EC2实例时,在Terraform的provisioner "remote-exec"块中设置这些步骤。
这在大部分情况下都可以工作,因为目录被创建了,但是在实际挂载步骤中遇到了错误。用户认为Terraform可能在一切建立正确的网络连接之前就尝试挂载。下面是完整的错误信息:

Error: remote-exec provisioner error
  with aws_instance.example-instance-with-efs[0],
  on main.tf line 72, in resource "aws_instance" "example-instance-with-efs":
  72:   provisioner "remote-exec" {
error executing "/tmp/terraform_1760279708.sh": Process exited with status 32

用户想知道是否这种方法是正确的。他觉得可以在EC2 AMI中设置已经挂载或者有一些启动挂载脚本,而不是依赖于Terraform provisioners(因为在文档中被标记为最后的手段)。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

我发现一个更好的方法是使用启动配置的user_data。虽然它仍然存在一些与provisioners相同的问题,但在权限和时间方面的错误几率要小得多,如其他问题所示。
例如:

resource "aws_launch_configuration" "sample" {
  image_id          = "ami-04afe279c8bff9ed8"
  instance_type = "t2.micro"
  security_groups = [
    aws_security_group.efs.id,
  ]
  user_data = <<-EOF
              #!/bin/bash
              mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${module.efs_mount.file_system_dns_name}:/ /your/mount/point/
              EOF
  lifecycle {
    create_before_destroy = true
  }
}

需要注意的是,这还意味着我额外使用了一个Auto Scaling Group,这可能不适合每个人的需求。

方案2

使用脚本或工具来管理容器的启动顺序可能会增加复杂性,并且需要确保容器A和容器B之间的依赖关系正确设置。
另一种方法是编写脚本或使用工具来控制容器的运行顺序。你可以使用docker run命令来手动控制容器的启动顺序,或者使用一些第三方工具来管理容器的依赖关系。

示例:

以下是一个简单的bash脚本示例,可以在容器A启动后启动容器B:

#!/bin/bash
# 启动容器A
docker run -d --name container_a your_image_a
# 等待容器A完全启动
while ! docker exec container_a echo "Container A is ready"; do
  sleep 1
done
# 启动容器B
docker run -d --name container_b your_image_b

在这个示例中,我们首先使用docker run命令启动容器A,并将其命名为container_a。然后,使用一个循环来等待容器A完全启动(这里是通过在容器内运行echo命令来测试)。一旦容器A就绪,我们再使用docker run命令启动容器B,并将其命名为container_b

正文完