AWS ParallelClusterを触ってみる

# はじめに

ご覧いただきありがとうございます。

ParallelClusterについて調査をする機会がありました。
備忘録として調査/検証内容をまとめようと思います。


# 概要

1. HPC環境の概観
2. AWS ParallelClusterのアーキテクチャ
3. AWS ParallelClusterを構築

今回の調査にあたり、下記の記事/AWS Black Belt Online Seminar/公式ドキュメントを参考にしました。
[一週間でなれる！スパコンプログラマ](https://kaityo256.github.io/sevendayshpc/)
[AWS ParallelCluster ではじめるクラウドHPC](https://d1.awsstatic.com/webinars/jp/pdf/services/20200408_BlackBelt_ParallelCluster.pdf)
[Amazon FSx for Lustre](https://d1.awsstatic.com/webinars/jp/pdf/services/20190319_AWS-Blackbelt-Amazon_FSx_Lustre.pdf)
[AWS ParallelClusterバージョン3](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/parallelcluster-version-3.html)

# 1. HPC環境の概観

### HPCのアーキテクチャ

HPC = ハイパフォーマンス・コンピューティングは、膨大な量の計算処理が必要なケースで、複雑な演算処理を高速に実行することを可能にします。

![](https://storage.googleapis.com/zenn-user-upload/6c3cde3feb6e-20220702.png)

一般的な構成では「ログインノード」「計算ノード」「ファイルシステム」が高速ネットワークで繋がるアーキテクチャとなっている。

ユーザーは「ログインノード」にログインして、作業を実施します。
実際の計算は「計算ノード」を使います。

HPC環境を複数のユーザーが共有するため、「各ユーザーが投げたジョブ」を「どの計算ノードで実行するか」決定する仕組みが必要である。

![](https://storage.googleapis.com/zenn-user-upload/29b8b598592a-20220702.png)

ユーザーは、ログインノードからジョブスケジューラーにジョブの実行を依頼します。
ジョブスケジューラーは、どのノードでジョブを実行するかを決定します。

![](https://storage.googleapis.com/zenn-user-upload/3aad3486a876-20220702.png)

ファイルシステムは「メタデータ(どこにデータがあるか)」と「データそのもの」で構成される。
多くのクライアントからの問い合わせを高速にさばいてくれる、スケーラブルな並列ファイルシステムが必要となる。
上記の課題を解決するためによく使われているのが「Lastre」である。

以上がアーキテクチャの概要である。

### HPC環境の課題

```
- サーバ台数が固定化することで、需要が増加する時期には処理に待ち時間が発生する(= スペックが足りない)
- どんな構成でも対応できるようなクラスタを作らざるをえない。結果として「メモリが多すぎる」などリソースの無駄が発生する(= 過剰スペック)
- サーバ台数が多くなることで管理が煩雑になる(= 管理コスト)
```

HPC環境をクラウドに移行することで、上記の問題をカバーする。

```
- 必要な時に必要なだけ利用可能(= スケーリング)
- アプリケーションに合わせた構成のクラスタを構築可能(= リソースの無駄を防ぐ)
- 管理の手間を抑える(= AWSマネージドで管理を任せる)
```

AWSにはHPC環境を実現するためのサービスがあり、クラウドならではの恩恵を受けられる。

# 2. AWS ParallelClusterのアーキテクチャ

### ParallelCluster活用のメリット

HPC環境をAWSに移行するにあたり、いくつか課題がある。

```
- AWS上にAutoScalingするクラスタ環境を作成するのは難しい
- 他のAWSサービスとの連携をさせたい
- HPCの知識以外にAWSやインフラの知識も必要
```

ParallelClusterを利用することで、課題を解決する。

```
- 数コマンド操作でAutoScalingするクラスタ環境をセットアップ
- FSx Lustreなど、AWSの様々なサービスと連携
- 自分専用のクラスタ環境を作成可能
```

ParallelClusterは、数コマンドで、ジョブ投入に応じて自動でスケールするクラスタをAWS上に構築可能なAWS公式ソフトウェアです。


![](https://storage.googleapis.com/zenn-user-upload/09cfd6e813ee-20220702.png)

ParallelClustrerにより、Compute Nodeが0台から数百台規模まで需要に応じてスケーリングするクラスタ環境を作成できます。

### 共有ストレージ

「NFS on Master」がParallelClusterの構成におけるデフォルトです。
[公式](https://aws.amazon.com/jp/hpc/faqs/)によると、「AWS ParallelClusterは、クラスターのマスターノードに接続され、ネットワークファイルシステム（NFS）を介してクラスターのコンピューティングノードにエクスポートされる15GBのElasticBlock Storage（EBS）の外部ボリュームを自動的に構成します」とあります。

一方で高速な分散ストレージサービスである「FSx for Lustre」を選択できます。
膨大なデータを多くの計算資源で高速に処理するワークロードでは、高速なデータアクセスが必要になります。計算環境をスケールさせてもデータアクセスが十分でなければ処理速度はスケールしません。

![](https://storage.googleapis.com/zenn-user-upload/e6fcddadad65-20220702.png)

処理を行う大量のデータは、耐久性が高いS3に置くことが推奨されます。
S3のデータセットとFSx for Lustreファイルシステムを関連づけることで、実際に処理を行うときのみFSx for Lustreを使用することができます。

- 処理をおこなわないときはS3にデータをストック
- 処理が必要なときにFSx for Lustreを立ち上げる
- ファイルをインポートする
- 各インスタンスを用いてデータを処理する
- 結果をS3にエクスポートする
- 処理が終了後、FSx for Lusterを削除


次のセクションでは、「AWS ParallelCluster」「FSx for Lustre」「S3」の構成で環境構築を行います。

# 3. AWS ParallelClusterを構築

### 事前準備

事前に下記のリソースを作成してください。

- VPC
- Public Subnet(Internet Gatewayへのルートあり)
- Private Subnet(NAT Gatewayへのルートあり)
- Internet Gateway
- NAT Gateway
- EC2 (Public Subnetに配置。Adminとして使用)
- S3バケット
- キーペア

### 構成

![](https://storage.googleapis.com/zenn-user-upload/90dd6955a157-20220703.png)

今回はPublic/Private Subnetに分割した構成になります。

それぞれのリソースについて補足します。

- Admin(EC2)
クラスタ構築/管理ツールである「Parallel Cluster」を実行するサーバです。

- ログインノード(EC2)
「Parallel Cluster」で構築されるクラスタのノードです。このサーバでジョブの実行をします。

- 計算ノード 
「Parallel Cluster」で構築されるクラスタのCompute Node(計算ノード)です。需要に応じてオートスケールします。

- FSx for Lustre
「Parallel Cluster」で構築されるクラスタのストレージです。

- Amazon S3
解析前のデータのアップロード、解析後のデータをダウンロードするためのストレージです。


### Admin用のEC2にSSHログイン/ParallelClusterのインストール

クラスタ構築/管理ツールである「Parallel Cluster」はAdminサーバで実行します。
「Parallel Cluster」を実行するためにAdminサーバへSSH接続します。

[こちら](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/install-v3-pip.html)を参考にしながら、インストール作業を行います。
この記事を書いている段階では、ParallelClusterバージョン3のドキュメントを参照しています。

```
$ python3 -m pip install "aws-parallelcluster" --upgrade --user
$ curl -o- https://raw.githubusercontent.com/nvm-
$sh/nvm/v0.38.0/install.sh | bash

$ chmod ug+x ~/.nvm/nvm.sh
$ source ~/.nvm/nvm.sh
$ nvm install --lts
$ node --version
$ pcluster version
{
  "version": "3.1.4"
}
python3 -m pip install "aws-parallelcluster" --upgrade --user
```

### ParallelClusterの初期設定

[公式](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/install-v3-configuring.html)を参考に初期設定を行います。

バージョン3ではyml形式になります。

AWSの認証情報をセットします。

```
$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxx
Default region name [us-east-1]: ap-northeast-1
Default output format [None]:

```

```
$ pcluster configure --config cluster-config.yaml
----------------------------------------------
#リージョン
Allowed values for AWS Region ID: ap-northeast-1
#キーペア
Allowed values for EC2 Key Pair Name: xxxxxxxxxxxxxxxxxxxxxxxx
# スケジューラー
Allowed values for Scheduler:slurm
# OS
Allowed values for Operating System: alinux2

# インスタンスタイプとインスタンス数設定
Head node instance type [t2.micro]: 
Number of queues [1]: 
Name of queue 1 [queue1]: 
Number of compute resources for queue1 [1]: 
Compute instance type for compute resource 1 in queue1 [t2.micro]: 
Maximum instance count [10]: 

# VPCを作成するか。ここでは既存のVPCを使用
Automate VPC creation? (y/n) [n]: n
Allowed values for VPC ID:
VPC ID [vpc-xxxxxxxx]: vpc-xxxxxxxxx

# サブネットを作成するか。ここでは既存のサブネットを使用
# head/Computeごとにサブネットを指定
Automate Subnet creation? (y/n) [y]: n
Allowed values for head node Subnet ID:
head node Subnet ID [subnet-xxxxxxx]: subnet-xxxxxxxxx
Allowed values for Compute Subnet ID:
compute subnet ID [subnet-xxxxxxxx]: subnet-xxxxxxxxx

----------------------------------------------
```
上記のように対話形式で、必要な値を入力します。
入力が完了すると、yamlファイルが作成されます。

```
$ ls
cluster-config.yaml

$ cat cluster-config.yaml

Region: ap-northeast-1
Image:
  Os: alinux2
HeadNode:
  InstanceType: t2.micro
  Networking:
    SubnetId: xxxxxxxxxxxxxxxxxxxxxx
  Ssh:
    KeyName: xxxxxxxxxxxxxxx
Scheduling:
  Scheduler: slurm
  SlurmQueues:
  - Name: queue1
    ComputeResources:
    - Name: t2micro
      InstanceType: t2.micro
      MinCount: 0
      MaxCount: 10
    Networking:
      SubnetIds:
      - xxxxxxxxxxxxxxxxxx
```

### 設定変更(FSx for Lustreの設定)

yamlファイルに編集を加えます。
[こちら](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/SharedStorage-v3.html)を参考にしながら、共有ストレージの設定を追加します。

```
Region: ap-northeast-1
Image:
  Os: alinux2
HeadNode:
  InstanceType: t2.micro
  Networking:
    SubnetId: subnet-xxxxxxxxxxxxxxxxx
  Ssh:
    KeyName: xxxxxxxxxxxxxx
Scheduling:
  Scheduler: slurm
  SlurmQueues:
  - Name: queue1
    ComputeResources:
    - Name: t2micro
      InstanceType: t2.micro
      MinCount: 0
      MaxCount: 10
    Networking:
      SubnetIds:
      - subnet-xxxxxxxxxxxxxxxxxxxxx
      
SharedStorage:
  - MountDir: /lustre
    Name: fsx
    StorageType: FsxLustre
    FsxLustreSettings:
      StorageCapacity: 1200
      ImportPath: s3://xxxxxxxxxxxxxxxxxx
```
「import_path」はS3BucketNameを指定します。



### クラスタの作成と各種CLIコマンド

-h オプションを用いると、pclusterコマンドの一覧が確認できます。

```
 list-clusters       Retrieve the list of existing clusters.
    create-cluster      Create a managed cluster in a given region.
    delete-cluster      Initiate the deletion of a cluster.
    describe-cluster    Get detailed information about an existing cluster.
    
    delete-cluster-instances
                        Initiate the forced termination of all cluster compute
                        nodes. Does not work with AWS Batch clusters.
    describe-cluster-instances
                        Describe the instances belonging to a given cluster.
    ssh                 Connects to the head node instance using SSH.
    version             Displays the version of AWS ParallelCluster.
```

各コマンドの詳細もhelpを使用して確認できます。

```
$ pcluster create-cluster --help
usage: pcluster create-cluster [-h] [-r REGION]
                               [--suppress-validators SUPPRESS_VALIDATORS [SUPPRESS_VALIDATORS ...]]
                               [--validation-failure-level {INFO,WARNING,ERROR}]
                               [--dryrun DRYRUN]
                               [--rollback-on-failure ROLLBACK_ON_FAILURE] -n
                               CLUSTER_NAME -c CLUSTER_CONFIGURATION [--debug]
                               [--query QUERY]

Create a managed cluster in a given region.

・・・(略)
```

ではクラスタを作成します。

```
$ pcluster create-cluster -n test-cluster -c cluster-config.yam
l
{
  "configurationValidationErrors": [
    {
      "level": "ERROR",
      "type": "SubnetsValidator",
      "message": "DNS Hostnames not enabled in the VPC vpc-xxxxxxxxxxxxxx."
    }
  ],
  "message": "Invalid cluster configuration."
```

エラーが発生しました。

![](https://storage.googleapis.com/zenn-user-upload/97be0f59b822-20220705.png)
ドキュメントによると、"VPC には DNS Resolution = yes と DNS Hostnames = yesが必要です。"とあります。
VPCのホスト名を有効化して、再度コマンドを実行します。

```
$ pcluster create-cluster -n test-cluster -c cluster-config.yaml
{
  "cluster": {
    "clusterName": "test-cluster",
    "cloudformationStackStatus": "CREATE_IN_PROGRESS",
    "cloudformationStackArn": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "region": "ap-northeast-1",
    "version": "3.1.4",
    "clusterStatus": "CREATE_IN_PROGRESS"
  }
}
```

クラスタ作成が始まりました。
CloudFormationのページに移行すると、作成中であることが分かります。

![](https://storage.googleapis.com/zenn-user-upload/a7b491ab067a-20220705.png)

```
pcluster describe-cluster --cluster-name test-cluster
```
上記コマンドを入力して、ステータスが"Complete"になったら、作成されたリソースを確認します。

```
## クラスタ⼀覧確認
 $ pcluster list-clusters
{
  "clusters": [
    {
      "clusterName": "test-cluster",
      "cloudformationStackStatus": "CREATE_COMPLETE",
      "cloudformationStackArn": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "region": "ap-northeast-1",
      "version": "3.1.4",
      "clusterStatus": "CREATE_COMPLETE"
    }
  ]
}
```
存在しているクラスタのリストを確認できます。

### ログインノードの確認

```
$ pcluster describe-cluster-instances -n test-cluster
{
  "instances": [
    {
      "launchTime": "2022-07-05T04:35:18.000Z",
      "instanceId": "i-xxxxxxxxxxxxxxxx",
      "publicIpAddress": "xxxxxxxxxxxxxxx",
      "instanceType": "t2.micro",
      "state": "running",
      "nodeType": "HeadNode",
      "privateIpAddress": "xxxxxxxxxxxxx"
    }
  ]
}
```

- EC2(ログインノード)

![](https://storage.googleapis.com/zenn-user-upload/71ec31e5fffe-20220705.png)

- FSx for Lustre

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697264/d9b68911-23aa-3ff2-3f79-310d49b73705.png)


### スタック作成時にエラーが発生する場合

なお私が検証した際は、CloudFormationでスタック作成時に「HeadNodeWaitCondition」がFailになり、リソース作成が失敗しました。
VPCのパブリックサブネットの「パブリック IPv4 アドレスを自動割り当て」が"いいえ"になっていました。
上記を"はい"に変更後、再度スタック作成を実施したところ、無事クラスタ作成が完了しました。

ネットワーク設定については[ドキュメント](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/network-configuration-v3.html)の「2つのサブネットを使用するAWS ParallelCluster」を参照ください。

### ログインノードへのアクセス

「AdminサーバへのSSH接続」を参考にログインノードへのSSH接続設定を行い、Head NodeへSSHアクセスを行います。
ログインノードのIPアドレスは、AWSマネジメントコンソールのEC2インスタンスのページで確認できます。

### ジョブの投入

ログインノードにログインしての作業になります。
[こちら](https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/tutorials-running-your-first-job-on-version-3.html)を参考に、ジョブの投入を実行します。

```
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
queue1*      up   infinite     10  idle~ queue1-dy-t2micro-[1-10]
```

コンピュートノードが設定されていることを確認します。

次にジョブを作成します。
```
$ vi hellojob.sh
$ cat hellojob.sh
#!/bin/bash
sleep 30
echo "Hello World from $(hostname)"
```

sbatch を使用してジョブを送信し、実行されることを確認します。
```
$ sbatch hellojob.sh
Submitted batch job 1
$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1    queue1 hellojob ec2-user CF       0:19      1 queue1-dy-t2micro-1
```

AWSマネジメントコンソールのEC2インスタンスのページを確認すると、Computeノードが立ち上がっていることが確認できます。

![](https://storage.googleapis.com/zenn-user-upload/909965e3f1e3-20220705.png)

少し時間を空けて、再度コマンドを実行します。
キューにジョブがないことが確認できます。

```
$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
```

出力内容を確認します。
```
$ ls -l
total 8
-rw-rw-r-- 1 ec2-user ec2-user 57 Jul  5 05:54 hellojob.sh
-rw-rw-r-- 1 ec2-user ec2-user 37 Jul  5 06:00 slurm-1.out

$ cat slurm-1.out
Hello World from queue1-dy-t2micro-1
```

ジョブ投入の結果が確認できました。

### リソースの削除

ログインノードからログアウトして、Adminサーバに移動。
「pcluster delete-cluster」コマンドを実行します。

```
$ pcluster delete-cluster --cluster-name test-cluster
{
  "cluster": {
    "clusterName": "test-cluster",
    "cloudformationStackStatus": "DELETE_IN_PROGRESS",
    "cloudformationStackArn": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "region": "ap-northeast-1",
    "version": "3.1.4",
    "clusterStatus": "DELETE_IN_PROGRESS"
  }
}
```

CloudFormationのページを確認すると、スタック削除が実行されていることが分かります。
※AdminサーバやS3は手動作成したため、自動削除の対象にならないことをご注意ください。

![](https://storage.googleapis.com/zenn-user-upload/f1c5ecae1b3a-20220705.png)


# さいごに

はじめてのHPCサービス体験だったため、手探りではありましたが簡単な調査と検証を実施しました。
御覧いただき ありがとうございました！！