Elastic File System

AWS 彈性檔案系統 (Amazon Elastic File System,Amazon EFS) 是 AWS 提供的一種雲端儲存服務,提供無伺服器、完全彈性和加密的檔案儲存,供 AWS 運算服務和企業內部使用。

Amazon EFS 支援網路檔案系統 (NFS) 版本 4.0 和 4.1 (NFSv4) 協定,並通過可移植作業系統介面 (POSIX) 權限控制使用者對檔案的訪問。

EFS 可以同時被多個系統或是 AWS 服務掛載。目前 EC2、ECS 與 Lambda 等計算服務皆可以掛載 EFS。

在 EC2 上掛載 EFS

EC2 需要手動掛載 EFS。以 Amazon Linux 2023 為例,首先安裝 Amazon EFS 客戶端。

sudo yum install -y amazon-efs-utils

然後在跟目錄底下新建一個 /efs 資料夾。

cd /
sudo mkdir efs

接下來就能透過下面的指令掛載 EFS。

# sudo mount -t efs <FILE-SYSTEM-ID> <EFS-MOUNT-POINT>
# 範例如下
sudo mount -t efs fs-abcd123456789ef0 efs/

[!NOTE]

EC2 掛載 EFS 不需要任何 Policy。

在 Lambda 上掛載 EFS

Lambda 上也能掛載 EFS。 但是 Lambda 必須放在 VPC 底下,並透過 Access Point 來存取 EFS。 下面以 Terraform 為例,建立一個 EFS 並掛載到 Lambda。

以 Terraform 為例。首先建立一個 EFS 與 Access Point。

resource "aws_efs_file_system" "for_lambda" {
  performance_mode = "generalPurpose"
  encrypted        = true

  tags = {
    Name = "efs_for_lambda"
  }
}

resource "aws_efs_backup_policy" "policy" {
  file_system_id = aws_efs_file_system.for_lambda.id

  backup_policy {
    status = "ENABLED"
  }
}

resource "aws_efs_mount_target" "for_lambda" {
  file_system_id  = aws_efs_file_system.for_lambda.id
  subnet_id       = data.aws_subnet.private.id
  security_groups = [aws_security_group.allow_internal_access_to_efs.id]
}

resource "aws_efs_access_point" "for_lambda" {
  file_system_id = aws_efs_file_system.for_lambda.id

  root_directory {
    path = var.root_directory

    creation_info {
      owner_gid   = 1000
      owner_uid   = 1000
      permissions = "755"
    }
  }

  posix_user {
    gid = 1000
    uid = 1000
  }
}

Lambda 在存取 EFS 中的檔案時,會以 Access Point 設定的 UID (User ID) 與 GID (Group ID) 來判斷是否擁有對檔案的權限

For Amazon EFS, file system objects (that is, files, directories, and so on) are owned by a single owner and a single group. Amazon EFS uses the mapped numeric IDs to check permissions when a user attempts to access a file system object.

所以如果你想用 Lambda 存取 EFS 中用 EC2 建立的檔案, 可以將 UID 與 GID 都設定為 1000,即 EC2 預設使用者的 UID 與 GID。

接下來在 Lambda 中掛載 EFS。

resource "aws_lambda_function" "web_lambda_function" {
  depends_on = [aws_efs_mount_target.alpha]

  filename         = var.filename
  source_code_hash = filesha256(var.filename)
  handler          = "Bref\\LaravelBridge\\Http\\OctaneHandler"
  runtime          = var.lambda_runtime
  function_name    = "${var.app_name}-web"
  memory_size      = 1024
  timeout          = 28
  architectures    = ["arm64"]
  role             = aws_iam_role.lambda_execution.arn
  layers           = [var.php_lambda_layer_arn]

  environment {
    variables = merge(local.lambda_function_environment_variables, {
      BREF_LOOP_MAX                    = "250"
      OCTANE_PERSIST_DATABASE_SESSIONS = "1"
    })
  }

  # 要掛載 EFS,Lambda 必須放在 VPC 底下
  vpc_config {
    subnet_ids         = [aws_subnet.private.id]
    security_group_ids = [aws_security_group.egress_only.id]
  }

  # 掛載 EFS,注意掛載路徑必須是 /mnt 開頭
  file_system_config {
    arn              = aws_efs_access_point.for_lambda.arn
    local_mount_path = "/mnt/efs"
  }
}

這樣 Lambda 中的 /mnt/efs 就會掛載到 EFS 中的 /lambda

EFS 支援 SQLite

因為 EFS 支援 NFSv4,所以可以在上面使用 SQLite。 讀多寫少的小網站完全可以考慮 EFS + SQLite 的方式來代替一般的資料庫。

參考資料


This site uses Just the Docs, a documentation theme for Jekyll.