🧩

【AWS Trainium 50本ノック #3】計算機クラスタ構築編

に公開

第 3 章 計算機クラスタ構築編

本章では以下を仮定します。

  • AWS のアカウントを所有している
  • シェルの基本的な操作の理解

問題 (11-18)

開発作業中にずっとTrnを立ち上げっぱなしにするのは経済的ではありません。普段は安いインスタンス上で開発して、プログラム実行時のみTrnインスタンスを立ち上げる(開発物を含むファイルたちはマウントしてTrnインスタンスから見えるようにしつつ)ほうがお財布に優しいです。さらに、大規模なモデルを学習するには、分散学習、すなわちTrnを複数台同時に立ち上げて、それらで同一のプログラムを並列的に実行しつつ通信させながら動かす必要があります。これを行うためにAWSマネジメントコンソール上からTrnインスタンスを1つずつ起動して手動でプログラムを立ち上げていると、非常に面倒です。そこで「計算機クラスタ」を立ち上げます。具体的にはAWS ParallelClusterを立ち上げます。

以下では、AWS ParallelCluster 他からなる以下のようなAWSリソース群を作成します。ただし、GUI(=AWSマネジメントコンソール)上でポチポチ作成していく代わりに、AWS CloudFormationを用いて CUI で作成します。

  • ⚠️ 金銭的コストについて
    • この環境構築を実施後、少なくとも以下の課金が発生します(いずれも us-east-2価格・2025-06-05調べ)。
      課金の内容を表示
      • ヘッドノードの料金
        • 起動している間は常に課金が発生します。作業していない時に停止することもできます。インスタンスタイプは c5.4xlarge なので、$0.68/h かかります。
      • コンピュートノードの料金
        • 以下の設定で環境構築した場合、普段はコンピュートノードは1つも起動していません。計算ジョブの投入に応じて起動し、起動している間だけ課金が発生します。インスタンスタイプは trn1.32xlarge なので、$21.50/h/ノードかかります。
      • Amazon FSx for Lustre の料金
        • 以下の設定では、1.2TBのファイルシステムをデータ圧縮ありの設定で作成しています。この場合、(ノードの稼働状況に関わらず)約 $87.6/月かかります。
      • S3の料金
        • バケットに保存されている容量に応じて $0.023/GB/月 かかります。
      • VPCの料金
        • ノードの稼働状況に関わらず $0.045/h かかり、またデータ転送量に応じて $0.045/GB かかります。
      • これらの合計を雑に勘定すると「月10万円程度 + Trn1利用料($21.50/h/ノード)」となりますが、実際の使用の仕方・リージョン・各サービスの時価・為替レート等で変動しますので各自の責任の下で進めてください。
    • 課金が走り続けることを避けるため、この50本ノックを完了(または放棄)する際には、必ずリソースの削除を実施してください。手順は本章の最後にあります。
  1. AWS マネジメントコンソールの画面上部にある、下図のようなアイコンをクリックして、AWS CloudShell を起動してください。

CloudShell は、ブラウザ上で使えるAWS公式のLinuxターミナル環境です。各種 aws コマンドが直ちに使用可能となっています。以下の本章の内容は、CloudShell上で作業してください。

💡 CloudShell の FAQ
  • 作業途中で放置していたらシェルの画面に何かメッセージが表示されました
    • シェルの画面をクリックしてください。数秒経って、元の作業途中のシェルが表示されればそのまま続行可能です。一方、もしシェル履歴がクリアされてしまった場合は、環境変数もクリアされてしまっています。ただしその場合も、保存済みのファイルはそのまま残っています(※ 非常に長期間放置してしまった場合には、保存済みのファイルも消えてしまう場合があります)。
  1. AWSリソース群を作成するリージョンおよびアベイラビリティゾーンを設定します。

    • まず、リージョンを設定します。Trn が利用可能なリージョンから、お好みのものを選択してください。

      export REGION=us-east-2
      
    • 次に、アベイラビリティゾーンを設定します。

      export AZ1=us-east-2c
      export AZ2=us-east-2a
      
      • 注意: AZ1, AZ2 は以下の要件を満たすように選択する必要があります。
        • AZ1: (REGION内で)Trn1が利用可能なアベイラビリティゾーンを選択してください。例えば、以下コマンドで調べられます。

          export REGION=us-east-2
          aws ec2 describe-instance-type-offerings \
            --location-type availability-zone \
            --filters Name=instance-type,Values=trn1.32xlarge \
            --region $REGION \
            --query "InstanceTypeOfferings[].Location" \
            --output text
          
        • AZ2: (REGION内で)AZ1以外の任意のアベイラビリティゾーンを選択してください。※ ParallelClusterやECSで使用するのはAZ1のみです。ALBの仕様上、2つ以上のアベイラビリティゾーンが必要なため2つ作成しています。

  2. CloudFormation を使用して、VPCを作成してください。以下の CloudFormation テンプレートファイル vpc.yaml を保存した上で、以下の「環境変数設定コマンド」を実行後、「CloudFormationコマンド」を実行してください。数分以内にSuccessfully created/updated stack ... と表示されれば成功です。もし失敗した場合は、以下の「CloudFormation の FAQ」をご参照ください。

    vpc.yaml
    AWSTemplateFormatVersion: "2010-09-09"
    Description: "CloudFormation template to deploy a VPC"
    
    Parameters:
      CidrBlock:
        Type: String
        Description: CIDR Block
        Default: 10.0.0.0/16
    
      VPCName:
        Type: String
        Description: Name of your VPC
    
      SubnetsAZ1:
        Type: AWS::EC2::AvailabilityZone::Name
        Description: Availability zone in which the subnets will be created.
    
      SubnetsAZ2:
        Type: AWS::EC2::AvailabilityZone::Name
        Description: Availability zone in which the subnets will be created.
    
    Resources:
      VPC:
        Type: AWS::EC2::VPC
        Properties:
          EnableDnsSupport: true
          EnableDnsHostnames: true
          CidrBlock: !Ref CidrBlock
          Tags:
            - Key: Name
              Value: !Ref VPCName
    
      FlowLogsRole:
        Type: AWS::IAM::Role
        Properties:
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Principal:
                  Service: vpc-flow-logs.amazonaws.com
                Action: sts:AssumeRole
          Policies:
            - PolicyName: flowlogs-policy
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: Allow
                    Action:
                      - logs:CreateLogStream
                      - logs:PutLogEvents
                      - logs:DescribeLogGroups
                      - logs:DescribeLogStreams
                    Resource: !GetAtt FlowLogsGroup.Arn
    
      FlowLogsGroup:
        Type: AWS::Logs::LogGroup
        Properties:
          RetentionInDays: 7
    
      FlowLogVPC:
        Type: AWS::EC2::FlowLog
        Properties:
          DeliverLogsPermissionArn: !GetAtt FlowLogsRole.Arn
          LogGroupName: FlowLogsGroup
          ResourceId: !Ref VPC
          ResourceType: VPC
          TrafficType: ALL
    
      InternetGateway:
        Type: AWS::EC2::InternetGateway
    
      GatewayToInternet:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
          VpcId: !Ref VPC
          InternetGatewayId: !Ref InternetGateway
    
      NATGateway:
        Type: AWS::EC2::NatGateway
        Properties:
          AllocationId: !GetAtt ElasticIP.AllocationId
          SubnetId: !Ref PublicSubnet1
    
      ElasticIP:
        Type: AWS::EC2::EIP
        Properties:
          Domain: vpc
    
      PublicSubnet1:
        Type: AWS::EC2::Subnet
        DependsOn: VPC
        Properties:
          MapPublicIpOnLaunch: true
          VpcId: !Ref VPC
          CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 3, 14]]
          AvailabilityZone: !Ref SubnetsAZ1
          Tags:
            - Key: Name
              Value: !Join [" ", [!Ref VPCName, "Public Subnet -", !Ref SubnetsAZ1]]
    
      PublicSubnet2:
        Type: AWS::EC2::Subnet
        DependsOn: VPC
        Properties:
          MapPublicIpOnLaunch: true
          VpcId: !Ref VPC
          CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 3, 14]]
          AvailabilityZone: !Ref SubnetsAZ2
          Tags:
            - Key: Name
              Value: !Join [" ", [!Ref VPCName, "Public Subnet -", !Ref SubnetsAZ2]]
    
      PrivateSubnet1:
        Type: AWS::EC2::Subnet
        DependsOn: VPC
        Properties:
          VpcId: !Ref VPC
          CidrBlock: !Select [2, !Cidr [!GetAtt VPC.CidrBlock, 3, 14]]
          AvailabilityZone: !Ref SubnetsAZ1
          Tags:
            - Key: Name
              Value:
                !Join [" ", [!Ref VPCName, "Private Subnet -", !Ref SubnetsAZ1]]
    
      PublicRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
    
      PublicRoute:
        Type: AWS::EC2::Route
        Properties:
          RouteTableId: !Ref PublicRouteTable
          DestinationCidrBlock: 0.0.0.0/0
          GatewayId: !Ref InternetGateway
    
      PrivateRouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
    
      PrivateRouteToInternet:
        Type: AWS::EC2::Route
        Properties:
          RouteTableId: !Ref PrivateRouteTable
          DestinationCidrBlock: 0.0.0.0/0
          NatGatewayId: !Ref NATGateway
    
      PublicSubnet1RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          SubnetId: !Ref PublicSubnet1
          RouteTableId: !Ref PublicRouteTable
    
      PublicSubnet2RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          SubnetId: !Ref PublicSubnet2
          RouteTableId: !Ref PublicRouteTable
    
      PrivateSubnet1RTAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          SubnetId: !Ref PrivateSubnet1
          RouteTableId: !Ref PrivateRouteTable
    
      DefaultSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupDescription: Default Security group
          VpcId: !Ref VPC
    
      DefaultSecurityGroupIngress:
        Type: AWS::EC2::SecurityGroupIngress
        Properties:
          GroupId: !Ref DefaultSecurityGroup
          IpProtocol: -1
          FromPort: -1
          ToPort: -1
          SourceSecurityGroupId: !Ref DefaultSecurityGroup
    
      DefaultSecurityGroupEgress:
        Type: AWS::EC2::SecurityGroupEgress
        Properties:
          GroupId: !Ref DefaultSecurityGroup
          IpProtocol: -1
          FromPort: -1
          ToPort: -1
          DestinationSecurityGroupId: !Ref DefaultSecurityGroup
    
      VPCESecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupDescription: Security group for VPC Endpoint
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 443
              ToPort: 443
              SourceSecurityGroupId: !Ref DefaultSecurityGroup
          SecurityGroupEgress:
            - IpProtocol: -1
              FromPort: -1
              ToPort: -1
              CidrIp: 0.0.0.0/0
          VpcId: !Ref VPC
    
      S3Endpoint:
        Type: AWS::EC2::VPCEndpoint
        Properties:
          RouteTableIds:
            - !Ref PublicRouteTable
            - !Ref PrivateRouteTable
          ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
          VpcEndpointType: Gateway
          VpcId: !Ref VPC
    
      LogsEndpoint:
        Type: AWS::EC2::VPCEndpoint
        Properties:
          VpcEndpointType: Interface
          PrivateDnsEnabled: true
          ServiceName: !Sub com.amazonaws.${AWS::Region}.logs
          VpcId: !Ref VPC
          SubnetIds:
            - !Ref PrivateSubnet1
          SecurityGroupIds:
            - !Ref VPCESecurityGroup
    
    Outputs:
      VPC:
        Value: !Ref VPC
        Description: ID of the VPC
        Export:
          Name: !Sub ${AWS::StackName}-VPC
      PublicSubnet1:
        Value: !Ref PublicSubnet1
        Description: ID of the public subnet
        Export:
          Name: !Sub ${AWS::StackName}-PublicSubnet1
      PublicSubnet2:
        Value: !Ref PublicSubnet2
        Description: ID of the public subnet
        Export:
          Name: !Sub ${AWS::StackName}-PublicSubnet2
      PrivateSubnet1:
        Value: !Ref PrivateSubnet1
        Description: ID of the private subnets
        Export:
          Name: !Sub ${AWS::StackName}-PrivateSubnet1
      DefaultSecurityGroup:
        Value: !Ref DefaultSecurityGroup
        Description: ID of the default security group
    
    • 環境変数設定コマンド

      # 作成するVPCの名前を定義(注意:同一AWSアカウント・同一リージョン内で一意である必要があります)
      export VPC_NAME=trn-drill-vpc
      
    • CloudFormationコマンド

      aws cloudformation deploy \
          --region ${REGION} \
          --capabilities CAPABILITY_IAM \
          --template-file vpc.yaml \
          --stack-name ${VPC_NAME} \
          --parameter-overrides \
              VPCName=${VPC_NAME} \
              SubnetsAZ1=${AZ1} \
              SubnetsAZ2=${AZ2}
      
💡 CloudFormation の FAQ
  • 失敗メッセージが表示された
    • 原因を確認しましょう。AWSマネジメントコンソールから見るのが便利です。検索欄に CloudFormation と入力して CloudFormation の画面を表示すると、直近の作成物(=スタック)の一覧が表示されます。❌印のついているものを選択し、右側の詳細画面から「イベント」をクリックし「根本原因を表示」をクリックすると、失敗の根本原因が表示されます。必要に応じて yaml ファイルを修正し、aws cloudformation deploy コマンドをリトライしてください。
  • リトライすると An error occurred (ValidationError) when calling the CreateChangeSet operation: ... is in ROLLBACK_COMPLETE state and can not be updated. のようなメッセージが表示された
    • このような場合は、一旦この作成物(=スタック)を削除してください。aws cloudformation delete-stack --stack-name <スタック名> で削除できます。その後、aws cloudformation deploy コマンドをリトライしてください(スタック名は変更無しで大丈夫です)。
    • なお、スタックを削除するのではなく「回復」する方法も存在します(参考)。
  • 同一内容の aws cloudformation deploy コマンドを重複して実行するとどうなりますか?同じリソースが2つ作成されますか?
    • いいえ。aws cloudformation deploy は、「スタック名」をキーとして動作します。同じスタック名を指定して再度 deploy を実行した場合、CloudFormation はそのスタックの 変更を検知して、差分があれば更新(update)しますが、差分がなければ「変更なし」として何も起きません。
  • Compute fleet が動いているのでスタックを更新できません的なメッセージが表示された。どうすれば?
    • 「Compute fleet の停止」を行ってから aws cloudformation deploy し、その後「Compute fleet の再開」を行う必要があります(注意:「コンピュートノードが1つも起動していないこと」と「Compute fleet が停止していること」は異なります)。以下手順で実行できます:
      • CloudShell に pcluster コマンドをインストールする(参考記事
      • Compute Fleet の停止コマンド:pcluster update-compute-fleet --status STOP_REQUESTED --cluster-name <クラスタ名>
        • 注意:「クラスタ名」は pcluster list-clusters で調べることができます。なお、クラスタ名は本記事に沿ってセットアップする際の PCLUSTER_NAME とは必ずしも一致しないのでご注意ください。
      • Compute Fleet の開始コマンド:pcluster update-compute-fleet --status START_REQUESTED --cluster-name <クラスタ名>
  1. CloudFormation を使用して、S3のバケットを作成してください。以下の CloudFormation テンプレートファイル s3.yaml を保存した上で、以下の「バケット名を適当に決定するコマンド」を実施後、以下の「CloudFormationコマンド」を実行してください。

    s3.yaml
    AWSTemplateFormatVersion: "2010-09-09"
    Description: "CloudFormation template to create an S3 bucket with customizable name"
    
    Parameters:
      BucketName:
        Type: String
        Description: "Name of the S3 bucket to be created"
    
    Resources:
      S3Bucket:
        Type: "AWS::S3::Bucket"
        DeletionPolicy: Delete
        Properties:
          BucketName: !Ref BucketName
          AccessControl: Private
          BucketEncryption:
            ServerSideEncryptionConfiguration:
              - ServerSideEncryptionByDefault:
                  SSEAlgorithm: AES256
    
    Outputs:
      BucketName:
        Description: "Name of the newly created S3 bucket"
        Value: !Ref S3Bucket
      BucketARN:
        Description: "ARN of the newly created S3 bucket"
        Value: !GetAtt S3Bucket.Arn
    
    • バケット名を適当に決定するコマンド(注意: ランダム性により結果は毎回変わります)

      # 作成するバケットの名前を定義(注意:バケット名は全世界で一意である必要があるため、被らないようにランダム文字列を添加しています)
      timestamp=$(date +%s)
      random_string=$(openssl rand -hex 3)
      export BUCKET_NAME=trn-drill-bucket-${timestamp}-${random_string}
      
    • CloudFormationコマンド

      aws cloudformation deploy \
          --region ${REGION} \
          --capabilities CAPABILITY_IAM \
          --template-file s3.yaml \
          --stack-name ${BUCKET_NAME} \
          --parameter-overrides \
              BucketName=${BUCKET_NAME}
      
  2. キーペアの準備

    • ヘッドノードにssh接続するためのキーペアを作成してください(すでに作成済みの場合は流用も可能です)。ただし以下に注意してください:
      • Ubuntu22.04以降では、RSA鍵(特に ssh-rsa 署名アルゴリズム)がデフォルトで無効になっています。そのため、ed25519 または ecdsa 形式の鍵を使用してください。
        • 以下のコマンドでed25519形式の鍵を作成できます:ssh-keygen -t ed25519 -C "your_email@example.com"
  3. CloudFormation を使用して、ParallelClusterを作成してください。以下の CloudFormation テンプレートファイル pcluster.yaml を保存した上で、以下の「環境変数設定コマンド1」「環境変数設定コマンド2」を実施後、以下の「CloudFormationコマンド」を実行してください。(注意: この CloudFormation コマンドは20-40分程度かかります。)

    pcluster.yaml
    AWSTemplateFormatVersion: "2010-09-09"
    Description: "CloudFormation template to create an Parallel Cluster"
    
    Parameters:
      KeyName:
        Type: String
        Description: "Name of the key pair"
    
      PublicSubnetId:
        Type: String
        Description: "ID of the VPC public subnet"
    
      PrivateSubnetId:
        Type: String
        Description: "ID of the VPC private subnet"
    
      Spot:
        Type: String
        Description: "Use Spot Instances if true, On-Demand if false"
        Default: "false"
        AllowedValues:
          - "true"
          - "false"
    
      NeuronVersion:
        Type: String
        Description: "Version of Neuron SDK"
        Default: v2.22.1
    
    Mappings:
      ParallelCluster:
        Constants:
          Version: 3.10.1
    
    Conditions:
      UseSpotInstances: !Equals
        - !Ref Spot
        - "true"
    
    Resources:
      PclusterClusterProvider:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: !Sub
            - https://${AWS::Region}-aws-parallelcluster.s3.${AWS::Region}.${AWS::URLSuffix}/parallelcluster/${Version}/templates/custom_resource/cluster.yaml
            - { Version: !FindInMap [ParallelCluster, Constants, Version] }
    
      PclusterCluster:
        Type: Custom::PclusterCluster
        Properties:
          ServiceToken: !GetAtt [PclusterClusterProvider, Outputs.ServiceToken]
          ClusterName: !Sub "c-${AWS::StackName}"
          ClusterConfiguration:
            Region: !Ref AWS::Region
            Image:
              Os: ubuntu2204
            HeadNode:
              InstanceType: c5.4xlarge
              Networking:
                SubnetId: !Ref PublicSubnetId
              Ssh:
                KeyName: !Ref KeyName
              LocalStorage:
                RootVolume:
                  Size: 1024
              CustomActions:
                OnNodeConfigured:
                  Script: !Sub s3://neuron-s3/pcluster/post-install-scripts/neuron-installation/${NeuronVersion}/u22/pt/install_neuron.sh
              Iam:
                S3Access:
                  - BucketName: neuron-s3
                    EnableWriteAccess: false
            Scheduling:
              Scheduler: slurm
              SlurmSettings:
                QueueUpdateStrategy: DRAIN
              SlurmQueues:
                - Name: compute1
                  CapacityType: !If
                    - UseSpotInstances
                    - SPOT
                    - ONDEMAND
                  ComputeSettings:
                    LocalStorage:
                      RootVolume:
                        Size: 1024
                      EphemeralVolume:
                        MountDir: /local_storage
                  ComputeResources:
                    - Efa:
                        Enabled: true
                      InstanceType: trn1.32xlarge
                      MaxCount: 8
                      MinCount: 0
                      Name: queue1-i1
                  Networking:
                    SubnetIds:
                      - !Ref PrivateSubnetId
                    PlacementGroup:
                      Enabled: true
                  CustomActions:
                    OnNodeConfigured:
                      Script: !Sub s3://neuron-s3/pcluster/post-install-scripts/neuron-installation/${NeuronVersion}/u22/pt/install_neuron.sh
                  Iam:
                    S3Access:
                      - BucketName: neuron-s3
                        EnableWriteAccess: false
            SharedStorage:
              - MountDir: /fsx
                Name: pclusterfsx
                StorageType: FsxLustre
                FsxLustreSettings:
                  DeploymentType: PERSISTENT_2
                  DataCompressionType: LZ4
                  StorageCapacity: 1200
                  PerUnitStorageThroughput: 125
    
    Outputs:
      HeadNodeIp:
        Description: The Public IP address of the HeadNode
        Value: !GetAtt [PclusterCluster, headNode.publicIpAddress]
    
    • 環境変数設定コマンド1

      # 作成するParallelClusterの名前を定義(注意:同一AWSアカウント・同一リージョン内で一意である必要があります)
      export PCLUSTER_NAME=trn-drill-pcluster
      
      # 準備したキーペア名
      export KEY_NAME=my-key-pair
      
    • 環境変数設定コマンド2(作成済のVPCから、サブネットIDを取得)

      export PUBLIC_SUBNET_ID=$(aws cloudformation describe-stacks \
          --region ${REGION} \
          --stack-name ${VPC_NAME} \
          --query "Stacks[0].Outputs[?OutputKey=='PublicSubnet1'].OutputValue" \
          --output text)
      export PRIVATE_SUBNET_ID=$(aws cloudformation describe-stacks \
          --region ${REGION} \
          --stack-name ${VPC_NAME} \
          --query "Stacks[0].Outputs[?OutputKey=='PrivateSubnet1'].OutputValue" \
          --output text)
      
    • CloudFormationコマンド

      • NeuronVersionについては、上記 pcluster.yaml 内のdefault定義に最新のものを記載するか、この後のCloudFormationコマンドでオーバーライドして最新のものを記載する必要があります(NeuronVersion=x.xx.x の部分)。Neuron ドキュメントの内容を確認してください。なお、2025.07.31 時点では最新バージョンは 2.25.0 です。
      aws cloudformation deploy \
          --region ${REGION} \
          --capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
          --template-file pcluster.yaml \
          --stack-name ${PCLUSTER_NAME} \
          --parameter-overrides \
              KeyName=${KEY_NAME} \
              PublicSubnetId=${PUBLIC_SUBNET_ID} \
              PrivateSubnetId=${PRIVATE_SUBNET_ID} \
              BucketName=${BUCKET_NAME} \
              NeuronVersion=2.25.0
      

    pcluster.yaml の中には以下のような情報が含まれています

    • ヘッドノードのインスタンスタイプ・起動時スクリプト
    • コンピュートノードのインスタンスタイプ・起動台数の最小値/最大値・起動時処理
    • ストレージの容量
  4. 作成した ParallelCluster 内の Fsx(ファイルシステム)を、作成済みの S3 バケットに関連付けてください。
    以下のコマンドを実行してください。

    fsx_id=$(aws cloudformation describe-stacks \
        --region ${REGION} \
        --stack-name c-${PCLUSTER_NAME} \
        --query "Stacks[0].Outputs[?OutputKey=='FSXIds'].OutputValue" \
        --output text)
    aws fsx create-data-repository-association \
        --region ${REGION} \
        --file-system-id ${fsx_id} \
        --file-system-path / \
        --data-repository-path s3://${BUCKET_NAME} \
        --s3 "AutoImportPolicy={Events=[NEW,CHANGED,DELETED]},AutoExportPolicy={Events=[NEW,CHANGED,DELETED]}" \
        --batch-import-meta-data-on-create
    
  5. 今後、この ParallelCluster を CloudShell 経由でメンテナンスする時に備え、以下を実行して、ファイル .env に環境変数を書き出しておいてください。この .env ファイルは、CloudShell 上だけでなくローカルにもコピーを保管しておいてください。

    env | grep -E '^(REGION|AZ1|AZ2|VPC_NAME|BUCKET_NAME|PCLUSTER_NAME|KEY_NAME|PUBLIC_SUBNET_ID|PRIVATE_SUBNET_ID)=' > .env
    
    • 後日 CloudShell で作業するときは、最初に source .env を実行することで、環境変数一式がセットされ、上述の aws cloudformation deploy コマンドをそのまま使える状態になります。

    aws cloudformation コマンドでデプロイ(作成)したこれらのリソースは、後からaws cloudformation コマンドで修正することもできます。例えば以下のような修正が可能です。

    • コンピュートノードのインスタンスタイプの変更・追加
    • ストレージの容量追加
  • ⚠️ 本章で作成したリソース群は、以下のコマンドで削除できます:

    # ParallelCluster の削除
    aws cloudformation delete-stack --region ${REGION} --stack-name ${PCLUSTER_NAME}
    # VPC の削除
    aws cloudformation delete-stack --region ${REGION} --stack-name ${VPC_NAME}
    # S3 バケットを空にする(空にしてからでないと delete-stack で削除できない)
    aws s3 rm s3://${BUCKET_NAME} --recursive
    # S3 バケットの削除
    aws cloudformation delete-stack --region ${REGION} --stack-name ${BUCKET_NAME}
    
    • 注意: S3 のバケットは、空になっていない状態では delete-stack で削除できません(削除失敗の場合も、delete-stack 時にエラーメッセージは表示されないので注意してください)。
脚注
  1. 本50本ノックの内容を監修くださった AWS の常世様に、感謝を申し上げます。 ↩︎

KARAKURI Techblog

Discussion