AWS ParallelCluster に Mountpoint for Amazon S3 を使って S3 バケットをマウントする方法

使い方によってはFSx for LustreなしにS3バケットへのアクセスが容易なクラスターを利用できるようになりました。
2023.08.22

AWS ParallelCluster に Mountpoint for Amazon S3 を利用して、S3 バケットをマウントしたクラスター環境を構築手順を紹介します。

ヘッドノード、コンピュートノードから直接 S3 バケットのデータを取得できます。大容量のデータを読み取ることの多い機械学習、ゲノム解析(リファレンスゲノムなど)のワークロードで ParallelCluster を利用する場合は本構成もご検討ください。

Inventory icons created by Freepik - Flaticon

S3 バケットに保存してあるファイルをパス指定(例: /mnt/s3)で直接ファイルアクセスできるようになった点が大きな変更点です。

Mountpoint for Amazon S3 でマウントした S3 バケットに対しての書き込み処理は注意が必要です。多くのケースは図の様に EBS や、EFS などのブロックストレージに一度書き出すことになります。最終的なデータ保存先として S3 へコピーや、移動するときの書き込み処理はあまり心配ありません。

2023/10/8追記
Ubuntu 22.04 を利用する場合は以下のブログもご参照ください。

設定の流れ

事前準備作業が地味に多いです。S3 バケットと IAM ポリシー、マウントスクリプトは一度作成すれば、他クラスター間で使いまわしできます。用途別に S3 バケットを分けたい場合は同じ手順を踏む必要はあります。

  1. マウント用の S3 バケット、IAM ポリシーを事前に作成する
  2. カスタムブートストラップアクションで実行する S3 マウントスクリプトを作成し、S3 に保存
  3. クラスターのコンフィグに IAM ポリシーの付与と、カスタムブートストラップアクション設定を追加
  4. クラスターをデプロイ(pclsuter create-clusterの実行)
  5. ヘッドノードに手動で S3 自動マウント用の設定追加

検証環境

OS は Ubuntu 20.04 LTS の AWS ParallelCluster 3.6.1 環境で検証しています。mount-s3 コマンドのバージョンは1.0.0です。

S3 をマウントするための準備

ParallelCluster に S3 バケットをマウントするために以下のリソースを事前に作成します。

  1. マウント対象となる S3 バケット
  2. ヘッドノード、コンピュートノードに必要な IAM ポリシー

CloudFormation テンプレート

必要なリソースは以下の CloudFormation テンプレートから作成できます。

mountpoint-for-s3.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: S3 Bucket and IAM Policy for Mountpoint for S3

Parameters:
  ProjectName:
    Description: Project Name
    Type: String
    Default: unnamed
  Environment:
    Description: Environment
    Type: String
    Default: dev
    AllowedValues:
      - prod
      - dev
  S3BucketName:
    Description: Bucket name
    Type: String

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Common Settings
        Parameters:
          - ProjectName
          - Environment

Resources:
  # ------------------------------------------------------------------------------------ #
  # S3
  # ------------------------------------------------------------------------------------ #
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}
      OwnershipControls:
        Rules:
          - ObjectOwnership: "BucketOwnerEnforced"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: "AES256"
            BucketKeyEnabled: false
      LifecycleConfiguration:
        Rules:
          - Id: AbortIncompleteMultipartUpload
            AbortIncompleteMultipartUpload:
              DaysAfterInitiation: 7
            Status: "Enabled"
          - Id: NoncurrentVersionExpiration
            NoncurrentVersionExpiration:
              NoncurrentDays: 14
            Status: Enabled
          - Id: IntelligentTiering
            Transitions:
              - TransitionInDays: 7
                StorageClass: INTELLIGENT_TIERING
            Status: Enabled

  # ------------------------------------------------------------------------------------ #
  # IAM Policy
  # ------------------------------------------------------------------------------------ #
  S3AccessPolicy:
    Type: "AWS::IAM::ManagedPolicy"
    Properties:
      ManagedPolicyName: !Sub ${ProjectName}-${Environment}-AllowMountpointForS3
      Path: "/"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action:
              - "s3:ListBucket"
            Resource:
              - !Sub arn:aws:s3:::${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}
          - Effect: "Allow"
            Action:
              - "s3:GetObject"
              - "s3:PutObject"
              - "s3:AbortMultipartUpload"
              - "s3:DeleteObject"
            Resource:
              - !Sub arn:aws:s3:::${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}/*

Outputs:
  ExportIAMPolicy:
    Value: !Ref "S3AccessPolicy"
    Export:
      Name: !Sub "${AWS::StackName}-S3AccessPolicy"
  ExportS3Bucket:
    Value: !Ref "S3Bucket"
    Export:
      Name: !Sub "${AWS::StackName}-S3BucketARN"

パラメータ入力

任意の名前を入力してください。

参考までに上記のパラメータで生成したときのリソース名は以下になります。

S3 バケットの設定内容の説明

暗号化、バージョニング有効化などの基本的な設定に加えて HPC ワークロードを考慮して以下の設定を追加しています。

S3 バケット名はユニークな名前にするために AWS アカウント ID を末尾に自動的に付与しています。命名規則はお好みで変更してください。

抜粋

  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}

IAM ポリシーの設定内容の説明

CloudFormation で作成したマウント対象の S3 バケットへのみ最低限必要な権限をもたせる IAM ポリシーが CloudFormation テンプレートから作成されます。ParallelCluster からマウントした S3 バケットに対してファイルの読み書きができるようにs3:DeleteObjectの権限を持たせています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::[CloudFromation で作成した S3 バケット名が自動入力されています]"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:AbortMultipartUpload",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::[CloudFormation で作成した S3 バケット名が自動入力されています]/*"
            ],
            "Effect": "Allow"
        }
    ]
}

カスタムブートストラップアクションの準備

コンピュートノード起動時に S3 バケットをマウントするスクリプト作成し、カスタムブートストラップ用の S3 バケットに保存します。ここでは S3 バケットをマウントするのに必要なスクリプトを紹介します。

  1. mount-s3.debパッケージをダウンロードしてインストール
  2. S3 バケットのマウント先のパスを/mnt/s3ディレクトリを作成
  3. mount-s3コマンドで/mnt/s3へ S3 バケットをマウント

CloudFormation で作成した S3 バケット名に置き換えてスクリプトをご利用ください。

mount.sh

#! /bin/bash

wget -P /tmp https://s3.amazonaws.com/mountpoint-s3-release/latest/x86_64/mount-s3.deb
sudo apt-get install /tmp/mount-s3.deb -y
sudo mkdir /mnt/s3
sudo mount-s3 --allow-delete --allow-other [要手動入力: CloudFormation で作成した S3バケット名] /mnt/s3/

カスタムブートストラップ用の S3 バケットの作成は省略します。適当な S3 バケットを作成してスクリプトを保存してください。

クラスターコンフィグ作成

S3 バケットをマウントするのに必要な追加設定について説明します。

マウントする S3 バケットへのアクセス権追加

ヘッドノードと、キュー毎のコンピュートノードに IAM ポリシーを追加します。IAM ポリシー名は CloudFormation テンプレートで作成されています。リソース名を確認し ARN を入力してください。

個々の環境によってアカウント ID、CloudFormation に入力したパラメータの値によって IAM ポリシー名が異なります。ご自身の環境に合わせて修正してください。

# ヘッドノード
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3

--- 略 ---
# コンピュートノード(キューの数分だけ設定が必要)
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3

コンピュートノード起動時に S3 バケットをマウントするスクリプト実行

カスタムブートストラップ用の S3 バケットに保存したスクリプトのパスを入力します。

個々の環境によってスクリプト保存先の S3 バケット名、パス、スクリプト名が異なります。ご自身の環境に合わせて修正してください。

# コンピュートノード(キューの数分だけ設定が必要)
     CustomActions:
        OnNodeConfigured:
          Script: s3://hpc-dev-postinstall-files/mount-moutpoint-for-s3/mount.sh

ヘッドノードへのカスタムブートストラップによるマウント設定は不要です。ヘッドノードの設定を自動化する上手い方法が思いつかなかったため、ヘッドノード起動後にログインして手動でマウント設定します。

既存の実行スクリプトが指定されている場合

ParallelCluster 3.6.0 のアップデートで、複数のスクリプトを列挙して実行できるようになりました。v3.6.0 以降であれば、既存のスクリプトがある場合はSequence:を追加し実行スクリプトを列挙すれば既存のスクリプトをいじることなく新たな処理を追加できます。

        OnNodeConfigured:
          # Script URLs. The scripts are run in the same order as listed in the configuration, after all the bootstrap scripts are run
          Sequence:
            - Script1: s3://bucket-name/on-node-configured1.sh
              Args:
                - arg1
            - Script2: s3://bucket-name/on-node-configured2.sh
              Args:
                - arg1

Custom bootstrap actions - AWS ParallelCluster

カスタムブートストラップ用の S3 バケットへのアクセス権追加

カスタムブートストラップ用の S3 バケットに保存したスクリプトにアクセスできる権限が別途必要になります。

# コンピュートノード(キューの数分だけ設定が必要)
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false

コンフィグ全文

検証用のクラスターを構築したコンフィグです。設定内容の参考にご覧ください。

sample.yaml

Region: ap-northeast-1
Image:
  Os: ubuntu2004
Tags:
  - Key: Name
    Value: MountS3Cluster
# ----------------------------------------------------------------
# Head Node Settings
# ----------------------------------------------------------------
HeadNode:
  InstanceType: t3.micro
  Networking:
    ElasticIp: false
    SubnetId: subnet-035be95eeaa091603
  Ssh:
    KeyName: sandbox-key
  LocalStorage:
    RootVolume:
      Size: 35
      Encrypted: true
      VolumeType: gp3
      Iops: 3000
      Throughput: 125
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3
    S3Access:
      - BucketName: hpc-dev-postinstall-files
        EnableWriteAccess: false
# ----------------------------------------------------------------
# Compute Node Settings
# ----------------------------------------------------------------
Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 5
  SlurmQueues:
    # ------ Compute 1 ------
    - Name: queue1
      ComputeResources:
        - Name: queue1
          Instances:
            - InstanceType: c6i.large
            - InstanceType: m6i.large
          MinCount: 0
          MaxCount: 10
          DisableSimultaneousMultithreading: true
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 35
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      AllocationStrategy: lowest-price
      Networking:
        SubnetIds:
          - subnet-035be95eeaa091603
        PlacementGroup:
          Enabled: false
      CustomActions:
        OnNodeConfigured:
          Script: s3://hpc-dev-postinstall-files/mount-moutpoint-for-s3/mount.sh
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3
        S3Access:
          - BucketName: hpc-dev-postinstall-files
            EnableWriteAccess: false

# ----------------------------------------------------------------
# Shared Storage Settings
# ----------------------------------------------------------------
SharedStorage:
  - MountDir: /mnt/efs-1zone
    Name: efs-1zone
    StorageType: Efs
    EfsSettings:
      FileSystemId: fs-0f1158ade79354809

# ----------------------------------------------------------------
#  Other Settings
# ----------------------------------------------------------------
Monitoring:
  Logs:
    CloudWatch:
      Enabled: true
      RetentionInDays: 180
      DeletionPolicy: "Delete"
  Dashboards:
    CloudWatch:
      Enabled: false

クラスターデプロイ後の設定

pcluster create-clusterコマンドでクラスターをデプロイ後に必要な設定です。

ヘッドノードに S3 バケットを自動マウント設定追加

コンピュートノードはカスタムブートストラップアクションにより、コンピュートノードが起動時にマウント処理が走ります。ヘッドノードは手動で自動マウント設定を入れます。

マウント先のディレクトリを作成します。

sudo mkdir /mnt/s3

S3 バケットは専用のmount-s3コマンドでマウントするのですが fstab のマウント処理はサポートしていません。そのため、ヘッドノード起動時になにかしらの方法でmount-s3コマンドを実行する必要があります。

crontab を利用して起動時に任意のコマンドを一度実行する例です。一行書き加えれば良いだけで手軽なので今ところ私は採用しています。

crontab language=-e

@reboot sudo mount-s3 --allow-delete --allow-other [要手動入力: CloudFormation で作成した S3バケット名] /mnt/s3

以上でクラスターの設定は完了です。

まとめ

カスタムブートストラップアクションで S3 をマウントするスクリプトを実行することが肝です。そのための事前準備が多少必要でした。

  1. マウント用の S3 バケット、IAM ポリシーを事前に作成する
  2. カスタムブートストラップアクションで実行する S3 マウントスクリプトを作成し、S3 に保存
  3. クラスターのコンフィグに IAM ポリシーの付与と、カスタムブートストラップアクション設定を追加
  4. クラスターをデプロイ(pclsuter create-clusterの実行)
  5. ヘッドノードに手動で S3 自動マウント用の設定追加

おわりに

ParallelCluster の設定手順のみの紹介となりました。アプリケーションの動作検証など時間あるときに試して結果を共有したいと思います。 なにがともあれ、クラスターに S3 バケットを直接マウントできることでファイルの読み込みに関しては大きく運用フローを改善できそうな大きなアップデートでした。