Amazon FSx for NetApp ONTAP検証環境をAWS CDKで丸ごとデプロイしてみた(Multi-AZ)

目次

はじめに

Amazon FSx for NetApp ONTAPの検証がしたい!! という時がありますよね。 弊社でもAmazon FSx for NetApp ONTAPを検証する機会が増えています。ただ、マネージドコンソール上で手動でVPCから作成すると手間と時間がかかってしまいます。

こんな時は、IaCでVPCやアクセス用のEC2ホストも含めて丸ごとセットでデプロイし、検証が終わったらすぐに削除したいですね。

弊社では特にクラウド環境の構築はIaCがスタンダードとなっています。CloudFormationで記述してもよかったのですが、IaCツールとしてホットなAWS CDK v2を使って最低限の検証環境をデプロイするコードを書いてみました。

注意: AWS CDKのバージョン1 は、2022/6/1をもってメンテナンスモードに移行し、現在はAWS CDK バージョン2がメインストリームになっています。しかし、AWS CDK v1の情報がネット上には多く存在しています。情報を得るときは、CDKバージョンがv2であることを確認しましょう。

aws.amazon.com

Amazon FSx for NetApp ONTAPとは

Amazon FSx for NetApp ONTAP は、AWSの提供するフルマネージドの共有ストレージです。元々はNetApp社のONTAPはオンプレミスから始まり、AWS上にもデプロイ可能となりました。オンプレミスのONTAPと連携することも可能となり、非常に魅力的なストレージとなっております。

詳細はこちら↓ www.storage-channel.jp

AWS CDKとは

AWS CDKは、TypeScript, Pythonなどのプログラミング言語で抽象的にリソースを宣言し、CloudFormationテンプレートを生成することができます。多少プログラミング言語については理解しておく必要がありますが、依存関係を自動で解消してくれたり、Visual Studio Code上で補完してくれたり、コードを記載している途中で記載ミスを指摘してくれたりと、非常に便利です。

そのため、今回はCDKで記載してみます。

詳細はこちら↓ aws.amazon.com docs.aws.amazon.com

構築する検証環境のゴール

今回作成するCDKコードのゴールを以下のように定めました。

  • VPC作成含め、一発で環境一式がデプロイできること
  • AWS CDK v2でデプロイすること
  • 最低限のリソースのみデプロイすること
  • インターネットから隔離されたセキュアなVPC環境であること
  • EC2上のLinuxからSVM(Storage Virtual Machine)にログインしてコマンドを試せること
  • EC2上のLinuxからボリュームをNFSマウントできること
  • 検証が完了したらVPCレベルで一発で削除しお片付けができること

全体構成図

今回作成する構成図は次の通りです。

CDKでデプロイする環境の構成図

FSx for Netapp ONTAPのコンポーネントファイルシステムSVM、ボリュームなども記載したかったのですが正確に記載すると複雑になるので今回は概略図となっています。今後のブログで詳しく解説する予定です。

CDKコードでデプロイされるリソースと作成順序

作成したコードからリソースが以下の順にデプロイされます。

  1. VPCの作成
  2. Private Subnet 2個作成
  3. EC2にセッションマネージャで接続するためのVPCエンドポイント作成
  4. EC2(BastionHost)のデプロイ
  5. ONTAPのファイルシステム用SecurityGroup作成
  6. ONTAPのファイルシステム作成
  7. SVM(Storage Virtual Machine)作成
  8. ボリューム(/vol1)の作成

設計のポイント

・EC2への接続

ポイントはVPC内にPublic Subnetを配置せず、Private Subnetのみとしました。EC2にはSSMのセッションマネージャでログインするようにしています。

なお、このような環境でセッションマネージャで接続するためには、VPCエンドポイントをアタッチする必要があります。インターフェイス型のVPCエンドポイントは時間で課金されるのでドキドキしますね。*1

加えてSSMのセッションマネージャで接続するためにはサブネットごとに3個必要となることにも注意が必要です。*2

サブネットは2個あるので、2サブネットx3エンドポイント=6個必要となるのですが節約のためEC2の存在しているサブネットにのみVPCエンドポイントを3個作成しています。

そのため、別のサブネットにEC2を起動させると当然のことながらセッションマネージャから接続できないことに注意が必要です。

ファイルシステムへの接続

今回は、EC2上からNFSマウントして最低限の動作確認ができるようにしました。

また、シングルAZでもよかったのですが、マルチAZの方が需要がありそうなのでマルチAZで構築しました。

検証用ということもありパスワードは平易なものを利用していますので、適宜変更をお願いいたします。

CDKからのデプロイ

CDKプロジェクトを作成し、以下のファイルをlib配下の「プロジェクト名.ts」に組み込み(class名などを変更する必要はありますが)、それ以外はそのまま動くと思います。

※コード、パラメータの説明は、割愛させていただきます。

作成したコード

import { aws_ec2 as ec2, aws_fsx as fsx, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";

export class FsxOntapStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    //
    // VPCの作成
    //

    const vpcFsxTest = new ec2.Vpc(this, "vpcFsxTest", {
      cidr: "10.0.0.0/16",
      maxAzs: 2,
      vpcName: "vpcFsxTest",
      subnetConfiguration: [],
    });

    //
    // Private Subnetを各AZに作成
    //

    const privateSubnet1a = new ec2.PrivateSubnet(this, "privateSubnet1a", {
      vpcId: vpcFsxTest.vpcId,
      availabilityZone: "ap-northeast-1a",
      cidrBlock: "10.0.1.0/24",
    });

    const privateSubnet1c = new ec2.PrivateSubnet(this, "privateSubnet1c", {
      vpcId: vpcFsxTest.vpcId,
      availabilityZone: "ap-northeast-1c",
      cidrBlock: "10.0.2.0/24",
    });

    //
    // RouteTableIDの保持
    //

    const private1aRouteTableId = privateSubnet1a.routeTable.routeTableId;
    const private1cRouteTableId = privateSubnet1c.routeTable.routeTableId;

    //
    // EC2を配置するサブネットをプライマリーのサブネットとして定義
    //

    const primarySubnet = vpcFsxTest.selectSubnets({
      subnets: [
        ec2.Subnet.fromSubnetAttributes(this, "Subnet", {
          subnetId: privateSubnet1a.subnetId,
          availabilityZone: "ap-northeast-1a",
        }),
      ],
    });

    //
    // プライベートSubnetのEC2にSSMセッションマネージャで接続するためのEndpoint作成
    // 節約のためにEC2を配置するSubnetだけにEndpoint接続
    // 3種類必要なことに注意
    //

    const ssmEndpoint = vpcFsxTest.addInterfaceEndpoint("ssmEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.SSM,
      subnets: primarySubnet,
    });

    const ssmMessagesEndpoint = vpcFsxTest.addInterfaceEndpoint(
      "ssmMessagesEndpoint",
      {
        service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
        subnets: primarySubnet,
      }
    );

    const ec2MessagesEndpoint = vpcFsxTest.addInterfaceEndpoint(
      "ec2MessagesEndpoint",
      {
        service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES,
        subnets: primarySubnet,
      }
    );

    //
    // BastionHostの構築
    //

    const bastionHost = new ec2.BastionHostLinux(this, "BastionHost", {
      vpc: vpcFsxTest,
      instanceName: "bastionHost",
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.MICRO
      ),
      subnetSelection: primarySubnet,
    });

    //
    // ONTAPのファイルシステムにアタッチするセキュリティグループ作成
    //

    const securityGroupOntapFileSystem = new ec2.SecurityGroup( this, "secuirtyGroupOntapFileSystem",
      {
        vpc: vpcFsxTest,
        allowAllOutbound: true,
      }
    );

    securityGroupOntapFileSystem.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(22)
    );

    securityGroupOntapFileSystem.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.allIcmp()
    );

    securityGroupOntapFileSystem.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(2049) //NFS用
    );

    //
    // ONTAPファイルシステムの作成
    //

    const ontapFileSystem = new fsx.CfnFileSystem(this, "ontapFileSystem", {
      fileSystemType: "ONTAP",
      ontapConfiguration: {
        deploymentType: "MULTI_AZ_1",
        fsxAdminPassword: "fsxAdmin123!",
        preferredSubnetId: privateSubnet1a.subnetId,
        routeTableIds: [private1aRouteTableId, private1cRouteTableId],
        throughputCapacity: 128,
      },
      subnetIds: [privateSubnet1a.subnetId, privateSubnet1c.subnetId],
      storageCapacity: 1024,
      securityGroupIds: [securityGroupOntapFileSystem.securityGroupId],
      tags: [
        {
          key: "Name",
          value: "ontapFileSystem",
        },
      ],
    });

    const ontapFileSystemId = ontapFileSystem.ref;

    //
    // SVMの作成
    //

    const ontapSVM = new fsx.CfnStorageVirtualMachine(this, "ontapSVM", {
      fileSystemId: ontapFileSystemId,
      name: "ontapSVM",
      rootVolumeSecurityStyle: "MIXED",
      svmAdminPassword: "svmAdmin123!",
      tags: [
        {
          key: "Name",
          value: "ontapSVM",
        },
      ],
    });

    const ontapSVMId = ontapSVM.ref;

    //
    // ボリュームの作成
    //

    const cfnVolume = new fsx.CfnVolume(this, "ontapVolume", {
      name: "ontapVolume",
      ontapConfiguration: {
        junctionPath: "/vol1",
        sizeInMegabytes: "4096",
        storageEfficiencyEnabled: "true",
        storageVirtualMachineId: ontapSVMId,
        securityStyle: "MIXED",
        tieringPolicy: {
          coolingPeriod: 2,
          name: "AUTO",
        },
      },
      tags: [
        {
          key: "Name",
          value: "ontapVolume",
        },
      ],
      volumeType: "ONTAP",
    });
  }
}

なお、スタックを分けたり、CIFSに対応させたり、cdk.jsonからパラメータを取ったり、既存のVPCにデプロイ可能にしたりなど、まだまだこれからコードを育てていく予定です。

デプロイしてみる

それでは実際にデプロイします。なお、デプロイまでの時間は約2349秒(約40分)でした。「即座にデプロイ」するつもりでしたが、少々時間がかかりますので検証の少し前から準備をしておく必要があります。

user@cdkDeployEnv:~/cdk/fsx-ontap$ cdk diff        #コードと実環境の差分を確認する
user@cdkDeployEnv:~/cdk/fsx-ontap$ cdk deploy      #デプロイする

...(現環境との変更箇所、リソースのリストなどが表示されますが省略)...

Do you wish to deploy these changes (y/n)? y
FsxOntapStack: deploying...
[0%] start: Publishing xxxxxxxxxxxxxxxxx:current_account-current_region
[100%] success: Published xxxxxxxxxxxxxxxxx:current_account-current_region
FsxOntapStack: creating CloudFormation changeset...

 ✅  FsxOntapStack

✨  Deployment time: 2339.59s

Outputs:
FsxOntapStack.BastionHostBastionHostIdxxxxxxxxxxxxxxxxxxxx = i-xxxxxxxxxxxxxxxxxxxx
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:AAAAAAAAAAAAAA:stack/FsxOntapStack/BBBBBBBBBBBBBBBBBBB

✨  Total time: 2349.12s

user@cdkDeployEnv:~/cdk/fsx-ontap$

何のリソース作成に時間がかかったのか?

FSx for NetApp ONTAPは意外とデプロイに時間がかかりました。 ご参考までにデプロイまでに時間がかかったリソースのトップ3を記載します。(CloudFormationのイベントから算出)

  1. ONTAP ファイルシステム: 31分34秒
  2. ONTAP SVM: 4分23秒
  3. ONTAP Volume: 1分4秒

ファイルシステムが堂々の1位となりました。ファイルシステムを作り直したり、後述しますが設定変更でも意外と時間がかかることは注意しておいた方がよさそうです。

あくまでも今回の検証環境のデプロイですので各設定内容によって時間が大きく変わる場合があります。また、今後のアップデートなどでデプロイ時間も変わる可能性もあります。

注意点

今回CDKコードを作成する際に検証環境なので特にパラメータも決めずに大まかにFSx for NetAPP ONTAPをデプロイして、詳細なパラメータはデプロイ後に入力していました。

CloudFormationレベルでパラメータを更新する時に"Update requires: Replacement"が意外に多いので注意が必要です。*3

例えば、以下のパラメータ変更は影響が無いと直感的に思っていたのですが実際にはファイルシステムの置き換えが始まりました。*4 

  • ファイルシステムの管理者パスワードの変更
  • アタッチするSecurity Groupの変更
  • アタッチするルートテーブルの変更 など

検証環境なので特に置き換えられても影響はないのでは? と思うかもしれませんが、パラメータを入力・デプロイを繰り返すこともありますが、その都度30分ほどのデプロイの時間を要します。

パスワード変更のパラメータを入れて、軽い気持ちで動作確認してみようと思ってもデプロイ中の31分間は、次のパラメータの更新や削除ができなくなってしまうので注意が必要です。

なお、新しいリソースがデプロイされてから自動置き換えとなりますので、ダウンタイムは最小限になります。設定変更時に約30分間ONTAPが利用できなくなるという意味ではありません。

まとめ

今回はAmazon FSx for NetApp ONTAPを使いたい時に丸ごとデプロイ可能なコードをCDKで作成してみました。検証環境では常に利用しているわけではないので、IaCで制御するとコスト面でも嬉しいですね。

次回は実際にデプロイされた検証環境の動作確認をしていきます。

お楽しみに。

  執筆: 伊藤 好宏, 技官  

*1:VPCエンドポイントの料金: 料金 - AWS PrivateLink | AWS

*2:Systems Manager を使用したインターネットアクセスなしでのプライベート EC2 インスタンスの管理

*3:2022年6月5日現在の情報です。FSx for NetApp ONTAPは、日々改善されているためReplacementの対象も今後は減少していくでしょう

*4:CloudFormation AWS::FSx::FileSystem: https://docs.amazonaws.cn/en_us/AWSCloudFormation/latest/UserGuide/aws-resource-fsx-filesystem.html#cfn-fsx-filesystem-securitygroupids