Macbook Airにて、Paralles Desktop 18に４台のUbuntu20.04仮想マシンをインストールして、SLURM環境を構築してみた。

以前、古いMacbook ProとParalles Desktop 12を使って、４台のCentOS 7の仮想マシンをインストールし、SLURM環境を構築してみました。
過去の記事：CentOS７版↓）
https://qiita.com/believeriver/items/cef880b9c9b9a19e4ce9

今回は、MacBook Air M2チップを購入したので、Paralles Desktop 18を使って同様の環境構築を検討しました。
CentOS 7のサポートが2024年６月に終了することもあり、今回はUbuntu 20.04(LTS)を使って、同様のSLURM動作環境を構築してみることにします。

# 目次
- 作業環境
- SLURMの構成
- Ubuntuのインストール
- Ubuntuの環境設定（NFS,LDAP認証,SSHノンパス設定など）
- SLURMインストール
- SLURMクラスタ(Partition)設定
- ジョブ投入テスト
- まとめ

# 作業環境
- Macbook Air M2 2022
- Paralles Desktop 18
- Ubuntu 20.04.5(LTS Foscal Fossa)Daily Build

# SLURMの構成
今回構築するSLURMの構成は以下の通りです。
|hostname|SLURM役割|仮想マシン|備考|
|:---|:---|:---|:---|
|ubuntu|SLURMヘッドノード|Ubuntu|SLURMの管理サーバ|
|node1|SLURM node1 |Ubuntu|計算ノード|
|node2|SLURM node2 |Ubuntu|計算ノード|
|node3|SLURM node3 |Ubuntu|計算ノード|

パーティション構成を以下のようにします。
パーティションを構築することで、ジョブ投入時に選別される計算ノードをグループ化することができます。
|パーティション名|グループ化されるノード|備考|
|:---|:---|:---|
|Debug|ubuntu|管理ノードの死活監視|
|cluster1|node1 |node1のみ|
|cluster2|node2, node3|node2,node3から割り当て|

# Ubuntuのインストール
MacBook Air M2チップは、ARMのインストーラが必要です。以下のサイトより、Ubuntu20.04(LTS　Focal Fossa) をダウンロードしておきましょう。リンクはDesktop版ですが、Server版でも問題はないかと思います。
https://cdimage.ubuntu.com/focal/daily-live/current/

Paralles Desktop 18は、Ubuntuのダウンロードからインストールまで、自動でできるようにはなっていますが、4台インストールする過程で、同じダウンロードを４回するのは無駄なので、ダウンロードは一回にしました。

# Ubuntuの環境設定（NFS,LDAP認証,SSHノンパス設定など）
### ネットワークコマンドのインストール

初期インストールの状態では、Linuxのネットワークコマンドであるifconfigが使えないようです。そこで、net-toolsをインストールしましょう。
```
# sudo apt install net-tools
```

### ホスト名の名前解決設定
次に、デフォルトインストールでは、すべてのノードのホスト名が「ubuntu」になっているようなので、ホスト名をそれぞれSLRUM構成に合わせて変更しましょう。
```
# hostnamectl set-hostname node1
# hostnamectl set-hostname node2
# hostnamectl set-hostname node3
```

ヘッドノードの　/etc/hosts ファイルにSLURM構成をする計算ノードのホスト名とIPアドレスを登録しましょう。（IPアドレスはそれぞれの環境に合わせて修正ください）
```
10.xxx.yyy.1	 ubuntu
10.xxx.yyy.2     node1
10.xxx.yyy.3     node2
10.xxx.yyy.4     node3
```

### openSSHのインストール
すべてのホストにおいてSSH通信ができるようにopensshをインストールします。
```
# sudo apt update
# sudo apt install -y openssh-server
# sudo systemctl enable ssh
# sudo systemctl start ssh
```

管理ノードから各計算ノードに対して、rootユーザによるSSHログインができるようにしておきます。各計算ノード　node1~node3にて以下の手順を実施します。
```
# sudo vi /etc/ssh/sshd_config
以下２つを修正する
PermitRootLogin yes
PasswordAuthentication yes

修正したら、sshデーモンを再起動する
# sudo systemctl restart ssh

rootのパスワードを再作成する
# sudo passwd root
# New passwd:********(任意）
# Retry New passwd:********（任意）
```

完了したら、ヘッドノードからsshログインができるかを確認する
```
# ssh root@node1
# ssh root@node2
# ssh root@node3
```

### hostsファイルの共有（配布）

次に、管理ノードで作成した /etc/hosts を他の全ての計算ノードに配布して、ホスト名とIPアドレスを共有しましょう。シェルを使います。（元々のhostsもhosts.org.としてバックアップをしてから、配布します。最後に、ls コマンドでチェックします。
```
#!/usr/bin/bash

for n in node{1..3}
do
	printf "%s: " $n
	ssh $n hostname
	ssh $n cp /etc/hosts /etc/hosts.org.
	scp -p /etc/hosts $n:/etc/

	ssh $n ls -l /etc/ | grep hosts
done
	echo " "
```

### rootでのSSHノンパス設定
今後の作業効率を高めるため、SLURM管理ノード（ホスト名：ubuntu)からrootでノンパスワードでSSHログインできるようにします。
まず、ubuntuでrootユーザになるには、「sudo su -」と入力します。
```
guset@ubuntu:~$ sudo su -
[sudo] password for guest:*ルート権限のパスワード* 
root@ubuntu:~# 
```
SSH公開鍵認証によるノンパス設定を行います。以下の通り、鍵ペアの作成および公開鍵の配布を行います。
```
# 管理サーバで鍵を作る（パスフレーズはなしでEnterでOK）
ssh-keygen -t rsa -b 4096

# リモート（計算ノード）へ公開鍵を転送する
ssh-copy-id -i ~/.ssh/id_rsa.pub root@node1
ssh-copy-id -i ~/.ssh/id_rsa.pub root@node2
ssh-copy-id -i ~/.ssh/id_rsa.pub root@node3
```
以上で、SSHノンパスワード設定は完了です。

注意）公開鍵の配布は、ssh-copy-id コマンドが便利で概ねうまくいきます。
しかし、たまにうまくいかないことがあるので、その場合はクライアントの.ssh/authorized_keysにホストの公開鍵を書き込む必要がありますので、以下の手順も参考にしてください。
https://qiita.com/ir-yk/items/af8550fea92b5c5f7fca

### NFSによるホームディレクトリの共有
並列計算環境の模擬のため、ヘッドノードのhomeディレクトリをNFSにより各計算ノードからマウントします。これにより、並列計算のジョブを実行時のために各計算ノードに同じファイルを転送する必要がなくなります。

SLURMとして必須な設定ではないのですが、今回の目的の一つが並列計算機の環境構築という点もあるので実施しておきます。

CentOSは、ホスト側にnfs-serverを入れるだけでよかった気がするのですが、ubuntuは初めてでしたので、下記サイトの手順を参考にさせていただきました。
参考１）https://changineer.info/vmware/hypervisor/vmware_ubuntu_nfs.html
参考２）https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nfs-mount-on-ubuntu-20-04-ja

これをベースに、今回はダイレクトに/homeをNSFで共有します。これは、ユーザのホームディレクトリを共有するためです。ジョブを投入するユーザのファイルを計算機で共有するのです。

それでは、まずホストサーバ（管理サーバ）側で、nfs-kernel-serverの環境構築をします。
```
# sudo apt install nfs-kernel-server
# sudo vi /etc/exports
( /etc/exports に以下の１行を追記して、クライアントからのマウントを許可します。xxx, yyyはそれぞれの環境に合わせて読み替えてください。　）
/home               10.xxx.yyy.0/24(rw,no_root_squash)
```

次にクライアントマシン（計算ノード）側で、nfs-commonのインストールと設定をします。複数マシンがあるので、以下のようなシェルでインストールからマウントまでをまとめて行いましいた。
```
#!/usr/bin/bash

for n in node{1..3}
do
	printf "%s: " $n
	ssh $n hostname
	ssh $n sudo apt install -y nfs-common
	ssh $n mount ubuntu:/home /home
	ssh $n df -h 
done
	echo " "
```
クライアント側では起動時にマウントするように、/etc/fstab も修正しておきます。
```
# sudo vi /etc/fstab
(/etc/fstab に次の１行を追記します）
ubuntu:/home /home nfs defaults 0 0
```

これで、NFSによるファイル共有の設定は完了です。

### ユーザ認証サーバの構築
ヘッドノードを認証サーバとして、各計算ノードのユーザ情報を共有します。並列計算機では、多数の計算ノードでユーザ情報を共有することになるので認証サーバの構築はマストですね。
認証サーバには大きく分けて２つあると思います。
- NIS
- LDAP

NISは認証サーバとして古い仕組みですが、私が業務で管理している並列マシンでは、まだNISが使われています。ゆえに、以前の記事にてCentOS７を用いて自宅に並列計算機のテスト環境を構築した時は、NISで認証サーバを構築しました。

将来的にはLDAPにしていかないといけないだろうと予測し、自分の勉強のためにも今回はLDAPで認証サーバの構築を行いました。
手順としては、次のサイトを参考にさせていただきました。
- https://www.kwbtblog.com/entry/2019/08/28/162233
- https://www.server-world.info/query?os=Ubuntu_20.04&p=openldap&f=1
- https://qiita.com/cffnpwr/items/be903005e291d0ece514

#### LDAPサーバインストール
まずはSLURMの管理サーバ（ホスト名：ubuntu)をLDAPサーバにしようと思いますので、LDAPサーバの関連ソフトウェアをインストールします。
```
# sudo apt -y install slapd ldap-utils
```
インストール後のLDAPの初期設定はこんな感じでした。「slapcat」で確認できます。
```
root@ubuntu:~/work/setting-sys# slapcat
dn: dc=nodomain
objectClass: top
objectClass: dcObject
objectClass: organization
o: nodomain
dc: nodomain
structuralObjectClass: organization
entryUUID: 17ff3ede-015b-103d-8cd1-3b7899dafdee
creatorsName: cn=admin,dc=nodomain
createTimestamp: 20221125222021Z
entryCSN: 20221125222021.060537Z#000000#000#000000
modifiersName: cn=admin,dc=nodomain
modifyTimestamp: 20221125222021Z

dn: cn=admin,dc=nodomain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9RmJvRDcxOVJmUjRmT1F4a09leEVrU0tQc1RzOU8xYXk=
structuralObjectClass: organizationalRole
entryUUID: 17ff54c8-015b-103d-8cd2-3b7899dafdee
creatorsName: cn=admin,dc=nodomain
createTimestamp: 20221125222021Z
entryCSN: 20221125222021.061106Z#000000#000#000000
modifiersName: cn=admin,dc=nodomain
modifyTimestamp: 20221125222021Z
```
ドメインが nodomain なのでこの辺りを含めて修正していきます。
```
sudo dpkg-reconfigure slapd
```
このあとは、実際はコマンドラインではなくて、BIOSのような画面で設定いくことになりますが、私の設定入力は次のようにしました。
```
DNS domain name?: beleiveriver.com
Organization name?: beleiveriver
Administrator password?: ******(再設定が必要です。任意でOK）
```
このあとは、全てEnterで設定を完了します。もう一度、「slapcat」で設定を確認すると、domainなどが変わっていることがわかります。
```
root@ubuntu:~/work/setting-sys# slapcat
dn: dc=believeriver,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: believeriver
dc: believeriver
structuralObjectClass: organization
entryUUID: 101f16fc-015c-103d-8530-71017421fcf7
creatorsName: cn=admin,dc=believeriver,dc=com
createTimestamp: 20221125222717Z
entryCSN: 20221125222717.344186Z#000000#000#000000
modifiersName: cn=admin,dc=believeriver,dc=com
modifyTimestamp: 20221125222717Z

dn: cn=admin,dc=believeriver,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9WE8yN0dBeWtrVGExZXJraCtLNDRQNzhXdHNZM2hueG0=
structuralObjectClass: organizationalRole
entryUUID: 101f2e3a-015c-103d-8531-71017421fcf7
creatorsName: cn=admin,dc=believeriver,dc=com
createTimestamp: 20221125222717Z
entryCSN: 20221125222717.344792Z#000000#000#000000
modifiersName: cn=admin,dc=believeriver,dc=com
modifyTimestamp: 20221125222717Z
```

次に、UserやGroupを作成します。「base.ldif」という設定ファイルを作成しますが、作業場所はどこでも良いようです。私は、適当に「work」というディレクトリを作って、そこに設定ファイルを作りました。私の「base.ldif」の内容は以下の通りです。
```
# vi base.ldif

dn: ou=people,dc=believeriver,dc=com
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=believeriver,dc=com
objectClass: organizationalUnit
ou: groups
```
ファイルを作成したら、LDAPサーバに設定を読み込ませます。
```
# ldapadd -x -D cn=admin,dc=believeriver,dc=com -W -f base.ldif
Enter LDAP Password: 
adding new entry "ou=people,dc=believeriver,dc=com"

adding new entry "ou=groups,dc=believeriver,dc=com"
```
adding new entryが返ってくればOKです。

次にユーザを登録してみましょう。
まず前提として、管理サーバ（ホスト名：ubuntu)にて通常の「adduser」にて新規ユーザを作成しておきましょう。（/etc/passwd に登録されるやつです。）。今回は「user1」というアカウントを作成します。
```
root@ubuntu:~# adduser user1
Adding user `user1' ...
Adding new group `user1' (1001) ...
Adding new user `user1' (1001) with group `user1' ...
Creating home directory `/home/user1' ...
Copying files from `/etc/skel' ...
New password: 
Retype new password: 
passwd: password updated successfully
Changing the user information for user1
Enter the new value, or press ENTER for the default
	Full Name []: 
	Room Number []: 
	Work Phone []: 
	Home Phone []: 
	Other []: 
Is the information correct? [Y/n] y
root@ubuntu:~# 
```
これで、管理サーバにてユーザ作成できました。
これをLDAPサーバにユーザ登録します。LDAP登録するための設定ファイルを作成して、コマンドでLDAPサーバに読み込ませるという手順になります。
設定ファイルにはパスワード（ハッシュ値）を記入する必要があるので、先ほど作成したuser1のパスワードのハッシュ値を「slappasswd」でこれを確認しましょう。
```
# slappasswd
New password: 
Re-enter new password: 
{SSHA}　＊パスワードのハッシュ値が表示される＊
```
SSHAのところは、適当なパスワードに対するハッシュ値です。これをメモして、設定ファイル「ldapuser.ldif」の"userPassword:"に記載します。

次に、管理サーバで作成してした「user1」のUIDとGIDを確認します。
```
# id user1
uid=1001(user1) gid=1001(user1) groups=1001(user1)
```

これで、「user1」をLDAPサーバに登録するたに必要な情報が揃いました。これを使って設定ファイルを作成します。今回の設定ファイルは以下の通りです。
```
# vi ldapuser.ldif
dn: uid=user1,ou=people,dc=believeriver,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: user1
sn: ubuntu
userPassword: {SSHA}＊先ほどメモしたパスワードハッシュ値を入力＊
loginShell: /bin/bash
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/user1

dn: cn=user1,ou=groups,dc=believeriver,dc=com
objectClass: posixGroup
cn: user1
gidNumber: 1001
memberUid: user1
```

設定ファイルができたら、コマンド「ldapadd」を使ってLDAPサーバにユーザを登録します。
```
# $sudo ldapadd -x -D cn=admin,dc=believeriver,dc=com -W -f ldapuser.ldif
Enter LDAP Password: 
adding new entry "uid=user1,ou=people,dc=believeriver,dc=com"

adding new entry "cn=user1,ou=groups,dc=believeriver,dc=com"
```
adding new entryが出ればOKです。
「ldap_bind: Invalid credentials (49)」が出るとエラーです。私の場合は、dcで指定するドメイン名のスペルミスでエラーが出ることがありました。また、文末にスペースが入っているなど、シンタックスエラーが多いです。

また、間違った場合にユーザを削除した時は「ldapdelete」を使います。

ldapサービス（「sldapd」)の自動起動と、サービスが起動していることを確認しておきましょう。
```
systemctl enable slapd
systemctl start slapd
systemctl status slapd
```
これでLDAPサーバにユーザの登録が完了しました。

##### (*** 補足 ***)
LDAPサーバへのユーザ登録を間違えた場合は、以下のコマンドで削除できます。
```
(UIDの削除)
$ ldapdelete -x -W -D cn=admin,dc=believeriver,dc=com uid=user1,ou=people,dc=believeriver,dc=com

(GIDの削除)
$ ldapdelete -x -W -D cn=admin,dc=believeriver,dc=com cn=user1,ou=groups,dc=believeriver,dc=com
```


### LDAPクライアントのインストール
各計算ノードにLDAPクライアントをインストールしていきます。
まずは計算ノード（ホスト名：node1)にて実施します。
```
apt install -y libnss-ldapd libpam-ldapd ldap-utils
```

このあとは、ldapサーバの設定を入力する画面に移ります。実際はコマンドラインではなくて、BIOSのような画面で設定いくことになりますが、私の設定入力は次のようにしました。
```
LDAP server Uniform Resource Identifier: ldap://10.xxx.yyy.zz
＊ここは、LDAPサーバのIPアドレス
*名前解決ができるならホスト名でもたぶん大丈夫。

Distinguished name of the search base: dc=believeriver,dc=com

Name services to configure:                                               |
 |                                                                           |
 |    [*] passwd                                                             |
 |    [*] group                                                              |
 |    [*] shadow 
```
完了したら、１回再起動します。
```
# reboot
```

これで、LDAPサーバ(管理サーバ、ホスト名：ubuntu)で作成・登録した　user1 で、計算ノード（ホスト名：node1）にログインができるのか確認しましょう。
```
user1@ubuntu:~$ ssh node1
The authenticity of host 'node1 (10.211.55.5)' can't be established.
ECDSA key fingerprint is SHA256:1+8+MChVItVqMDu5BJVfhBVkqyR4W2OXeOXiWm44W8c.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'node1,10.211.55.5' (ECDSA) to the list of known hosts.
user1@node1's password: 

user1@node1:~$
```
うまくいきました！　念の為、LDAPサーバとクライアントでのUID、GIDも一致しているか確認しておきましょう。
```
user1@ubuntu:~$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1)
user1@node1:/$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1)
```
一致していますね！うまくいっているようです。

残りの計算ノード　node2, node3 にも、LDAPクライアントのインストールと設定をやっていきましょう！

##### (*** 補足 ***)
注意1）今回、/home は、管理サーバ（ubuntu)をマウントしているため、計算ノードでのhomeディレクトリの作成は不要です。

注意２）LDAPサーバ側でユーザ情報を削除・修正などした場合、もしLDAPクライアント側に反映されていない場合は、クライアントを再起動するか、クライアントのデーモンを以下のように再起動してみましょう。
```
# systemctl restart nscd
```
注意２）LDAPクライアントで、「user1」でログインできないときは、nslcdの設定ミスがあるかもしれません（IPアドレスやドメイン名など）
その場合は、/etc/nslcd.conf の　uri, base の設定を確認してスペルミスなどないかをチェックしましょう。
```
# ssh node1 cat /etc/nslcd.conf

# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.

# The user and group nslcd should run as.
uid nslcd
gid nslcd

# The location at which the LDAP server(s) should be reachable.
uri ldap://10.xxx.yyy.1

# The search base that will be used for all queries.
base dc=believeriver,dc=com

# The LDAP protocol version to use.
#ldap_version 3

# The DN to bind with for normal lookups.
#binddn cn=annonymous,dc=example,dc=net
#bindpw secret

# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com

# SSL options
#ssl off
#tls_reqcert never
tls_cacertfile /etc/ssl/certs/ca-certificates.crt

# The search scope.
#scope sub

```

クライアント側の設定についてあまり細かいところはしていませんが、こちらも参考になりました。
https://web.chaperone.jp/w/index.php?LDAP/Client/ubuntu


### userでのSSHノンパス設定
ユーザでSSHノンパス設定を行う方法としては、大きく次の２つがあります。
- ユーザでSSH公開鍵認証を行う
- ホストベース認証を行う

ユーザでSSH公開鍵認証を行う場合は、rootでSSHノンパス設定をした手順と全く同じです。rootでの手順を参考に、各ユーザにてホストで鍵ペアの作成とクライアントへの公開鍵配布を実施します。

ホストベース認証というのは、その名の通りホスト間の認証設定になります。ホスト間で認証しておけば、ユーザは何も設定せずともホスト間のSSHノンパスログインが可能となります。

今回は、ユーザも公開鍵認証にてノンパス設定することとしますので、rootでの公開鍵認証設定をユーザで実施しておきます。

鍵ペア作成はパスフレーズなしでOK。
```
user1@ubuntu:~$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user1/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user1/.ssh/id_rsa
Your public key has been saved in /home/user1/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:Kd9yFKlkzUklYpJE/PFLglKFEKo2bp7TWRsM7wWuEcM user1@ubuntu
The key's randomart image is:
+---[RSA 4096]----+
|    o*+++ o..    |
|   .  =o.= +     |
|  o  . ooo*      |
| . E...oooo.     |
|.o  B.o So..     |
|o .. * + o.      |
| o. * + o o      |
|o..+ o   o       |
| o.              |
+----[SHA256]-----+
```
次に、公開鍵の配布を行います。実は、今回のクライアントへの鍵配布は１回だけでOKです。
管理ノードのホームディレクトリは計算ノードからマウントされているので、同じ.ssh/authorized_keysを参照することになるのです。（つまり、自分で自分の鍵を確認する、ということになるのですね。）
```
user1@ubuntu:~$ ssh-copy-id -i ~/.ssh/id_rsa.pub user1@node1
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user1/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
user1@node1's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'user1@node1'"
and check to make sure that only the key(s) you wanted were added.
```
これにより、ユーザでは管理ノード、計算ノード（node1,node2,node3)の相互のSSHノンパス設定が完了します。

並列計算機ではMPIなどによる並列計算のため、計算ノード間での相互のSSHノンパス設定は必須になります。（実行ユーザレベルでOK）

ホストベース認証よりも簡単に正確に実施できるので、ユーザ作成時にSSH公開鍵認証設定を行うのがベターかなと思います。

（　ちなみにrootではそうはなりません。root領域をマウントすることはできませんので。。。）


# SLURMのインストール
Ubuntu 20.0４へのSLURMインストール手順は、下記記事を参照して1台構成のSLURM構築が可能です。AWSですが OSはUbuntu20.０４ですので、Munge,SLURMともに問題なくインストールしてテスト実行も行うことができます。
下記記事を参照いただき、ヘッドノードと全計算ノードにSLURM（slurm-20.11.x）をインストールしてください。slurmctldは、ヘッドノードのみで起動しますので、計算ノードでのslurmctldの起動は不要です。
UbuntuへのSLURMインストール手順）https://qiita.com/daikumatan/items/f59999ce4e85a580c63d

注意点としては、上記の手順でインストール可能なSLURMのバージョンは”slurm-20.11.x”までのようです。２０２２・１１現在の最新版"slurm-22.05.x"を試したところうまくいきませんでした。バージョンによって手順の見直しが必要なようです。

(CentOSで構築した時は、あちこちのサイトから情報を集めて、なんとか起動して実行までこぎつけましたが、Ubuntu　１台の構成ではあるものの、この記事手順で簡単にインストールできて、非常に助かりました。感謝です。)

それでは、上記記事を参考とさせていただき、今回必要な部分をサクッとメモしておきます。

#### mungeのインストール
mungeのインストールはaptで可能なので、とても簡単です（バージョンを選んでいない点は少し気になりますが、CentOSではmungeもパッケージダウンロードとコンパイルが必要だったので、かなり助かります。。）
```
sudo apt update
sudo apt install -y munge libmunge-dev
```


#### slurmのインストール
前提としてのコンパイラインストール
```
root@node1:/home# sudo apt install -y build-essential

Reading package lists... Done
Building dependency tree       
Reading state information... Done
build-essential is already the newest version (12.8ubuntu1.1).
build-essential set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 8 not upgraded.
```

```
root@node1:~# gcc --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

SLURMパッケージのダウンロード。ここでは最新ではなく、slurm-20.11.x です。（最新版は、この手順では失敗するようです。）
```
root@node1:/home# wget https://download.schedmd.com/slurm/slurm-20.11.9.tar.bz2
```
ファイルを展開します。
```
root@node1:/home# tar -jxvf slurm-20.11.5.tar.bz2
root@node1:/home# ls
slurm-20.11.9  slurm-20.11.9.tar.bz2
```
展開したファイルをコンパイルします。mungeの実行パスをつけることがポイントのようです。
```
root@node1:/home# cd /home/slurm-20.11.9
root@node1:/home/slurm-20.11.9# munge_dir=$(which munge)
root@node1:/home/slurm-20.11.9# ./configure --with-root@node1:/home/slurm-20.11.9# munge="${munge_dir%/munge}"
root@node1:/home/slurm-20.11.9# make
```
注意）SLURMのパッケージのダウンロードとコンパイル作業は１回しておけば、あとはコンパイル後のモジュールを他のノードに共有にてslurmのインストールができます。私は、すでにNFSで/home をマウントしているので、管理ノードでコンパイルしたモジュールを共有してインストールを行いました。


コンパイルが完了したら、slurmをインストールします。（環境によりますが、私の場合はインストール完了するまで５〜１０分くらいかかります）
```
sudo make install
```

インストールが完了したら、デーモン化（systemctlで管理できる）ようにしておきます。
```
HOME=/home (ここは、インストール先に合わせて変えてください）
sudo cp ${HOME}/slurm-20.11.9/etc/slurmctld.service /etc/systemd/system
sudo cp ${HOME}/slurm-20.11.9/etc/slurmd.service /etc/systemd/system
```

ここでは、SLURMのインストールまででOKです。コンフィグを作成しないと起動しないので、次のセクションでパーティションを定義してSLURMを起動します。


# SLURM起動
全ノードへのSLURMインストールが完了してからの手順から記載します。最終的にヘッドノードから、slurm.confを全ノードに配布して、slurmを再起動することで、クラスタの構成が完了します。

#### mungeの通信設定
管理ノードと各計算ノードの間で munge の通信ができるようにする必要があります。
まず、管理ノードで　munge.key があることを確認します。
```
root@ubuntu:/etc/munge# ls /etc/munge
munge.key
```
管理ノードの「munge.key」を各計算ノードに配布します。以下のシェルで元のmunge.keyはバックアップをとり、配布しています。配布後にmunge再起動して通信チェックしており、Successが出ればmunge通信設定完了です。
```
#!/usr/bin/bash

for n in node{1..3}
do
	printf "%s: " $n
	ssh $n hostname
    #元のmunge.keyファイルのバックアップ
	ssh $n cp /etc/munge/munge.key /etc/munge/munge.key.org
    #管理ノードからのmunge.key配布
	scp -p /etc/munge/munge.key $n:/etc/munge/munge.key

    #munge 再起動
	ssh $n systemctl restart munge

	ssh $n systemctl status munge | grep Active | awk '{print $2 $3}'
	ssh $n munge -n | ssh $n unmunge | grep STATUS | awk '{print $2 $3}'
done
	echo " "
```
うまくいけば、以下のような応答があります。
```
root@ubuntu:/home# ./send-munge-key 
node1: node1
munge.key                                                         100% 1024     3.1MB/s   00:00    
active(running)
Success(0)
node2: node2
munge.key                                                         100% 1024     2.9MB/s   00:00    
active(running)
Success(0)
node3: node3
munge.key                                                         100% 1024     3.2MB/s   00:00    
active(running)
Success(0)
```


#### slurm.conf作成・配布
slurm.confを作成していきます。
まず、「slurmd -C」コマンドにて管理ノード、計算ノードのステータスを確認します。
```
root@ubuntu:/home# slurmd -C

NodeName=ubuntu CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962
UpTime=0-02:28:42

node1: node1
NodeName=node1 CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962
UpTime=0-02:28:11
node2: node2
NodeName=node2 CPUs=1 Boards=1 SocketsPerBoard=1 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=963
UpTime=0-02:27:55
node3: node3
NodeName=node3 CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962
UpTime=0-02:27:50
```

それでは、この情報をもとに今回のslurm.confを作成しました。
```
# slurm.conf file generated by configurator easy.html.
# Put this file on all nodes of your cluster.
# See the slurm.conf man page for more information.
#
SlurmctldHost=ubuntu
#
#MailProg=/bin/mail
MpiDefault=none
#MpiParams=ports=#-#
ProctrackType=proctrack/pgid
ReturnToService=1
SlurmctldPidFile=/var/run/slurmctld.pid
#SlurmctldPort=6817
SlurmdPidFile=/var/run/slurmd.pid
#SlurmdPort=6818
SlurmdSpoolDir=/var/spool/slurmd
SlurmUser=root
#SlurmdUser=root
StateSaveLocation=/var/spool
SwitchType=switch/none
TaskPlugin=task/none
#
#
# TIMERS
#KillWait=30
#MinJobAge=300
#SlurmctldTimeout=120
#SlurmdTimeout=300
#
#
# SCHEDULING
SchedulerType=sched/backfill
SelectType=select/cons_tres
SelectTypeParameters=CR_Core
#
#
# LOGGING AND ACCOUNTING
AccountingStorageType=accounting_storage/none
ClusterName=cluster
#JobAcctGatherFrequency=30
JobAcctGatherType=jobacct_gather/none
#SlurmctldDebug=info
#SlurmctldLogFile=
#SlurmdDebug=info
#SlurmdLogFile=
#
#
# COMPUTE NODES
NodeName=ubuntu CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962 State=UNKNOWN
NodeName=node1 CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962 State=UNKNOWN
NodeName=node2 CPUs=1 Boards=1 SocketsPerBoard=1 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=963 State=UNKNOWN
NodeName=node3 CPUs=2 Boards=1 SocketsPerBoard=2 CoresPerSocket=1 ThreadsPerCore=1 RealMemory=962 State=UNKNOWN

#Partition
PartitionName=debug Nodes=ubuntu Default=NO MaxTime=10:00 State=UP
PartitionName=cluster1 Nodes=node1 Default=NO MaxTime=INFINITE State=UP
PartitionName=cluster2 Nodes=node[2-3] Default=NO MaxTime=INFINITE State=UP
```

このslurm.confファイルを管理ノードで作成し、各計算ノードに配布してslurmデーモンの起動を行います。
```
#!/usr/bin/bash

for n in node{1..3}
do
	printf "%s: " $n
	ssh $n hostname
	#管理ノードの「slurm.conf」を各計算ノードにコピー配布
	scp -p /usr/local/etc/slurm.conf $n:/usr/local/etc/slurm.conf

    #各計算ノードの「slurmd」を起動。初回なのでenableも実施。
	ssh $n systemctl enable slurmd
	ssh $n systemctl stop slurmd
	ssh $n systemctl start slurmd
	ssh $n systemctl status slurmd| grep  Active| awk '{print $2 $3}'
done
	echo " "

#管理ノードの「slurmctld, slurmd」を起動。初回なのでenableも実施。
sudo systemctl enable slurmctld slurmd
sudo systemctl stop slurmctld slurmd
sudo systemctl start slurmctld slurmd
sudo systemctl status slurmctld slurmd| grep  Active| awk '{print $2 $3}'
```

以下のように、Activeの応答があれば成功です。
```
root@ubuntu:/home# ./send-slurm-conf 
node1: node1
slurm.conf                                                        100% 1762     4.8MB/s   00:00    
active(running)
node2: node2
slurm.conf                                                        100% 1762     5.7MB/s   00:00    
active(running)
node3: node3
slurm.conf                                                        100% 1762     4.8MB/s   00:00    
active(running)
 
active(running)
active(running)
```

#### slurm起動確認
それでは、slurmが起動していることを「sinfo」コマンドで確認します。
```
root@ubuntu:/home# sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
debug        up      10:00      1   idle ubuntu
cluster1     up   infinite      1   idle node1
cluster2     up   infinite      2   idle node[2-3]
```
各PARTITIONのステータスが、idleになっていれば成功です。うまくいきました。

#### ジョブ投入テスト
それでは、「user1」でジョブ投入テストをしてみます。
sleepするだけのシェルを以下のように作成します。
```
#!/bin/sh
#SBATCH --job-name testjob
#SBATCH --partition=cluster2
#SBATCH --nodes=1
#SBATCH -o %x.%J.out
#SBATCH -e %x.%J.err

hostname
sleep 600
```
では、ジョブを投入してみます。ジョブ投入は「sbatch」コマンドを使用します。
```
user1@ubuntu:~$ sbatch run.sh
Submitted batch job 4
```
ジョブ実行状況を「squeue」コマンドで確認します。
```
user1@ubuntu:~$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 4  cluster2  testjob    user1  R       1:21      1 node2
```
node2 が選択されてジョブが実行されています。うまくいきました！


### 余談（SLURM DB）
本当は、さらにSLURMデータベースを構築してsacctが使用できるようにしていく必要があります。本記事が少々長くなったため、続きの記事としてSLURMデータベース構築を検証してまとめたいと思います。

（追記）
SLURMデータベースの設定手順もまとめました。思っていた以上に手こずりましたが、何とかデータベースも構成することができました。
URL）https://qiita.com/believeriver/items/9993c3730fed2a777d4a


# まとめ

今回、SLURMの実行環境を作るというのがテーマではあったものの、そもそも並列計算機の動作環境を一から構築してみようということで、NFS,LDAPなどの要素も含めてメモってきましたので、かなり長い記事になってしまいました。
最後まで読んでくださったかたは、お付き合いいただき、誠にありがとうございました。

今回、新しいParalles DesktopではCentOSがインストールできないというトラブルから、UbuntuでのSLURM環境構築をトライすることになりました。

やってみて、CentOSとの違いはあるものの、基本的な考え方や使いやすさは変わらないということを確認することができました。

また、並列計算機の運用管理を担当しているものとして、今後CentOSがサポート外となることはかなり大きなインパクトのある問題です。

RedHatとDebianとアーキテクチャが異なるものの、並列計算機としてもっともよく使われるソフトウェアの一つであるANSYSが、CentOS（Stream)のサポートはせず、Ubuntuのサポートに変わるという話もあります。
https://www.ansys.com/content/dam/it-solutions/platform-support/cent-os-support-announcement.pdf

ゆえに、Ubuntuへの移行は避けられないのでは、と予想していますので、今後も状況を観察しながら勉強と検証を進めていこうと思います。

# 参考サイト
今回の環境構築にあたり、主に参考にさせていただいたサイトを最後にまとめさせていただきます。
SSHノンパスワード設定）
- https://qiita.com/kazokmr/items/754169cfa996b24fcbf5
- https://qiita.com/ir-yk/items/af8550fea92b5c5f7fca

NFS）
- https://changineer.info/vmware/hypervisor/vmware_ubuntu_nfs.html
- https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nfs-mount-on-ubuntu-20-04-ja

LDAP)
サーバ
- https://www.kwbtblog.com/entry/2019/08/28/162233
- https://www.server-world.info/query?os=Ubuntu_20.04&p=openldap&f=1
- https://qiita.com/cffnpwr/items/be903005e291d0ece514

ユーザ登録
- https://www.server-world.info/query?os=Ubuntu_20.04&p=openldap&f=2
- https://qiita.com/cffnpwr/items/be903005e291d0ece514

クライアント
- https://www.server-world.info/query?os=Ubuntu_20.04&p=openldap&f=3
- https://qiita.com/cffnpwr/items/be903005e291d0ece514
- https://web.chaperone.jp/w/index.php?LDAP/Client/ubuntu

LDAPの項目の意味について
https://qiita.com/ryysud/items/2804ae10be25af4707a3


SLURM）
　- https://qiita.com/daikumatan/items/f59999ce4e85a580c63d
　- https://wiki.fysik.dtu.dk/Niflheim_system/Slurm_installation/
　- https://qiita.com/evakichi/items/265c218362b200c3bc3d
　- http://www-fps.nifs.ac.jp/ito/memo/slurm01.html