亚马逊AWS官方博客

使用Simple Active Directory集中管理多个 ParallelCluster集群的用户

简介

ParallelCluster是由亚马逊云科技提供支持的开源集群管理工具,可以帮助客户快速创建并管理HPC集群。在一些场景下,客户会需要使用ParallelCluster部署多个Slurm集群,此外,还希望能做到集中管理多个集群的用户,并在多个集群间共享用户数据。

通过本文,您可以了解如何使用SimpleAD实现多个ParallelCluster集群的用户集中管理;并将共享存储Amazon Elastic File System (Amazon EFS) 作为用户的家目录,实现用户在多个集群间的数据共享。

Simple Active Directory (Simple AD)是亚马逊云科技提供的一个托管的目录服务,与Samba 4 目录服务兼容,并提供了不同规模的版本,满足不同用户的需求。Amazon EFS是亚马逊云科技提供的即用式无服务器弹性文件系统,它可以随着您添加和删除文件自动增大或收缩存储空间,无需管理或预置。

本文会包含个五个章节:环境要求,创建VPC、EFS及SimpleAD,创建ParallelCluster集群,集群用户管理,资源清理。

环境要求

在开始之前,我们首先需要了解下环境要求,避免出现意外的错误。

版本

  • 本文在Ubuntu 20.04进行了测试,并建议您也使用此OS版本 。
  • 本文撰写时,ParallelCluster的版本号为2.11.1,如果您的版本不同,请以官网文档给出的配置方法为准。

Amazon VPC

  • Amazon VPC 需要包含至少1个公有
  • 子网、2个分处不同可用区(Availability Zone, AZ)的私有子网;
  • 公有子网放置ParallelCluster的Head节点,或者说是Slurm集群的登录(Login)节点;
  • 其中一个私有子网与公有子网同处一个AZ,并放置Compute节点,以减少跨AZ数据传输带来的流量费。
  • 私有子网,需要确保存在NAT 网关,以满足ParallelCluster访问外网的需求。否则,会导致集群创建失败。
  • NAT网关需要放在公有子网
  • 启用DNS 主机名
  • 启用DNS 解析

Amazon EFS文件系统

  • 建议手动创建EFS,防止集群终止的时候,文件系统被一起删除。
  • Simple AD会使用两个AZ的子网,需要保证EFS在这两个AZ都有挂载点(Mount Target)。
  • EFS绑定的安全组需要允许Head及Compute节点访问。没有特殊要求的话,可以将安全组的source指定为 VPC CDIR。Region(区域)
  • 确保以下服务/资源都是在同一个Region创建

准备工作

在部署ParallelCluster集群之前,我们需要先创建VPC网络、EFS及Simple AD等基础依赖项。

创建VPC

如果已有VPC,请按照 环境要求章节检查是否满足要求。如果没有VPC,可以使用[1]中的链接,通过CloudFormation服务,快速创建包含公有子网和 私有子网及对应NAT网关的VPC。

创建EFS

我们建议您手动创建EFS,在VPC中所有的AZ中都创建挂载点。防止集群终止的时候,文件系统被一起删除。

您也可以选择让ParallelCluster帮您自动完成EFS文件系统的创建,但您需要手动在其他AZ添加挂载点。

注意,EFS挂载点上绑定的安全组需要允许Head及Compute节点访问。

创建Simple AD

Simple AD的默认管理员是Administrator,以下参数请根据您的实际需要调整。

Directory DNS name: awsabc.cn

Directory NetBIOS name: TEST

Administrator password: <Your DOMAIN password>

第三步中的VPC选择之前创建的VPC,并选择两个私有子网,注意,其中一个子网的AZ需要和Head节点的相同。

等待约10分钟,完成创建,信息如下:

更新VPC DHCP选项集

这里,我们使用Simple AD管理DNS解析,因此需要使用自定义的VPC的DHCP选项集(DHCP Options Set)。

获取Simple AD的信息

从Simple AD的截图获取如下信息:

  • DNS地址:10.45.230,10.0.0.4
  • Domain Name:awsabc.cn ap-southeast-1.internal

注意:ap-southeast-1需要和您选择的Region一致。

创建DHCP选项集

在VPC控制台,点击创建DHCP选项集。

填入如下信息:

  • 名称(可选):pcluster-u20-simplead
  • 域名:awsabc.cn ap-southeast-1.internal
  • 域名服务器:0.0.4,10.0.45.230

这里,需要注意域名服务器的IP顺序,请将与您Head节点或者Compute节点同一个CIDR的IP放在第一个。

DHCP选项集创建完成:

绑定DHCP选项集到VPC


创建ParallelCluster集群

自定义AMI

可以将必要的软件包提前打包到AMI里,减少Compute节点的初始化时间。打包方式参考官方doc[2] 。以下步骤,使用的是新加坡区域(ap-southeast-1),ParallelCluster 版本号为 2.11.1 ,OS及版本为Ubuntu 20.04  的。注意,pcluster每个版本的base image不同。您需要根据当前所用的pcluster版本,选择对应的base image。

ParallelCluster版本的查看命令是 pcluster version,输出为2.11.1(以实际输出为准)。

在官方AMI的基础上,构建定制化AMI的步骤如下:

  1. https://github.com/aws/aws-parallelcluster/blob/v2.11.1/amis.txt 找到base image,如ubuntu 20.04 为 ap-southeast-1: ami-0b0a1c6100fd9218d 。
  2. 根据此AMI启动机器,
  3. 安装自己的环境,
  4. 执行 sudo /usr/local/sbin/ami_cleanup.sh ,
  5. 关机,
  6. 创建AMI并得到新的AMI ID。

初始化ParallelCluster配置文件

建议您把ParallelCluster的Head节点放在公有子网,这样您就可以通过公网的方式直接访问Head节点。

同时,建议您选择与公有子网相同AZ的私有子网启动Compute节点,可以保证Head节点与Compute节点之间的延迟最小,且避免产生跨AZ的流量费。

export AWS_PROFILE=defalut
pcluster configure -c ~/.parallelcluster/config.sin.efs.u20 
Allowed values for AWS Region ID:
1. ap-east-1
2. ap-northeast-1
3. ap-northeast-2
4. ap-south-1
5. ap-southeast-1
…
AWS Region ID [eu-central-1]: 5

Allowed values for EC2 Key Pair Name:
1. new-sing
2. …
EC2 Key Pair Name [new-sing]: 1

Allowed values for Scheduler:
1. sge
2. torque
3. slurm
4. awsbatch
Scheduler [slurm]: 3

Allowed values for Operating System:
1. alinux2
2. centos7
3. centos8
4. ubuntu1804
5. ubuntu2004
Operating System [alinux2]: 5

Minimum cluster size (instances) [0]: <ENTER>

Maximum cluster size (instances) [10]: <ENTER>

Head node instance type [t2.micro]: t3.large

Compute instance type [t2.micro]: c5.large

Automate VPC creation? (y/n) [n]: n

Allowed values for VPC ID:
  #  id                               name                                         number_of_subnets
---  ---------  ---------------------------------                    -------------------
  3  vpc-xx     ParallelClusterVPC-20210824092800                    3

VPC ID [vpc-00cf21c92c6158040]: 3

Automate Subnet creation? (y/n) [y]: n

Allowed values for head node Subnet ID:
  #                     id                        name                               size    availability_zone
---  ------------------------  -------------------------------  ------  -------------------
  1  subnet-08b5a8997039c523c  ParallelClusterPublicSubnet       256    ap-southeast-1c
  2  subnet-06a806ca4e7635b2a  ParallelClusterPrivateSubnet-1c   4096  ap-southeast-1c
  3  subnet-0bcaaff0386296d48  ParallelClusterPrivateSubnet-1b    4096  ap-southeast-1b
head node Subnet ID [subnet-08b5a8997039c523c]: 1

Allowed values for compute Subnet ID:
  #                     id                        name                               size    availability_zone
---  ------------------------  -------------------------------  ------  -------------------
  1  subnet-08b5a8997039c523c  ParallelClusterPublicSubnet     256    ap-southeast-1c
  2  subnet-06a806ca4e7635b2a  ParallelClusterPrivateSubnet-1c   4096  ap-southeast-1c
  3  subnet-0bcaaff0386296d48  ParallelClusterPrivateSubnet-1b    4096  ap-southeast-1b
compute Subnet ID [subnet-06a806ca4e7635b2a]: 2

Configuration file written to /Users/binc/.parallelcluster/config.sin.u20 

编辑PCluster配置文件

增加修改集群配置,使用Spot实例,增加pre/post install 脚本,

注意,请根据您的情况,调整文件内容。

cat ~/.parallelcluster/config.sin.efs.u20 

[aws]
aws_region_name = ap-southeast-1

[aliases]
ssh = ssh {CFN_USER}@{MASTER_IP} {ARGS}

[global]
cluster_template = default
update_check = true
sanity_check = true

[cluster default]
key_name = <YOUR-KEY-PAIR>
scheduler = slurm
master_instance_type = t3.large
base_os = ubuntu2004
vpc_settings = default
queue_settings = spot
s3_read_resource = arn:aws:s3:::<YOUR-BUCKET>/*
pre_install = s3://<YOUR-BUCKET>/pcluster/scripts/ad/pre_install.sh
post_install = s3:// <YOUR-BUCKET>/pcluster/scripts/ad/post_install.sh
additional_iam_policies=arn:aws:iam::aws:policy/AmazonSSMDirectoryServiceAccess,arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore,arn:aws:iam::aws:policy/AWSLambda_FullAccess
efs_settings = customfs

[vpc default]
vpc_id = <YOUR-VPC-ID>
master_subnet_id = <YOUR-HEAD-SUBNET-ID>
compute_subnet_id = <YOUR_COMPUTE-SUBNET-ID>

[queue spot]
enable_efa = false
enable_efa_gdr = false
compute_resource_settings = default
compute_type=spot

[compute_resource default]
instance_type = c5.large
min_count = 0
max_count=300

[efs customfs]
shared_dir = efs
efs_fs_id = <YOUR-EFS-ID> 

pre_install.sh

#!/bin/bash

set -x

exec > >(tee /var/log/pre-install.log|logger -t user-data -s 2>/dev/console) 2>&1

if ! command -v realm &> /dev/null
then
    echo "<realm> could not be found, run install..."
    # Install the required packages
    export DEBIAN_FRONTEND=noninteractive
    apt update && apt -y install sssd realmd krb5-user samba-common packagekit adcli sssd-tools
fi

instance_id=$(curl http://169.254.169.254/latest/meta-data/instance-id)
region=$(curl  -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/[a-z]$//')
# Lambda function to join the linux system in the domain
aws --region ${region} lambda invoke --function-name join-domain-function /tmp/out --payload '{"instance": "'${instance_id}'"}' --log-type None
output=""
while [ -z "$output" ]
do
  sleep 5
  output=$(realm list)
done
#This line allows the users to login without the domain name
sed -i 's/use_fully_qualified_names = True/use_fully_qualified_names = False/g' /etc/sssd/sssd.conf
#This line configure sssd to create the home directories in the shared folder
sed -i '/fallback_homedir/c\fallback_homedir = /efs/home/%u' /etc/sssd/sssd.conf
sleep 1
service sssd restart
# This line is required for AWS Parallel Cluster to understand correctly the custom domain
sed -i "s/--fail \${local_hostname_url}/--fail \${local_hostname_url} | awk '{print \$1}'/g" /opt/parallelcluster/scripts/compute_ready

echo "####pre install finished####" 

post_install.sh

#!/bin/bash

set -x

exec > >(tee /var/log/post-install.log|logger -t user-data -s 2>/dev/console) 2>&1

if ! [ -d /efs/home ]; then
    mkdir /efs/home
fi

sed -i 's/PasswordAuthentication no//g' /etc/ssh/sshd_config
echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
sleep 1
service sshd restart

echo "####post install finished####" 

创建Lambda函数

此函数可以实现将head和compute节点加入到domain中。

环境

Lambda 控制台,点创建函数。

  • Function name:join-domain-function
  • Runtime:python 3.6

函数代码

填入如下代码(注意修改区域、用户名和密码),然后点击 部署(Deploy)。

import json
import boto3
import time

def lambda_handler(event, context):
    json_message = json.dumps(event)
    message = json.loads(json_message)
    instance_id = message['instance']
    ssm_client = boto3.client('ssm', region_name="ap-southeast-1") # 修改region_name为您所选区域
    DomainName_value = "awsabc.cn"   # 修改为您的域名
    DomainPassword_value = "Yourpassword1234"  # 修改为您的密码
    response = ssm_client.send_command(
             InstanceIds=[
                "%s"%instance_id
                     ],
             DocumentName="AWS-RunShellScript",
             Parameters={
                'commands':[
                     'echo "%s" | realm join -U Administrator %s --verbose;rm -rf /var/lib/amazon/ssm/i-*/document/orchestration/*'%(DomainPassword_value, DomainName_value)                       ]
                  },
               )
    return {
        'statusCode': 200,
        'body': json.dumps('Command Executed!')
    } 

函数权限

点击角色名称,

点击附加策略

筛选 AmazonSSMFullAccess ,勾选 AmazonSSMFullAccess,点击附加策略。

执行集群创建命令

pcluster create -nr -c ~/.parallelcluster/config.sin.efs.u20 u20-cluster 

-nr参数,表示如果出现错误,不回滚CloudFormation,方便在集群创建出现问题的时候进行调试。

在确认集群功能正常之后,您可以采用同样的命令,快速创建出更多的集群。

测试集群功能

集群加入Domain成功

可以通过realm list命令查看状态。

root@ip-10-0-0-123:~# realm list
awsabc.cn
  type: kerberos
  realm-name: AWSABC.CN
  domain-name: awsabc.cn
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: sssd-tools
  required-package: sssd
  required-package: libnss-sss
  required-package: libpam-sss
  required-package: adcli
  required-package: samba-common-bin
  login-formats: %U
  login-policy: allow-realm-logins 

远程登录Head节点

通过 pcluster status -c ~/.parallelcluster/config.sin.u20 u20-cluster 命令,获取到公网IP。

binc@12345678b1fb ~ % pcluster status -c ~/.parallelcluster/config.sin.u20 u20-cluster
Status: CREATE_COMPLETE
MasterServer: RUNNING
MasterPublicIP: 13.214.17.226
ClusterUser: ubuntu
MasterPrivateIP: 10.0.0.123
ComputeFleetStatus: RUNNING 
binc@12345678b1fb ~ % ssh awsabc.cn\\Administrator@13.214.17.226  

awsabc.cn\Administrator@13.214.17.226's password: 
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.8.0-1041-aws x86_64)
...
administrator@ip-10-0-0-123:/$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
spot*        up   infinite    300  idle~ spot-dy-c5large-[1-300] 

提交作业

从命令的执行情况,我们可以看到:

  • 使用pre_install script安装AD 相关软件包相对比较费时间,约为5分钟才能完成机器的初始化。这里,可以通过预先打包依赖软件的方式减少初始化时间;
  • 作业是以当前登录用户提交到Slurm中。

集群用户管理

您可以使用亚马逊云科技建议的方法[3]来管理您的用户和组,也可以使用如下方法。

Kerberos登录

kinit Administrator

查看本地ticket

klist

列出当前域中所有用户

net ads user -S awsabc.cn

添加用户

使用net命令:

net ads user ADD johndoe Password123! -C "John Doe" -S awsabc.cn

搜索用户

net ads search '(objectCategory=user)' -S awsabc.cn

设置密码并启用用户

新添加的用户默认处于禁用状态,此时userAccountControl的值为514,我们需要给用户设置登录密码,并调整 userAccountControl为512,以启用此用户。

修改过程如下:

首先,创建一个ldif文件,包含需要新增或修改的属性:

sudo vi uac.ldif

dn:    CN=johndoe,CN=Users,DC=awsabc,DC=cn
changetype:    modify
replace:     userAccountControl
userAccountControl:    512
-
replace: userPassword
userPassword: yourPassword 

其次,执行如下命令,完成userAccountControl以及userPassword的修改:

ldapmodify -h awsabc.cn -p 389 -D cn=Administrator,cn=Users,dc=awsabc,dc=cn -w YourAdminPassword -f uac.ldif

设置用户家目录

首先,我们创建一个ldif文件,包含增加homeDirectory属性的命令:

sudo vi uac-home.ldif

dn:    CN=johndoe,CN=Users,DC=awsabc,DC=cn
changetype:    modify
add: homeDirectory
homeDirectory: /efs/home/johndoe 

其次,执行如下命令,完成homeDirectory属性的变更:

ldapmodify -h awsabc.cn -p 389 -D cn=Administrator,cn=Users,dc=awsabc,dc=cn -w YourAdminPassword -f uac-home.ldif 

最后,我们通过如下命令,在homeDirectory指定的路径,创建文件夹。

sudo mkhomedir_helper johndoe@awsabc.cn

确认家目录正常

如上图所示,我们通过执行pwd、mount及id命令,确认用户家目录使用的是EFS。

完整命令

这里,我们通过Shell脚本,快速完成用户的增加及初始化工作。内容如下:

#!/bin/bash

set -x

if [ "$EUID" -ne 0 ]; then
    echo "Please run as root"
    exit
fi

if [ "$#" -lt 2  ]; then
    echo "usage: $0 <username> <password> <display name>"
    exit
fi

DCs=""
DNSDN=`dnsdomainname`
function parse_domain_name {
    DCs=""
    IFS=.
    for item in $DNSDN;
    do 
        DCs="${DCs},DC=${item}"
    done
}

parse_domain_name

read -s adminPsw

echo "${adminPsw}"  | kinit Administrator
net ads user ADD "$1" "$2" -C "$1" -S "$DNSDN"

cat <<EOF > /tmp/uac.ldif
dn:    CN=$1,CN=Users${DCs}
changetype:    modify
replace:     userAccountControl
userAccountControl:    512
-
replace: userPassword
userPassword: $2
-
add: homeDirectory
homeDirectory: /efs/home/$1
EOF

ldapmodify -h "$DNSDN" -p 389 -D cn=Administrator,cn=Users"${DCs}" -w Mypassword1234 -f /tmp/uac.ldif

sleep 2
mkhomedir_helper $1@${DCs} 

清理资源(可选)

您可以清理ParallelCluster集群、EFS及Simple AD,以防止产生额外费用。

清理ParallelCluster

pcluster delete -c ~/.parallelcluster/config.sin.u20 &lt;cluster name&gt;

清理EFS及Simple AD

对于EFS及Simple AD来说,您可以到对应的控制台,执行删除操作。

FAQ & 问题排查

DNS是如何管理的?

ParallelCluster会自动创建一个私有的Route53 托管域,在修改完VPC的DHCP选项集之后, Simple AD会自动将DNS请求转发给Amazon为您VPC提供的DNS服务器,这些服务器会解析私有Route53 托管域中的域名,详细见文档[4]。

如果堆栈创建失败怎么办?

可以通过EC2控制台或者Terminal,登陆到Head 节点,查看/var/log/中的log文件。

我们在pre/post install script中,插入了存档log的逻辑,对应pre-install.log 及 post-install.log,如:

exec > >(tee /var/log/post-install.log|logger -t user-data -s 2>/dev/console) 2>&1 

cfn-init.log

查看当前CloudFormation执行到了哪一步,据此,分析应该查看的log文件。如:

2021-08-25 12:33:08,155 [INFO] Running config shellRunPreInstall
2021-08-25 12:33:08,155 [DEBUG] No packages specified
2021-08-25 12:33:08,155 [DEBUG] No groups specified
2021-08-25 12:33:08,155 [DEBUG] No users specified
2021-08-25 12:33:08,155 [DEBUG] No sources specified
2021-08-25 12:33:08,155 [DEBUG] No files specified
2021-08-25 12:33:08,156 [DEBUG] Running command runpreinstall
2021-08-25 12:33:08,156 [DEBUG] No test for command runpreinstall
2021-08-25 12:36:20,474 [INFO] Command runpreinstall succeeded 

pre-install.log

如果已经进入到pre install阶段,可以查看此log,排查script执行情况。

post-install.log

如果已经进入post install 阶段,可以查看此log,排查script执行情况。

cloud-init-output.log

cloud-init-output日志文件 (/var/log/cloud-init-output.log) 会捕获控制台的输出,因此如果实例未按您预期的方式运行,则可以在实例启动后调试脚本。

EFS挂载失败

在/var/log/chef-client.log文件中,可以观察到类似 STDERR: mount.nfs4: Failed to resolve server fs-a100bfe1.efs.ap-southeast-1.amazonaws.com: No address associated with hostname的记录,表示EFS DNS解析失败了。

您可以排查下DHCP选项集中,DNS 服务器的IP顺序是否正确。可以尝试在Head节点中,依次执行nslookup来判断。如:

ubuntu@ip-10-0-0-210:~$ nslookup fs-bc45c1fc.efs.ap-southeast-1.amazonaws.com 10.0.45.230
Server:		10.0.45.230
Address:	10.0.45.230#53

Non-authoritative answer:
*** Can't find fs-bc45c1fc.efs.ap-southeast-1.amazonaws.com: No answer

ubuntu@ip-10-0-0-210:~$ nslookup fs-bc45c1fc.efs.ap-southeast-1.amazonaws.com 10.0.0.4
Server:		10.0.0.4
Address:	10.0.0.4#53

Non-authoritative answer:
Name:	fs-bc45c1fc.efs.ap-southeast-1.amazonaws.com
Address: 10.0.0.106 

可以看到第一个DNS IP未成功返回查询结果,第二个IP正常。则,您应把第二个IP放在DHCP选项集的首位。

或者,(不推荐,可能导致跨区域流量费)您也可以在Simple AD所使用的另一个AZ,为EFS创建挂载点:

aws efs create-mount-target --file-system-id fs-xxx--subnet-id subnet-xxx  --region ap-southeast-1

然后,等待约5分钟,重新执行DNS查询。

[1] VPC快速创建模板 https://raw.githubusercontent.com/awslabs/aws-cloudformation-templates/master/aws/services/VPC/VPC_With_Managed_NAT_And_Private_Subnet.yaml

[2]  Parallel Cluster 创建自定义AMI https://docs.thinkwithwp.com/parallelcluster/latest/ug/tutorials_02_ami_customization.html#modify-an-aws-parallelcluster-ami

[3] 管理 Simple AD用户和组https://docs.thinkwithwp.com/directoryservice/latest/admin-guide/simple_ad_manage_users_groups.html

[4] 配置Simple AD DNS https://docs.thinkwithwp.com/directoryservice/latest/admin-guide/simple_ad_dns.html

本篇作者

陈斌

AWS解决方案架构师,负责基于AWS云计算方案的架构咨询与设计,具有丰富的解决客户实际问题的经验,目前关注深度学习的研究与应用。