Amazon FSx for NetApp ONTAPとは
Amazon FSx for NetApp ONTAPはNetApp ONTAPファイルシステム上に構築されたスケーラブルなフルマネージド型のファイルストレージ。
詳しくは以下の記事を参照。
» Amazon FSx for NetApp ONTAPとは何ですか - FSx for ONTAP
本記事ではTerraformを使用してNFSでマウントできるようにするまでの手順を記載する。
VPCの作成
FSxのインスタンスを設置するVPCを作成する。
Terraformの基本設定とproviderの設定と初期化
terraformブロックでtfstateファイルはローカルに保存するように設定する。(S3に保存する場合は適宜変更する)
AWSを利用するため、awsプロバイダーを設定する。
terraform {
  required_version = ">= 0.12"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
  backend "local" {
    path = "example.tfstate"
  }
}
provider "aws" {
  region = "ap-northeast-1"
  default_tags {
    tags = {
      Project = "fsx-test"
    }
  }
}
設定したら以下のコマンドでawsプロバイダのインストールを含めた初期化を行なう。
$ terraform init
.terraformディレクトリーや.terraform.lock.hclファイルが作成される。
ネットワークの作成
VPC, サブネット, インターネットゲートウェイ, ルートテーブルを作成する。
# VPCの作成
resource "aws_vpc" "vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
}
# インターネットゲートウェイの作成
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
}
# サブネットの作成
resource "aws_subnet" "subnet_c" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1c"
  cidr_block              = "10.0.0.0/20"
  map_public_ip_on_launch = true
}
# ルートテーブルの作成
resource "aws_route_table" "route_table_c" {
  vpc_id = aws_vpc.vpc.id
}
resource "aws_route" "route_c" {
  route_table_id         = aws_route_table.route_table_c.id
  gateway_id             = aws_internet_gateway.igw.id
  destination_cidr_block = "0.0.0.0/0"
}
resource "aws_route_table_association" "route_table_association_c" {
  subnet_id      = aws_subnet.subnet_c.id
  route_table_id = aws_route_table.route_table_c.id
}
この段階で一度applyしておく。
$ terraform apply
credentialsの設定は適宜おこななう。
NFSのセキュリティグループの作成
NFSのポート(2049番ポート)を開けるためのセキュリティグループを作成する。
egressは全てのポートを開けておく。
ingressで必要なポートが他にある場合や、egressで全てのポートを開けるのが気になる場合は適宜変更する。
CIDRはVPCのCIDRを指定しており、VPC内からのみアクセスできるようにしている。
更に絞りたい場合は適宜変更する。
resource "aws_security_group" "nfs_sg" {
  name   = "nfs"
  vpc_id = aws_vpc.vpc.id
}
resource "aws_security_group_rule" "ingress_nfs_sg" {
  type              = "ingress"
  from_port         = 2049
  to_port           = 2049
  protocol          = "tcp"
  cidr_blocks       = ["10.0.0.0/16"]
  security_group_id = aws_security_group.nfs_sg.id
}
resource "aws_security_group_rule" "egress_nfs_sg" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.nfs_sg.id
}
ここまでの内容をapplyしておく。
$ terraform apply
Amazon FSx for NetApp ONTAPの作成(シングルAZ構成)
シングルAZ構成のFSxを作成する。
# ファイルシステムの作成
resource "aws_fsx_ontap_file_system" "example" {
  storage_capacity    = 1024
  subnet_ids          = [aws_subnet.subnet_c.id]
  preferred_subnet_id = aws_subnet.subnet_c.id
  deployment_type     = "SINGLE_AZ_1"
  throughput_capacity = 128
  security_group_ids  = [aws_security_group.nfs_sg.id]
  timeouts {
    create = "60m"
    update = "60m"
    delete = "2h"
  }
}
# ストレージ仮想マシン (SVM) の作成
resource "aws_fsx_ontap_storage_virtual_machine" "example" {
  file_system_id = aws_fsx_ontap_file_system.example.id
  name           = "example-svm"
}
# ボリュームの作成
resource "aws_fsx_ontap_volume" "example" {
  name                       = "example_volume"
  junction_path              = "/vol1"
  size_in_megabytes          = 1024
  storage_efficiency_enabled = true
  storage_virtual_machine_id = aws_fsx_ontap_storage_virtual_machine.example.id
}
FSxの構成は「ファイルシステム←ストレージ仮想マシン (SVM)←ボリューム」のような階層構造になる。
ws_fsx_ontap_file_systemは作成に20分程度かかる。
Terraformのデフォルト待機時間は30分でそれほど余裕が無いので、念のためにtimeoutsで待機時間を延長している。
ここまでの内容をapplyしておく。
$ terraform apply
EC2からNFSマウントする
お試しのEC2インスタンスをVPC内に作成し、NFSマウントしてみる。
EC2インスタンスプロファイルの作成
EC2インスタンスにはSSMを使用するためのプロファイルを作成する。
resource "aws_iam_instance_profile" "instance_profile" {
  role = aws_iam_role.instance_profile_role.name
}
resource "aws_iam_role" "instance_profile_role" {
  name               = "ec2-instance-profile"
  assume_role_policy = data.aws_iam_policy_document.instance_profile_assume_role.json
}
data "aws_iam_policy_document" "instance_profile_assume_role" {
  statement {
    effect = "Allow"
    actions = [
      "sts:AssumeRole",
    ]
    principals {
      type = "Service"
      identifiers = [
        "ec2.amazonaws.com",
      ]
    }
  }
}
resource "aws_iam_policy_attachment" "instance_profile_policy_attachment" {
  name       = "ec2-instance-profile-ssm"
  roles      = [aws_iam_role.instance_profile_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
» 参考: 【Terraform】Session Managerでログイン可能なEC2を建てる
EC2インスタンスの作成
EC2のインスタンスを立ち上げる
resource "aws_instance" "host" {
  ami                    = "ami-02eb2602e381117c7" # Amazon Linux 2023 AMI 2023.2.20231011.0 arm64 HVM kernel-6.1
  instance_type          = "t3.nano"
  subnet_id              = aws_subnet.subnet_c.id
  iam_instance_profile   = aws_iam_instance_profile.instance_profile.name
  vpc_security_group_ids = [aws_security_group.ec2_sg.id]
  root_block_device {
    volume_type = "gp2"
    volume_size = 8
  }
  metadata_options {
    instance_metadata_tags = "enabled"
    http_endpoint          = "enabled"
    http_tokens            = "optional"
  }
  user_data = <<-EOF
    #!/bin/bash
    sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
    sudo systemctl enable amazon-ssm-agent --now
  EOF
}
resource "aws_security_group" "ec2_sg" {
  name   = "ec2"
  vpc_id = aws_vpc.vpc.id
}
resource "aws_security_group_rule" "ingress_ec2_sg" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["10.0.0.0/16"]
  security_group_id = aws_security_group.ec2_sg.id
}
resource "aws_security_group_rule" "egress_ec2_sg" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.ec2_sg.id
}
ここまでの内容をapplyしておく。
$ terraform apply
EC2インスタンスにNFSマウントする
立ち上げたEC2インスタンスにSession Managerでログインする。
$ aws ssm start-session --target i-xxxxxxxxxxxxxxxxx
インスタンスのID(i-xxxxxxxxxxxxxxxxx)はterraform applyの結果や、terraform state show aws_instance.hostで確認できる。
ログインできたらNFSマウントを試す。
$ sudo mkdir -p /mnt/fsx
$ sudo mount -t nfs svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.com:/vol1 /mnt/fsx
svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.comはFSxのNFSエンドポイント。
実際の値はAWSコンソールで確認するか、Terraformのtfstateを参照すると確認できる。
terraform stateコマンドでaws_fsx_ontap_storage_virtual_machineの値を参照し、nfsのdns_nameを確認する。
$ terraform state show aws_fsx_ontap_storage_virtual_machine.example
...
            nfs        = [
                {
                    dns_name     = "svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.com"
                    ip_addresses = [
                      ...
                    ]
                },
            ]
...
dfコマンドでマウントできているか確認する。
$ df -h
...
svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.com:/vol1 973M  320K  973M   1% /mnt/fsx
ファイルを作成してみる。
$ sudo echo "hello" > /mnt/fsx/hello.txt
$ ls /mnt/fsx
hello.txt
一度アンマウントする。
$ sudo umount /mnt/fsx
$ ls /mnt/fsx
もう一度マウントしてみる。
$ sudo mount -t nfs svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.com:/vol1 /mnt/fsx
$ cat /mnt/fsx/hello.txt
hello
NFSでマウントできていることが確認できた。
/etc/fstabでマウントする場合は以下の通り。
svm-xxxxxxxxxxxxxxxxx.fs-xxxxxxxxxxxxxxxxx.fsx.ap-northeast-1.amazonaws.com:/vol1 /mnt/fsx nfs defaults 0 0
/etc/fstabを編集したら以下のコマンドでマウントする。
$ mount -a
マルチAZ構成
マルチAZ構成にしてみる。
サブネットの追加
マルチAZ構成とするために、ap-northeast-1aにもサブネットを作成する。
ネットワーク設定に以下を追加する。
...
resource "aws_subnet" "subnet_a" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-northeast-1a"
  cidr_block              = "10.0.16.0/20"
  map_public_ip_on_launch = true
}
resource "aws_route_table" "route_table_a" {
  vpc_id = aws_vpc.vpc.id
}
resource "aws_route" "route_a" {
  route_table_id         = aws_route_table.route_table_a.id
  gateway_id             = aws_internet_gateway.igw.id
  destination_cidr_block = "0.0.0.0/0"
}
resource "aws_route_table_association" "route_table_association_a" {
  subnet_id      = aws_subnet.subnet_a.id
  route_table_id = aws_route_table.route_table_a.id
}
ファイルシステムの変更
マルチAZにするためにはシングルAZ構成に比べて以下を変更する。
- aws_fsx_ontap_file_systemの- deployment_typeを- SINGLE_AZ_1から- MULTI_AZ_1に変更
- aws_fsx_ontap_file_systemの- subnet_idsにサブネットを追加
- route_table_idsを追加し、すべてのサブネットでルートテーブルを設定
具体的には以下のような設定となる。
resource "aws_fsx_ontap_file_system" "example" {
  storage_capacity    = 1024
  subnet_ids          = [aws_subnet.subnet_a.id, aws_subnet.subnet_c.id] # subnet_a を追加
  preferred_subnet_id = aws_subnet.subnet_c.id
  deployment_type     = "MULTI_AZ_1" # MULTI_AZ_1 に変更
  throughput_capacity = 128
  security_group_ids  = [aws_security_group.nfs_sg.id]
  route_table_ids     = [aws_route_table.route_table_a.id, aws_route_table.route_table_c.id] # 追加
  timeouts {
    create = "60m"
    update = "60m"
    delete = "2h"
  }
}
VolumeやSVMを誤って削除されないようにガードする
aws_fsx_ontap_file_systemの設定値の一部を修正すると、aws_fsx_ontap_volumeやaws_fsx_ontap_storage_virtual_machineが削除される。
不用意に削除されないようにするため、念のためlifecycleでガードする。
resource "aws_fsx_ontap_storage_virtual_machine" "example" {
  ...
  lifecycle {
    prevent_destroy = true
  }
}
resource "aws_fsx_ontap_volume" "example" {
  ...
  lifecycle {
    prevent_destroy = true
  }
}
この状態でaws_fsx_ontap_storage_virtual_machineやaws_fsx_ontap_volumeが削除されるようなterraform applyするとエラーで止まるようになる。

