SageMaker HyperPod で FSx Lustre をマウントしてみた
こんにちは!AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。
みなさん SageMaker HyperPod 使っていますか?
今回は SageMaker HyperPod の共有ストレージ領域に FSx for Lustre を利用したいと思います。
FSx for Lustre
AWS が提供する高性能なフルマネージド分散並列ファイルシステムです。
FSx for Lustre を利用することで 1/100 秒未満のレイテンシ、最大数百 GBps のスループット、最大数百万の IOPS の性能を有したファイルシステムを利用できます。
データリポジトリ
FSx for Lustre では S3 と統合しており、 S3 オブジェクトをファイルとして透過的に書き込み/読み込みできます。
学習や推論で利用されるデータはサイズが大きいことが多々あり、各ノードが起動するタイミングで直接 S3 からダウンロードするのは時間もお金も大きくかかります。
FSx for Lustre を中継させることでコスト効率を高める効果が見込めます。
通信要件
EFA の有無で異なります。
EFA 無し
EFA なしの場合は SageMaker HyperPod ノードおよび自身のセキュリティグループを 988, 1018-1023 ポートで許可するように設定します。
Lustre ファイルシステム側
インバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
Custom TCP | TCP | 988 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 988 | SageMaker HyperPod ノードのセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | SageMaker HyperPod ノードのセキュリティグループ ID |
アウトバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
Custom TCP | TCP | 988 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 988 | SageMaker HyperPod ノードのセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | SageMaker HyperPod ノードのセキュリティグループ ID |
Lustre クライアント側
インバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
Custom TCP | TCP | 988 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 988 | Lustre ファイルシステムのセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | Lustre ファイルシステムのセキュリティグループ ID |
アウトバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
Custom TCP | TCP | 988 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 988 | Lustre ファイルシステムのセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | 自身のセキュリティグループ ID |
Custom TCP | TCP | 1018-1023 | Lustre ファイルシステムのセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | 0.0.0.0/0 |
※一番最後のすべてのトラフィックは外部接続用のルールのため、 Lustre とのやりとりとは別のルールです。
EFA 有り
EFA 有りの場合はすべての送受信トラフィックを許可する必要があります。
If you are going to create an EFA-enabled FSx for Lustre, you should first create an EFA-enabled security group and specify it as the security group for the file system. An EFA requires a security group that allows all inbound and outbound traffic to and from the security group itself and the security group of the clients if clients reside in a different security group. For more information, see Step 1: Prepare an EFA-enabled security group in the Amazon EC2 User Guide.
要約すると以下のルールを追加する必要があります。
Lustre ファイルシステム側
インバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
すべてのトラフィック | すべて | すべて | 自身のセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | SageMaker HyperPod ノードのセキュリティグループ ID |
アウトバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
すべてのトラフィック | すべて | すべて | 自身のセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | SageMaker HyperPod ノードのセキュリティグループ ID |
Lustre クライアント側
インバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
すべてのトラフィック | すべて | すべて | 自身のセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | Lustre ファイルシステムのセキュリティグループ ID |
アウトバウンドルール
タイプ | プロトコル | ポート | ソース |
---|---|---|---|
すべてのトラフィック | すべて | すべて | 自身のセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | Lustre ファイルシステムのセキュリティグループ ID |
すべてのトラフィック | すべて | すべて | 0.0.0.0/0 |
一番最後のすべてのトラフィックは外部接続用のルールのため、 Lustre とのやりとりとは別のルールです。
0.0.0.0/0
で許可をしていますが、合わせてセキュリティグループ ID も許可してあげる必要があります。
If you want to create a HyperPod cluster with EFA-enabled instances, make sure that you set up a security group to allow all inbound and outbound traffic to and from the security group itself. Note that allowing outbound traffic to 0.0.0.0/0 isn't sufficient and can cause EFA health checks to fail. Make sure that you add an explicit outbound traffic rule to the security group so that the instances in the security group can communicate. To learn more, see Step 1: Prepare an EFA-enabled security group in the Amazon EC2 User Guide.
SageMaker HyperPod 上で動かす際の注意点
ドキュメントの通りなのですが、ユーザー管理の VPC 上でホストする必要があること、ネットワーク遅延を避けるためになるべく同一 AZ 上でクライアント、ファイルシステムの送受信を行うことが推奨されています。
To start using SageMaker HyperPod and mapping data paths between the cluster and your FSx for Lustre file system, select one of the AWS Regions supported by SageMaker HyperPod. After choosing the AWS Region you prefer, you also should determine which Availability Zone (AZ) to use. If you use SageMaker HyperPod compute nodes in AZs different from the AZs where your FSx for Lustre file system is set up within the same AWS Region, there might be communication and network overhead. We recommend that you to use the same physical AZ as the one for the SageMaker HyperPod service account to avoid any cross-AZ traffic between SageMaker HyperPod clusters and your FSx for Lustre file system. Also, make sure that you have configured it with your VPC. If you want to use Amazon FSx as the main file system for storage, you must configure SageMaker HyperPod clusters with VPC.
やってみる
それでは SageMaker HyperPod のインスタンスを FSx for Lustre にマウントしてみたいと思います。
今回利用したコードは以下に格納されています。
Security Group
セキュリティグループはドキュメントに従い、 EFA 対応にしてみました。(Lustre 側で EFA 有効化する術がないため、本来だと特定ポートで制御が望ましいですが。)
###################################################
# Security Group for Lustre File System
###################################################
resource "aws_security_group" "lustre" {
name = "${local.prefix}-lustre-sg"
vpc_id = module.vpc.vpc_id
description = "${local.prefix}-hyperpod-sg"
tags = {
Name = "${local.prefix}-lustre-sg"
}
}
# Ingress
resource "aws_vpc_security_group_ingress_rule" "lustre_all_traffic_self" {
security_group_id = aws_security_group.lustre.id
referenced_security_group_id = aws_security_group.lustre.id
ip_protocol = "-1"
}
resource "aws_vpc_security_group_ingress_rule" "lustre_all_traffic_hyperpod" {
security_group_id = aws_security_group.lustre.id
referenced_security_group_id = aws_security_group.hyperpod.id
ip_protocol = "-1"
}
# Egress
resource "aws_vpc_security_group_egress_rule" "lustre_all_traffic_self" {
security_group_id = aws_security_group.lustre.id
referenced_security_group_id = aws_security_group.lustre.id
ip_protocol = "-1"
}
resource "aws_vpc_security_group_egress_rule" "lustre_all_traffic_hyperpod" {
security_group_id = aws_security_group.lustre.id
referenced_security_group_id = aws_security_group.hyperpod.id
ip_protocol = "-1"
}
クライアント(ノード)側も許可してあげましょう。
###################################################
# Security Group for SageMaker HyperPod Cluster
###################################################
resource "aws_security_group" "hyperpod" {
name = "${local.prefix}-hyperpod-sg"
vpc_id = module.vpc.vpc_id
description = "${local.prefix}-hyperpod-sg"
tags = {
Name = "${local.prefix}-hyperpod-sg"
}
}
# Ingress
resource "aws_vpc_security_group_ingress_rule" "hyperpod_all_traffic_self" {
security_group_id = aws_security_group.hyperpod.id
referenced_security_group_id = aws_security_group.hyperpod.id
ip_protocol = "-1"
}
+ resource "aws_vpc_security_group_ingress_rule" "hyperpod_all_traffic_lustre" {
+ security_group_id = aws_security_group.hyperpod.id
+ referenced_security_group_id = aws_security_group.lustre.id
+ ip_protocol = "-1"
+ }
# Egress
resource "aws_vpc_security_group_egress_rule" "hyperpod_all_traffic_self" {
security_group_id = aws_security_group.hyperpod.id
referenced_security_group_id = aws_security_group.hyperpod.id
ip_protocol = "-1"
}
+ resource "aws_vpc_security_group_egress_rule" "hyperpod_all_traffic_lustre" {
+ security_group_id = aws_security_group.hyperpod.id
+ referenced_security_group_id = aws_security_group.lustre.id
+ ip_protocol = "-1"
+ }
resource "aws_vpc_security_group_egress_rule" "hyperpod_all_traffic_ipv4" {
security_group_id = aws_security_group.hyperpod.id
cidr_ipv4 = "0.0.0.0/0"
ip_protocol = "-1"
}
Lustre Fils System
Lustre ファイルシステムの定義です。
書き込みした結果を S3 にも反映したいため、aws_fsx_data_repository_association
を定義しました。
###################################################
# Data Repository for Lustre File System
###################################################
resource "aws_s3_bucket" "data_repository" {
bucket = "${local.prefix}-hyperpod-data-${local.account_id}"
force_destroy = true
}
resource "aws_s3_bucket_public_access_block" "data_repository" {
bucket = aws_s3_bucket.data_repository.bucket
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_ownership_controls" "data_repository" {
bucket = aws_s3_bucket.data_repository.bucket
rule {
object_ownership = "BucketOwnerPreferred"
}
}
###################################################
# Lustre File System
###################################################
resource "aws_fsx_lustre_file_system" "this" {
storage_type = "SSD"
file_system_type_version = "2.15"
storage_capacity = 1200
security_group_ids = [aws_security_group.lustre.id]
subnet_ids = [module.vpc.private_subnets[0]]
data_compression_type = "LZ4"
deployment_type = "PERSISTENT_2"
per_unit_storage_throughput = 250
metadata_configuration {
mode = "AUTOMATIC"
}
}
resource "aws_fsx_data_repository_association" "this" {
file_system_id = aws_fsx_lustre_file_system.this.id
data_repository_path = "s3://${aws_s3_bucket.data_repository.bucket}"
file_system_path = "/"
s3 {
auto_export_policy {
events = ["NEW", "CHANGED", "DELETED"]
}
auto_import_policy {
events = ["NEW", "CHANGED", "DELETED"]
}
}
}
provisioning_parameters.json
provisioning_parameters.json
です。
Lustre をマウントするため、fsx_dns_name
と fsx_mountname
を定義します。
###################################################
# Lifecycle Script Objects for SageMaker HyperPod Cluster
###################################################
resource "aws_s3_object" "life_cycle_scripts" {
for_each = fileset("./config/", "**")
bucket = aws_s3_bucket.life_cycle_scripts.bucket
key = "config/${each.value}"
source = "./config/${each.value}"
}
resource "aws_s3_object" "life_cycle_scripts_provisioning_parameters" {
bucket = aws_s3_bucket.life_cycle_scripts.bucket
key = "config/provisioning_parameters.json"
content = jsonencode(
{
"version" = "1.0.0"
"workload_manager" = "slurm"
"controller_group" = "controller-group"
"worker_groups" = []
+ "fsx_dns_name" = aws_fsx_lustre_file_system.this.dns_name
+ "fsx_mountname" = aws_fsx_lustre_file_system.this.mount_name
}
)
}
HyperPod
最後に HyperPod クラスターです。
Lustre 周り諸々依存関係を depends_on
で明示的に定義してあげるのが重要なポイントです。
###################################################
# SageMaker HyperPod Cluster
###################################################
resource "awscc_sagemaker_cluster" "this" {
cluster_name = "${local.prefix}-cluster"
instance_groups = [
{
execution_role = aws_iam_role.hyperpod.arn
instance_count = 1
instance_group_name = "controller-group"
instance_type = "ml.t3.medium"
life_cycle_config = {
source_s3_uri = "s3://${aws_s3_bucket.life_cycle_scripts.id}/config/"
on_create = "on_create.sh"
}
}
]
vpc_config = {
security_group_ids = [aws_security_group.hyperpod.id]
subnets = [module.vpc.private_subnets[0]]
}
depends_on = [
+ aws_iam_role_policy_attachment.hyperpod_vpc,
+ aws_iam_role_policy_attachment.hyperpod_s3,
+ aws_vpc_endpoint.s3,
+ aws_s3_object.life_cycle_scripts_provisioning_parameters
]
}
aws_iam_role_policy_attachment.hyperpod_s3
は sagemaker-
から始まる S3 バケットではないためアタッチしています。
接続確認
接続確認をしてみます。
aws ssm start-session \
--target sagemaker-cluster:je7plekuheau_controller-group-i-02cb085c72ba19ca6
うまく繋がっていますね。
[cloudshell-user@ip-10-132-77-98 ~]$ aws ssm start-session \
> --target sagemaker-cluster:je7plekuheau_controller-group-i-02cb085c72ba19ca6
Starting session with SessionId: cm-takakuni.shinnosuke-fsfoepusyfrug2ch99lopbchtu
# whoami
root
/fsx
領域に 1.2T の大きさでマウントされてますね。
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 97G 51G 46G 53% /
devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 386M 1.2M 385M 1% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/loop0 64M 64M 0 100% /snap/core20/2379
/dev/loop2 75M 75M 0 100% /snap/core22/1621
/dev/loop1 64M 64M 0 100% /snap/core20/2434
/dev/loop5 92M 92M 0 100% /snap/lxd/29619
/dev/loop3 74M 74M 0 100% /snap/core22/1663
/dev/loop4 39M 39M 0 100% /snap/snapd/21759
/dev/nvme0n1p15 105M 6.1M 99M 6% /boot/efi
tmpfs 386M 24K 386M 1% /run/user/128
10.0.1.35@tcp:/vtmdtbev 1.2T 38M 1.2T 1% /fsx
#
/fsx
領域に移動し、ファイルを作ってみました。
# cd /fsx
# ls
enroot ubuntu
# echo hello! from hyperpod node! > hello.txt
# cat hello.txt
hello! from hyperpod node!
#
S3 からも確認できますね。
S3 からもオブジェクトアップロードしてみました。
hello! from S3!
ノード側も出現してきました。中身も問題なく確認できますね。
# ls
enroot hello.txt hello_from_s3.txt ubuntu
# cat hello_from_s3.txt
hello! from S3!#
まとめ
以上、「SageMaker HyperPod で FSx Lustre をマウントしてみた」でした。
Lustre はじめて触ったのですが S3 バケットを透過的に操作できる点、素晴らしいですね。
これからもマスターできるようゴリゴリ触っていきたいと思います。
AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!