AWS ParallelCluster Ubuntu 22.04 で Mountpoint for Amazon S3 を使ってヘッドノードとコンピュートノードに S3 バケットを自動マウントする方法

2024.04.30

AWS ParallelCluster を使った HPC クラスターの運用において、データの共有方法と保存コストは大きな課題です。本記事では Mountpoint for Amazon S3 を活用し、ヘッドノードとコンピュートに S3 バケットの自動マウントを実現する方法を紹介します。これにより、クラスター間でのデータ共有と、コスト効率の高いデータの長期保存が可能になります。

構成概要

本記事で紹介する構成の概要を以下の図に示します。ヘッドノードとコンピュートノードに S3 バケットがマウントされます。ヘッドノードでは systemd サービスによって自動マウントが行われ、コンピュートノードでは起動時に mount-s3 コマンドが実行されます。

本記事の目的と解決する課題

以前、AWS ParallelCluster の Ubuntu 22.04 に対応した Moutpoint for Amazon S3 の利用方法を紹介しました。クラスターの運用をする中でいくつかの課題が見えてきたためブラッシュアップしました。

本記事では、以下の 2 点を改善した Mountpoint for Amazon S3 の活用方法を紹介します。

  1. カスタムブートストラップスクリプトと systemd を使ってヘッドノードに S3 バケットを自動マウントする
  2. クラスターのコンフィグからマウント設定を引数で渡し、マウント用スクリプトの再利用性を高める

これにより、S3 バケットのマウント作業を自動化し、運用の手間を削減できます。また、マウント設定をクラスターコンフィグで一元管理できるため、スクリプトの管理コストを抑えます。

それでは、具体的な手順を見ていきましょう。

実装手順

クラスター構築に必要な要素は大きく分けて 3 つあります。

  1. カスタムブートストラップスクリプト
  2. IAM ポリシー
  3. クラスターのコンフィグ

それぞれについて詳しく見ていきましょう。

カスタムブートストラップスクリプトの作成

カスタムブートストラップスクリプトは、ヘッドノードとコンピュートノードの起動時に実行されるスクリプトです。今回は以下の 3 つのスクリプトを用意しました。

  1. 共通 Mountpoint for Amazon S3 インストールスクリプト
    • ヘッドノードとコンピュートノードの両方で実行され、Mountpoint for Amazon S3 をインストールします。
  2. コンピュートノード用 S3 バケットマウントスクリプト
    • コンピュートノードの起動時に実行され、mount-s3 コマンドを使って S3 バケットをマウントします。
    • マウントに必要な情報はクラスターのコンフィグから引数で渡します。
  3. ヘッドノード用 S3 バケットマウントスクリプト
    • ヘッドノードの初回起動時に実行され、systemd サービスを作成して S3 バケットを自動マウントします。
    • マウントに必要な情報はクラスターのコンフィグから引数で渡します。

共通 Mountpoint for Amazon S3 インストールスクリプト

ヘッドノード、コンピュートノードの初回起動時に Mountpoint for Amazon S3 をインストールします。

項目名
ファイル名 install.sh
保存先 任意の S3 バケット
#! /bin/bash

# Install mount-s3 command for Ubuntu 22.04
sudo apt-get update
sudo apt-get install libfuse2 -y

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

コンピュートノード用 S3 バケットマウントスクリプト

コンピュートノードの起動時にmount-s3コマンドを実行し S3 バケットをマウントします。 コンピュートノードは、ジョブの実行に合わせて動的に起動・終了するため、起動のたびに mount-s3 コマンドでマウントを行う設定としています。

項目名
ファイル名 mount.sh
保存先 任意の S3 バケット
#! /bin/bash

BUCKET_NAME=$1
TARGET_DIRECTORY=$2
OPTIONS=$3

# Allow other users to access mount
# Needed if --allow-root or --allow-other option is set
if ! grep -q "^user_allow_other" /etc/fuse.conf
then
    echo "user_allow_other" | sudo tee -a /etc/fuse.conf
fi

sudo mkdir -p ${TARGET_DIRECTORY}
sudo chmod 777 ${TARGET_DIRECTORY}
sudo mount-s3 ${OPTIONS} ${BUCKET_NAME} ${TARGET_DIRECTORY}

ヘッドノードノード用 S3 バケットマウントスクリプト

ヘッドノードノードの初回起動時に systemd で Moutpoint 用のサービスを作成します。以降はサービスの起動により S3 バケットを自動マウントします。コンピュートノードのスクリプトと同様にマウント対象の S3 バケットや、マウントパスはクラスターのコンフィグから引数で渡します。

項目名
ファイル名 mount-headnode.sh
保存先 任意の S3 バケット
#! /bin/bash

BUCKET_NAME=$1
TARGET_DIRECTORY=$2
OPTIONS=$3

# Generate a distinct identifier to allow multiple mountpoint-s3 services
SERVICE_ID=$(echo -n "${BUCKET_NAME}:${TARGET_DIRECTORY}" | md5sum | awk '{print $1}')
SERVICE_ID=${SERVICE_ID:0:8}
SERVICE_NAME="mountpoint-s3-${SERVICE_ID}"

# Allow other users to access mount
# Needed if --allow-root or --allow-other option is set
if ! grep -q "^user_allow_other" /etc/fuse.conf
then
    echo "user_allow_other" | sudo tee -a /etc/fuse.conf
fi

# Create mount TARGET_DIRECTORY
sudo mkdir -p ${TARGET_DIRECTORY}
sudo chmod 777 ${TARGET_DIRECTORY}

# Create service file
tee > "${SERVICE_NAME}.service" <<EOF
[Unit]
Description=Mount s3://${BUCKET_NAME} at ${TARGET_DIRECTORY}
Wants=network-online.target
After=default.target
AssertPathIsTARGET_DIRECTORY=${TARGET_DIRECTORY}

[Service]
Type=forking
User=ubuntu
Group=ubuntu
ExecStart=/usr/bin/mount-s3 ${OPTIONS} ${BUCKET_NAME} ${TARGET_DIRECTORY}
ExecStop=/usr/bin/fusermount -u ${TARGET_DIRECTORY}

[Install]
WantedBy=default.target
EOF

# Install and start the service
sudo mv "${SERVICE_NAME}.service" /etc/systemd/system/

sudo systemctl daemon-reload
sudo systemctl enable "${SERVICE_NAME}"
sudo systemctl start "${SERVICE_NAME}"

IAM ポリシーの作成

S3 バケットをマウントするには、ヘッドノードとコンピュートノードにアクセス権限を付与する必要があります。今回は以下の IAM ポリシーを作成し、ヘッドノードとコンピュートノードの IAM ロールにアタッチします。

マウントした S3 バケット用にアクセスするための権限

マウント対象となる S3 バケットに対してヘッドノード、コンピュートノードからアクセスするために必要な権限を付与します。ヘッドノード、コンピュートノードからマウントした S3 バケットに対してファイルの読み書きができるように s3:DeleteObject の権限を持たせています。

項目名
ポリシー名 hpc-dev-AllowMountpointForS3
アタッチ先 ヘッドノード、コンピュートノードの IAM ロール(クラスターのコンフィグで指定)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::hpc-dev-mountpoint-sample-1",
                "arn:aws:s3:::hpc-dev-mountpoint-sample-2"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:AbortMultipartUpload",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::hpc-dev-mountpoint-sample-1/*",
                "arn:aws:s3:::hpc-dev-mountpoint-sample-2/*"
            ],
            "Effect": "Allow"
        }
    ]
}

以下のブログで、S3 バケットを作成と同時に上記の IAM ポリシーを作成する CloudFormation テンプレートを紹介しています。

クラスターのサンプルコンフィグ

クラスターのコンフィグを紹介します。ここではヘッドノードとコンピュートノードの設定を中心に解説します。

コンフィグファイル全文

先にコンフィグファイル全文を掲載します。

Region: ap-northeast-1
Image:
  Os: ubuntu2204
Tags:
  - Key: Name
    Value: mountS3-v391
# ----------------------------------------------------------------
# Head Node Settings
# ----------------------------------------------------------------
HeadNode:
  InstanceType: m7i-flex.large
  Networking:
    ElasticIp: false
    SubnetId: subnet-0c82bb28e119e2aa8
  Ssh:
    KeyName: org-sandbox-keypair
  LocalStorage:
    RootVolume:
      Size: 40
      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-custom-boostrap-files
        EnableWriteAccess: false
  CustomActions:
    OnNodeConfigured:
      Sequence:
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/install.sh
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount-for-headnode.sh
          Args:
            - hpc-dev-mountpoint-sample-1
            - /mnt/s3-readonly
            - "--allow-delete --allow-other"
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount-for-headnode.sh
          Args:
            - hpc-dev-mountpoint-sample-2
            - /mnt/s3
            - "--allow-delete --allow-other"
# ----------------------------------------------------------------
# Compute Node Settings
# ----------------------------------------------------------------
Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 5
  SlurmQueues:
    # ------ Compute 1 ------
    - Name: p1
      ComputeResources:
        - Name: m6idmetal
          Instances:
            - InstanceType: m6id.metal
          MinCount: 0
          MaxCount: 30
          DisableSimultaneousMultithreading: true
      ComputeSettings:
        LocalStorage:
          RootVolume:
            Size: 40
            Encrypted: true
            VolumeType: gp3
            Iops: 3000
            Throughput: 125
      CapacityType: SPOT
      AllocationStrategy: capacity-optimized
      Networking:
        SubnetIds:
          - subnet-0c82bb28e119e2aa8
          - subnet-0296a0c8515ed3bdc
          - subnet-0089ff187d1f54258
        PlacementGroup:
          Enabled: false
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3
        S3Access:
          - BucketName: hpc-custom-boostrap-files
            EnableWriteAccess: false
      CustomActions:
        OnNodeConfigured:
          Sequence:
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/install.sh
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount.sh
              Args:
                - hpc-dev-mountpoint-sample-1
                - /mnt/s3-readonly
                - "--read-only --allow-other"
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount.sh
              Args:
                - hpc-dev-mountpoint-sample-2
                - /mnt/s3
                - "--allow-delete --allow-other"
# ----------------------------------------------------------------
# Shared Storage Settings
# ----------------------------------------------------------------
SharedStorage:
  - MountDir: /mnt/efs-elastic
    Name: efs1
    StorageType: Efs
    EfsSettings:
      FileSystemId: fs-0846dc947572a66a1
  - MountDir: /mnt/efs-bursting
    Name: efs2
    StorageType: Efs
    EfsSettings:
      FileSystemId: fs-046b02d3ba107c2b2

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

ヘッドノードの設定解説

AdditionalIamPolicies:セクションで、マウントした S3 バケットへの必要なアクセス権限を付与した IAM ポリシーを指定します。 また、カスタムブートストラップスクリプトが保存されている S3 バケットへの権限が必要なため、S3Access:セクションでスクリプト保存先の S3 バケットへ対して読み取り権限を付与しています。

  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3
    S3Access:
      - BucketName: hpc-custom-boostrap-files
        EnableWriteAccess: false

CustomActions:セクションでは、ヘッドノードの起動時に実行するカスタムブートストラップスクリプトを指定します。

まず、install.shスクリプトで Mountpoint for Amazon S3 をインストールします。

次に、mount-for-headnode.shスクリプトを 2 回呼び出し、異なる S3 バケットを異なるマウントポイントにマウントしています。このスクリプトは、systemd サービスを作成し、ヘッドノードの起動時に自動的に S3 バケットをマウントします。

スクリプトの引数には、以下の 3 つを指定しています。

  1. マウント対象の S3 バケット名
  2. マウントするディレクトリのパス
  3. mount-s3コマンドのオプション指定

これにより、S3 バケット hpc-dev-mountpoint-sample-1/mnt/s3-readonly にマウントし、hpc-dev-mountpoint-sample-2/mnt/s3 に同じスクリプトを利用してマウントを実現します。マウントオプションで --allow-delete--allow-other を指定し、他のユーザーからのアクセスを許可しつつ、ファイルの削除を可能にしています。/mnt/s3-readonlyという名前なのに削除を許可している理由は、コンピュートノードとマウントするディレクトリ名を統一しているためです。ヘッドノードからは読み書きできた方が便利だったため、書き込めるようにしています。

  CustomActions:
    OnNodeConfigured:
      Sequence:
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/install.sh
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount-for-headnode.sh
          Args:
            - hpc-dev-mountpoint-sample-1
            - /mnt/s3-readonly
            - "--allow-delete --allow-other"
        - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount-for-headnode.sh
          Args:
            - hpc-dev-mountpoint-sample-2
            - /mnt/s3
            - "--allow-delete --allow-other"

コンピュートノードの設定解説

コンピュートノードの設定は、ヘッドノードと同様にIam:セクションで IAM ポリシーと S3 バケットへのアクセス権を付与しています。

      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::123456789012:policy/hpc-dev-AllowMountpointForS3
        S3Access:
          - BucketName: hpc-custom-boostrap-files
            EnableWriteAccess: false

CustomActions:セクションでは、コンピュートノードの起動時に実行するカスタムブートストラップスクリプトを指定します。

まず、install.sh スクリプトで Mountpoint for Amazon S3 をインストールします。

次に、mount.sh スクリプトを 2 回呼び出し、異なる S3 バケットを異なるマウントポイントにマウントしています。このスクリプトは、mount-s3 コマンドを使って S3 バケットをマウントします。

スクリプトの引数には、以下の 3 つを指定しています。

  1. マウント対象の S3 バケット名
  2. マウントするディレクトリのパス
  3. mount-s3コマンドのオプション指定

hpc-dev-mountpoint-sample-1 のマウントオプションでは、--read-only を指定し、読み取り専用でマウントしています。一方、hpc-dev-mountpoint-sample-2 では、--allow-delete を指定し、ファイルの削除を可能にしています。どちらのマウントポイントでも--allow-other オプションを指定し、他のユーザーからのアクセスを許可しています。

      CustomActions:
        OnNodeConfigured:
          Sequence:
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/install.sh
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount.sh
              Args:
                - hpc-dev-mountpoint-sample-1
                - /mnt/s3-readonly
                - "--read-only --allow-other"
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount.sh
              Args:
                - hpc-dev-mountpoint-sample-2
                - /mnt/s3
                - "--allow-delete --allow-other"

動作検証

前述のサンプルコンフィグより構築したクラスターで Mountpoint for Amazon S3 が正常に動作することを確認します。ヘッドノードとコンピュートノードそれぞれで、S3 バケットがマウントされていることを検証します。

ヘッドノードのマウント状況確認

ヘッドノードにログインし、以下のコマンドを実行して Mountpoint for Amazon S3 のサービスが正常に起動していることを確認します。

$ systemctl list-units | grep mountpoint-s3
  mountpoint-s3-585e79a6.service                                                                loaded active     running   Mount s3://hpc-dev-mountpoint-sample-2 at /mnt/s3
  mountpoint-s3-91ef1212.service                                                                loaded active     running   Mount s3://hpc-dev-mountpoint-sample-1 at /mnt/s3-readonly

以下のコマンドの出力から、2 つの S3 バケットが指定したディレクトリにマウントされていることが確認できます。

$ ls /mnt/s3
YouCanLookThisFileFromS3.txt

$ ls /mnt/s3-readonly/
YouCanLookThisFileFromS3.txt  images  reads

ヘッドノードの EC2 インスタンスを停止し、再度開始した場合でも、systemd サービスによって S3 バケットが自動的にマウントされることを確認します。

以下は、インスタンス開始後のサービスの状態とマウント状況です。

$ systemctl list-units | grep mountpoint-s3
  mountpoint-s3-585e79a6.service                                                                loaded active     running   Mount s3://hpc-dev-mountpoint-sample-2 at /mnt/s3
  mountpoint-s3-91ef1212.service                                                                loaded active     running   Mount s3://hpc-dev-mountpoint-sample-1 at /mnt/s3-readonly

systemd サービスが自動的に起動し、S3 バケットがマウントされていることがわかります。

$ mount | grep mountpoint-s3
mountpoint-s3 on /mnt/s3-readonly type fuse (rw,nosuid,nodev,noatime,user_id=1000,group_id=1000,default_permissions,allow_other)
mountpoint-s3 on /mnt/s3 type fuse (rw,nosuid,nodev,noatime,user_id=1000,group_id=1000,default_permissions,allow_other)

コンピュートノードのマウント状況確認

コンピュートノードで S3 バケットがマウントされていることを確認するために、適当なテストジョブをサブミットしコンピュートノードを起動させます。

起動してきたコンピュートノードにログインし、以下のコマンドの出力から 2 つの S3 バケットが指定したディレクトリにマウントされていることが確認できます。

$ ls /mnt/s3
YouCanLookThisFileFromS3.txt

$ ls /mnt/s3-readonly/
YouCanLookThisFileFromS3.txt  images  reads

/mnt/s3-readonlyは read-only オプションが指定されており、読み取り専用(ro)でマウントされています。一方、/mnt/s3では allow-delete オプションが指定されており、ファイルの読み書き(rw)が可能になっています。

$ mount | grep mountpoint-s3
mountpoint-s3 on /mnt/s3-readonly type fuse (ro,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other)
mountpoint-s3 on /mnt/s3 type fuse (rw,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other)

まとめ

本記事では、AWS ParallelCluster の Ubuntu 22.04 環境で Mountpoint for Amazon S3 を活用し、ヘッドノードとコンピュートノードに S3 バケットを自動マウントする方法を紹介しました。カスタムブートストラップスクリプトと systemd を使うことで、クラスター起動時に S3 バケットを自動的にマウントできます。また、クラスターのコンフィグでマウント設定を一元管理することで、マウントスクリプトの管理コストを削減できます。

おわりに

Mountpoint for Amazon S3 を活用することで、AWS ParallelCluster でのデータ共有と永続化が容易になります。今後は、ゲノム解析のワークロードで Mountpoint for Amazon S3 を活用し、利便性と効率性を高める検証を進めていきます。