AWS ParallelCluster カスタムブートストラップスクリプトでクラスターコンフィグから引数を受け取るスクリプトを試してみた

便利な使い方を今更知ったのでまとめました。
2024.04.06

AWS ParallelCluster では、クラスターのコンフィグファイルからカスタムブートストラップスクリプトに引数を渡すことができます。要はクラスター毎に使い回し可能なスクリプトととなる可能性を秘めています。

本記事では、Mountpoint for Amazon S3 を ParallelCluster に組み込む処理を例に、この機能を検証した結果を共有します。

# 例
      CustomActions:
        OnNodeConfigured:
          Sequence:
            - Script: s3://example-bucket/mount.sh # 汎用的に使いわせるようにスクリプトを用意
              Args:
                - hoge # 引数をクラスターのコンフィグから渡したい

AWS ParallelCluster + Mountpoint 構成

AWS HPC レシピのサンプルコードを確認したところ、Mountpoint for Amazon S3 のカスタムブートストラップスクリプトが紹介されていました。 汎用的に使い回せる書き方をされており良かったので、実装を方法をよりシンプルにアレンジして試してみました。

ParallelCluster で Mountpoint for Amazon S3 を利用する構成は過去に私も紹介しています。CloudFromation で必要な IAM ポリシーを生成できて便利ですので、詳しい設定方法は以下のブログをご覧ください。

カスタムブートストラップスクリプトの書き方

必要なパッケージをインストールするスクリプトと、S3 バケットをマウントするスクリプトの 2 つを作成し、任意の S3 バケットに保存します。

インストールスクリプト

Mountpoint for Amazon S3 のコマンドであるmount-s3をインストールするスクリプト(install.sh)を作成しました。

#! /bin/bash

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

Ubuntu 22.04 の場合はlibfuse2を追加インストールする必要があります。詳細は以下の記事をご覧ください。

マウントスクリプト

S3 バケット名、マウントするディレクトリ、mount-s3コマンドのオプションを引数として受け取り、実行するスクリプト(mount.sh)です。書き方は一般的な Bash スクリプトと同じでした。

#! /bin/bash

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

echo "#--- Start of Mount Process ---#"
echo ${BUCKET_NAME}
echo ${TARGET_DIRECTORY}
echo ${OPTIONS}

sudo mkdir -p ${TARGET_DIRECTORY}
sudo mount-s3 ${OPTIONS} ${BUCKET_NAME} ${TARGET_DIRECTORY}
echo "#--- End of Mount Process---#"

クラスターコンフィグの書き方

設定箇所にコメントを書きました。OnNodeConfigured:セクションが本検証のポイントです。

      CustomActions:
        OnNodeConfigured:
          Sequence: # スクリプトを複数個実行する場合は Sequence: セクション配下に指定が必要
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/install.sh # 作成したインストールスクリプトの保存パス
            - Script: s3://hpc-custom-boostrap-files/mountpoint-for-ubuntu22/mount.sh # 作成したマウントスクリプトの保存パス
              Args: # 作成したスクリプトに合わせて引数 3 つ渡す
                 - hpc-dev-mountpoint-sample-1 # マウントするS3バケット名
                - /mnt/s3/sample-1 # マウントポイントのディレクトリパス
                - "--allow-delete --allow-other --debug" # mount-s3コマンドのオプション
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::0123456789012:policy/hpc-dev-AllowMountpointForS3 #  Mountpoint for Amazon S3 用の権限必須
        S3Access:
          - BucketName: hpc-custom-boostrap-files # カスタムブートストラップスクリプトを保存してある S3 バケットへのアクセス権を付与
            EnableWriteAccess: false

クラスターコンフィグ全文

今回の検証に使用したクラスターのコンフィグは以下になります。こちらのコンフィグから ParallelCluster 3.9 のクラスター環境を構築しました。

Region: ap-northeast-1
Image:
  Os: ubuntu2204
Tags:
  - Key: Name
    Value: TokoroScalpo390
# ----------------------------------------------------------------
# Head Node Settings
# ----------------------------------------------------------------
HeadNode:
  InstanceType: t3.micro
  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::012345679012:policy/hpc-dev-AllowMountpointForS3
    S3Access:
      - BucketName: hpc-custom-boostrap-files
        EnableWriteAccess: false
# ----------------------------------------------------------------
# Compute Node Settings
# ----------------------------------------------------------------
Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 5
  SlurmQueues:
    # ------ Test 1 ------
    - Name: test1
      ComputeResources:
        - Name: test1
          Instances:
            - InstanceType: t3.micro
            - InstanceType: t3a.micro
          MinCount: 0
          MaxCount: 20
          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
        S3Access:
          - BucketName: hpc-custom-boostrap-files
            EnableWriteAccess: false
    # ------ Compute 1 ------
    - Name: queue1
      ComputeResources:
        - Name: queue1
          Instances:
            - InstanceType: m7i.2xlarge
            - InstanceType: m7a.xlarge
          MinCount: 0
          MaxCount: 10
          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
      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/sample-1
                - "--allow-delete --allow-other --debug"
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
          - Policy: arn:aws:iam::012345679012:policy/hpc-dev-AllowMountpointForS3
        S3Access:
          - BucketName: hpc-custom-boostrap-files
            EnableWriteAccess: false

# ----------------------------------------------------------------
# Shared Storage Settings
# ----------------------------------------------------------------
SharedStorage:
  - MountDir: /mnt/hpc-dev-efs-for-parallelcluster
    Name: efs1
    StorageType: Efs
    EfsSettings:
      FileSystemId: fs-0846dc947572a66a1

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

S3 バケットがマウントされるか動作確認

Mountpoint for Amazon S3 でコンピュートノードにマウントする S3 バケットには、テストファイルを保存してあります。コンピュートノードからこのファイルを確認できるか検証します。

コンピュートノードを起動

ジョブをサブミットしてコンピュートノードを起動させました。セッションマネージャで接続しマウント状況を確認します。

/mnt/s3配下にsample-1ディレクトリが作成されています。

ubuntu@queue1-dy-queue1-1:/mnt/s3$ ll
total 8
drwxr-xr-x 3 root root 4096 Apr  6 05:31 ./
drwxr-xr-x 4 root root 4096 Apr  6 05:31 ../
drwxr-xr-x 2 root root    0 Apr  6 05:31 sample-1/

sample-1ディレクトリを確認すると、S3 バケットに保存してあるテキストファイルを確認できました。

ubuntu@queue1-dy-queue1-1:/mnt/s3/sample-1$ ll
total 4
drwxr-xr-x 2 root root    0 Apr  6 05:31 ./
drwxr-xr-x 3 root root 4096 Apr  6 05:31 ../
-rw-r--r-- 1 root root    0 Apr  6 04:15 YouCanLookThisFileFromS3.txt

今回作成したカスタムブートストラップスクリプトにより正常に S3 バケットをコンピュートノードにマウントを確認できました。

トラブルシュート

カスタムブートストラップスクリプトを編集後にスクリプトの記述ミスなどの理由によりコンピュートノードが起動失敗を繰り返すことをよくやります。今回も 1 時間ほど時間を溶かしました。

スクリプトがどこまで進んだのか、エラーはなにかは CloudWatch Logs に保存されるログを確認するのがオススメです。理由はコンピュートノードはテンポラリなため、起動に失敗するとターミネートされログインしてログ確認ができないからです。

オススメの確認先

.bootstrap_error_msg.syslogのログイベントが切り分けに役立ちます。実際のログイベントにはプリフィックスとして、起動したコンピュートノードのプライベート IP とインスタンス ID がつきます。

ブートストラップエラーログ

カスタムブートストラップスクリプトにエラーがあると、.boostrap_error_msgというログイベントが作成されます。

ip-10-0-1-117.i-0e4b44ca6b5b26d86.bootstrap_error_msg

メッセージ内容を確認するとstderrの項目でスクリプトの実行エラー文を確認できます。ここを手がかりに切り分けをはじめられます。

{
    "datetime": "2024-04-06T04:34:27.017+00:00",
    "version": 0,
    "scheduler": "slurm",
    "cluster-name": "TokoroScalop390",
    "node-role": "ComputeFleet",
    "component": "custom-action",
    "level": "ERROR",
    "instance-id": "i-0e4b44ca6b5b26d86",
    "compute": {
        "name": "queue1-dy-queue1-2",
        "instance-id": "i-0e4b44ca6b5b26d86",
        "instance-type": "m7a.xlarge",
        "availability-zone": "ap-northeast-1a",
        "address": "10.0.1.117",
        "hostname": "ip-10-0-1-117.ap-northeast-1.compute.internal",
        "queue-name": "queue1",
        "compute-resource": "queue1",
        "node-type": "dynamic"
    },
    "event-type": "custom-action-error",
    "message": "Failed to execute OnNodeConfigured script 2, return code: 2.",
    "detail": {
        "action": "OnNodeConfigured",
        "step": 2,
        "stage": "executing",
        "error": {
            "exit_code": 2,
            "stderr": "error: unexpected argument 'hpc-dev-mountpoint-sample-1' found\n\nUsage: mount-s3 [OPTIONS] <BUCKET_NAME> <DIRECTORY>\n\nFor more information, try '--help'.\n"
        }
    }
}

シスログ

こちらはシスログをウォッチできるためコンピュートノード起動中にモニタリングしておくと順調か、ダメそうなのかニアリアルタイムに確認できます。

ip-10-0-1-38.i-0ab9efe2c6023ed5f.syslog

おわりに

コンピュートノードへの S3 バケットマウントは、カスタムブートストラップスクリプトを工夫することで汎用的な作りにできました。複数のクラスター間でマウントスクリプトを使いまわしやすくなりました。しばらく運用してみて使用感を確認してみます。

本記事ではコンピュートノードへの S3 バケットマウントを実現しましたが、ヘッドノードへのマウントが前々からの課題です。 AWS HPC レシピにサービス化して実現するサンプルコードが載っていたので、次はそちらを検証し、ヘッドノードへのマウント方法を共有できればと思います。

参考