Amazon Web Services ブログ

AWS ParallelCluster における Slurm REST API

AWS ParallelCluster は、新薬の発見から F1 レースカーの設計、天気の予測に至るまで、さまざまな問題に対応する強力なコンピューティング機能を提供します。 ParallelCluster を利用する全てのケースにおいて、シミュレーションを実行するエンジニアや、実験結果の分析を行うサイエンティストが手動で処理を実行する必要があります。

この投稿では、オープンソースの Slurm REST API を使用して、プログラムでジョブを送信したり監視したりする方法を説明します。 これにより、API 呼び出しを介して ParallelCluster を自動化システムに統合できます。 例えば、ゲノムサンプルがシーケンサーから読み取られるたびに、個々の読み取りのアライメントを行う二次解析パイプラインが自動的に供給されたり、新しい衛星データがAmazon S3バケットに格納されると、最新の天気予報を作成するジョブがトリガーされたりすることを意味します。

本日は、AWS ParallelCluster を使用してこのような仕組みを設定する方法を説明します。 使用できるコードを含む GitHub リポジトリへのリンクを示し、curl と Python の両方を使用して API を呼び出す方法の例を示します。

アーキテクチャー

この図は、Slurm REST API を使用したクラスター アーキテクチャーの例を示しています。 REST API はヘッドノード上で実行され、ジョブを Compute キューに送信します。 API の認証に使用される認証情報は、AWS Secrets Manager に保存されます。 図示されている Compute キューは例にすぎません。クラスターは任意のインスタンス構成で構成できます。

図 1 – REST API 実行におけるアーキテクチャー図

このチュートリアルでは、ParallelCluster UI を使用してSlurm REST API を有効化し、クラスターをセットアップします。 ParallelCluster UI をセットアップするには、オンライン ドキュメントを参照してくださいParallelCluster CLI を使用したい場合は、Step 4 のYAML 構成例 を参照してください。

Step 1 – インバウンド API リクエストを許可するセキュリティ グループを作成する

デフォルト構成では、クラスターは REST API へのインバウンド HTTPS リクエストを受け入れることができません。セキュリティグループを作成して、クラスター外部からのAPI呼び出しを許可します。

  1. EC2 セキュリティグループコンソールに移動し、[セキュリティ グループを作成] を選択します。
  2. [セキュリティ グループ名]に、Slurm REST API (または任意の別の名前) を入力します。
  3. [VPC] がクラスターを構築した VPC と一致することを確認してください。
  4. インバウンド ルールを追加し、[タイプ] で HTTPS を選択し、[ソース] をアクセスしたい CIDR 範囲のみに変更します。 例えば、VPC に関連付けられた CIDR を設定することでVPC 内へのアクセスを制限できます。
  5. [セキュリティグループを作成]を選択します。

図 2 – セキュリティグループの設定

Step 2 – IAM 権限を追加する

ParallelCluster UI チュートリアル のセクションG – Setup IAM Permissions の手順に従ってください。

Step 3 – クラスターを構成する

  1. ParallelCluster UI の Create Clusters で、Head node section > Head node instance > Advanced options > Additional security groups の項目に Step 1 で作成した Slurm REST API セキュリティーグループを追加します。Scripts 配下にある Run script on node configured を選択し、次のスクリプトを追加します。
    https://raw.githubusercontent.com/aws-samples/aws-parallelcluster-post-install-scripts/main/rest-api/postinstall.sh

    図 3 – ノード構成後に実行するスクリプトの追加

  2. Head node section > Security configuration and permissions > IAM Policies の項目に、ポリシーを追加します。この作業は JSON Web Token (JWT) を自動的に更新するために必要となります。
    arn:aws:iam::aws:policy/SecretsManagerReadWrite

    図 4 – AWS SecretsManager の更新を許可する IAM ポリシーの追加

  3. クラスターを作成します。

Step 4 – 構成を検証する

Cluster Configuration YAML ファイルは次のようなテキストになります。 ParallelCluster UI の代わりに ParallelCluster CLI を使用することを選択した場合は、以下を置き換える必要があります。

Imds:
  ImdsSupport: v1.0
HeadNode:
  InstanceType: c5.xlarge
  Imds:
    Secured: true
  Ssh:
    KeyName: amzn2
  LocalStorage:
    RootVolume:
      VolumeType: gp3
  Networking:
    SubnetId: subnet-xxxxxxxxxxxxxx
    AdditionalSecurityGroups:
      - sg-slurmrestapixxxxxxxxxx
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/SecretsManagerReadWrite
  CustomActions:
    OnNodeConfigured:
      Script: >-
        https://raw.githubusercontent.com/aws-samples/aws-parallelcluster-post-install-scripts/main/rest-api/postinstall.sh
Scheduling:
  Scheduler: slurm
  SlurmQueues:
    - Name: queue-1
      ComputeResources:
        - Name: queue-1-cr-1
          Instances:
            - InstanceType: c5.xlarge
          MinCount: 0
          MaxCount: 4
      ComputeSettings:
        LocalStorage:
          RootVolume:
            VolumeType: gp3
      Networking:
        SubnetIds:
          - subnet-xxxxxxxxxxxxxxxxxx
Region: us-east-2
Image:
	Os: alinux2

Step 5 – API を呼び出す

  1. Step 1 のセキュリティグループ上で許可したネットワークのマシンにログインします。このマシンがヘッドノードと通信できることを確認してください。
    ssh username@ip
  2. 次の環境変数を設定します。
    export CLUSTER_NAME=[name of cluster]
  3.  API リクエストを作成するために必要な情報を確認し、API リクエストを呼び出します。 APIリクエストの作成には、以下の情報が必要です。
    ・JWT トークン: インストール後のスクリプトにより、AWS SecretsManagerslurm_token_$CLUSTER_NAME という名前でシークレットが作成されます。 AWS コンソールまたは AWS CLI を使用して、クラスター名に基づいてシークレットを確認します。

    export JWT=$(aws secretsmanager get-secret-value --secret-id slurm_token_$CLUSTER_NAME | jq -r '.SecretString')
    NOTE: Since the Slurm REST API script is not integrated into ParallelCluster, this secret will not be automatically deleted along with the cluster. You may want to remove it manually on cluster deletion.
    Bash
    

    ・ヘッドノードの Public IP: Amazon EC2 ダッシュボードまたは ParallelCluster CLI を使用してヘッドノードの Public IP を確認することができます。

    export HEADNODE_IP=$(pcluster describe-cluster-instances -n $CLUSTER_NAME | jq -r '.instances[0].publicIpAddress')

    ・クラスター ユーザー: 利用するAMI によって異なりますが、通常は ec2-user 、 ubuntu 、または centos のいずれかになります。

    export CLUSTER_USER=ec2-user
  4. curl を使用して API を呼び出します。
    curl -H "X-SLURM-USER-NAME: $CLUSTER_USER" -H "X-SLURM-USER-TOKEN: $JWT" https://$HEADNODE_IP/slurm/v0.0.39/ping -k

    次のような応答が返されます。

    {
        "meta": {
            "plugin": {
                "type": "openapi\/v0.0.39",
                "name": "REST v0.0.39"
            },
            "Slurm": {
                "version": {
                "major": 23,
                "micro": 2,
                "minor": 2
            },
             "release": "23.02.2"
        }...

    APIを使用してジョブを送信します。 JSONを使用してジョブパラメーターを指定します。 クラスターユーザーに応じて、標準ディレクトリの変更が必要になる場合があります。
    API にジョブを送信します。

    curl -H "X-SLURM-USER-TOKEN: $CLUSTER_USER" -H "X-SLURM-USER-TOKEN: $JWT" -X POST https://$IP/slurm/v0.0.39/job/submit -H "Content-Type: application/json" -d @testjob.json -k

    ジョブが実行中であることを確認します。

    curl -H "X-SLURM-USER-NAME: $CLUSTER_USER" -H "X-SLURM-USER-TOKEN: $JWT" https://$IP/slurm/v0.0.39/jobs -k

Python リクエスト ライブラリを使用した API の呼び出し

  1. 次の内容を含む slurmapi.py というスクリプトを作成します。
    #!/usr/bin/env python3
    import argparse
    import boto3
    import requests
    import json
    
    # Create argument parser
    parser = argparse.ArgumentParser()
    parser.add_argument('-n', '--cluster-name', type=str, required=True)
    parser.add_argument('-u', '--cluster-user', type=str, required=False)
    subparsers = parser.add_subparsers(dest='command', required=True)
    
    diag_parser = subparsers.add_parser('diag', help="Get diagnostics")
    ping_parser = subparsers.add_parser('ping', help="Ping test")
    
    submit_job_parser = subparsers.add_parser('submit-job', help="Submit a job")
    submit_job_parser.add_argument('-j', '--job', type=str, required=True)
    
    list_jobs_parser = subparsers.add_parser('list-jobs', help="List active jobs")
    
    describe_job_parser = subparsers.add_parser('describe-job', help="Describe a job by id")
    describe_job_parser.add_argument('-j', '--job-id', type=int, required=True)
    
    cancel_parser = subparsers.add_parser('cancel-job', help="Cancel a job")
    cancel_parser.add_argument('-j', '--job-id', type=int, required=True)
    
    args = parser.parse_args()
    
    # Get JWT token
    client = boto3.client('secretsmanager')
    boto_response = client.get_secret_value(SecretId=f'slurm_token_{args.cluster_name}')
    jwt_token = boto_response['SecretString']
    
    # Get cluster headnode IP
    client = boto3.client('ec2')
    filters = [{'Name': 'tag:parallelcluster:cluster-name', 'Values': [args.cluster_name]}]
    boto_response = client.describe_instances(Filters=filters)
    headnode_ip = boto_response['Reservations'][0]['Instances'][0]['PublicIpAddress']
    
    url = f'https://{headnode_ip}/slurm/v0.0.39'
    headers = {'X-SLURM-USER-TOKEN': jwt_token}
    if args.cluster_user:
        headers['X-SLURM-USER-NAME'] = args.cluster_user
    
    # Make request
    if args.command == 'ping':
        r = requests.get(f'{url}/ping', headers=headers, verify=False)
    elif args.command == 'diag':
        r = requests.get(f'{url}/diag', headers=headers, verify=False)
    elif args.command == 'submit-job':
        with open(args.job) as job_file:
            job_json = json.load(job_file)
        r = requests.post(f'{url}/job/submit', headers=headers, json=job_json, verify=False)
    elif args.command == 'list-jobs':
        r = requests.get(f'{url}/jobs', headers=headers, verify=False)
    elif args.command == 'describe-job':
        r = requests.get(f'{url}/job/{args.job_id}', headers=headers, verify=False)
    elif args.command == 'cancel-job':
        r = requests.delete(f'{url}/job/{args.job_id}', headers=headers, verify=False)
    
    print(r.text)
  2. ジョブを送信するには下記を実行してください。
    ./slurmapi.py -n [cluster_name] submit-job -u [cluster_user] -j testjob.json
  3. さらに詳しい情報を入手するには下記を実行してください。
    ./slurmapi.py -h

結論

Slurm REST API をセットアップすると、クラスターをプログラムで制御できるようになり、クラスターを自動化ワークフロー上で構築できるようになります。 これにより、無数のユースケースの中でも、ゲノミクスデータの自動二次分析、金融市場のリスク分析、天気予報などの新しいユースケースが可能になります。 私たちは皆さんが何を構築するかを楽しみにしています。思いついたものを X(旧Twitter) に投稿して紹介してください。

この投稿は、シニア HPC ソリューション アーキテクトである Sean Smith と、HPC SDE インターンである Ryan Kilpadi によって寄稿されました。

翻訳はソリューションアーキテクトの寺部が担当しました。原文はこちらです。

著者について

Ryan Kilpadi

Ryan Kilpadi は、AWS ParallelCluster を手がける HPC チームの SDE インターンとして戻ってきました。 彼は、2022 年の夏のインターンシップ プロジェクトとして、ParallelCluster での Slurm REST API の実装に取り組みました。

Sean Smith

Sean Smith は、AWS の HPC および生成 AI 担当のシニア スペシャリスト ソリューション アーキテクトです。 以前は AWS Batch と CfnCluster のソフトウェア エンジニアとして働き、AWS ParallelCluster を作成したチームの最初のエンジニアになりました。