Try   HackMD

MPI Cluster 架構

  • 在一個 Cluster 中會有多台機器(電腦),稱為 node
    • 一個 node 當作 Manager (Master)
      • 分配運算工作給 nodes
    • 多個 nodes 當作 Woker (Slave)
      • 執行 manager 分配的運算工作
  • Nodes 間使用網路溝通,為了方便操作,通常會將每個 nodes 設定靜態 IP
  • OpenMPI 依賴兩種服務進行溝通
    • SSH:
      • 負責指令傳輸
      • Master 需要能免密碼登入到 worler
    • NFS:
      • 透過共用資料夾,進行資料傳輸
      • 所有 nodes 只要有一台當作 NFS-Server,其他 nodes 直接存取 server 的資料夾就好
      • 可以用 managerNFS-Server,worker 使用 NFS-Client 存取 manager 上的資料夾

用虛擬機建立 MPI Cluster

所以如果要用多台虛擬機上搭建一個 MPI Cluster,需要

  1. 建立多台虛擬機,安裝好 Linux
  2. 設定網卡
    • 為了方便設定和操作,網卡設定要符合以下條件
      • 為了可以下載套件,要能連上 Internet
      • 讓所有機器連上同個 LAN,並使用靜態 IP
      • 本機也可以連上所有虛擬機 (即本機也在同個 LAN)
    • 推薦的設定是每台機器都用兩張網卡,分別是 . . .
    • NAT:
      • 保證機器可以連上 Internet
      • 因為只是拿來上網,所以可以直接選用 DHCP
    • VirtualBox Host-Only (僅限主機介面卡)
      • 雖然 NAT 已經可以讓虛擬機互通,但是外部機器 (包括本機) 沒辦法連上
      • 如果使用 Host-Only 就可以讓本機可以連上虛擬機,所以我會在這張網卡設定靜態 IP
    • 為了方便,可以編輯 /etc/hosts,設定其他幾台機器的名稱和對應的 IP address
  3. 安裝必要套件
    • 編譯環境
      • GCC: build-essential (gcc, g++, gfortran, make)
      • OpenMPI: openmpi-bin, libopenmpi-dev, openmpi-doc
    • SSH
      • Open-SSH: openssh-client, openssh-server
    • NFS
      • Server (裝在 Manager): nfs-kernel-server
      • Client (裝在 Worker): nfs-common
    • 推薦套件
      • ifconfig: net-tools
  4. 設定 SSH 和 NFS
    • SSH
      • Manager 必須要能 無密碼登入 其他 nodes
      • 要在 manager 上產生一組 RSA Key,並複製給其他 nodes
    • NFS
      • 在 manager 上設定要共享出去的資料夾路徑
      • 在 workers 上掛載 manager 共享的資料夾

建立 MPI Cluster - 使用 Virtualbox 及 Ubuntu Server

  • 建立共有三個 nodes 的 cluster
    • 一個 manager node
    • 兩個 worker nodes
  • 建立虛擬機時,可以同時啟動三台虛擬機進行 Linux 安裝
  • 也可以先裝好一台,再用複製的方式,複製兩台虛擬機,減少下載套件的時間

關於 Linux 發行版

  • 不管使用哪種 Linux 發行版都可以執行 OpenMPI,可以用自己慣用的就好
  • 我用 Ubuntu 是因為我自己對 Ubuntu 比較熟
  • 用 Server 版是因為它佔用的額外資源比較少 (沒有 GUI)

建立多部虛擬機 並安裝 Linux

  • 下載 Linux ISO Image,我使用的是 Ubuntu Server
    https://ubuntu.com/download/server
  • 使用 Virtualbox 建立虛擬機
    • 因為筆電資源有限,可以選擇兩顆核心和 2G 記憶體就行
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
  • 啟用兩張網卡
    • 選擇要使用的機器,按 "設定"
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
    • 選擇網路
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
    • 點 "介面卡1",勾選 "啟用網路卡",並選擇附加到 NAT
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
    • 點 "介面卡2",勾選 "啟用網路卡",並選擇附加到 Host-only (僅限主機介面卡)
      Image Not Showing Possible Reasons
      • The image was uploaded to a note which you don't have access to
      • The note which the image was originally uploaded to has been deleted
      Learn More →
    • 按確定儲存設定
  • 安裝 Ubuntu Server
    • 安裝時不需要特別的設定,使用預設選項就行
    • 設定 Server's name (hostname) 時盡量讓每台機器有不同的名稱,以利辨識
      • 名稱沒有限制,方便自己辨識就行,我使用的名稱是 mpi-mgr, mpi-w0, mpi-w1
      • 不過 Hostname 也可以在安裝完成後修改,如果採用先裝好一台再複製的方法,可以在複製機器後修改
        Image Not Showing Possible Reasons
        • The image was uploaded to a note which you don't have access to
        • The note which the image was originally uploaded to has been deleted
        Learn More →
    • 安裝過程中可以勾選安裝 Open-ssh server
      • 如果沒裝到也沒關係,之後可以透過指令安裝
        Image Not Showing Possible Reasons
        • The image was uploaded to a note which you don't have access to
        • The note which the image was originally uploaded to has been deleted
        Learn More →

裝好 OS 之後就可以先關機,然後複製出其他幾台機器
也可以先安裝好所有 nodes 都必要的套件,再開始複製

安裝必要套件

共同套件

  • 列出的套件是所有 nodes 上都需要的套件
  • 下面指令可以一次安裝所有必要套件
  • 如果怕出錯可以一個一個分開安裝
    ​​​​sudo apt install \
    ​​​​    build-essential \
    ​​​​    libopenmpi-dev openmpi-doc \
    ​​​​    openssh-client openssh-server \
    ​​​​    net-tools
    

如果採用先裝一台,再複製出另外兩台的作法
可以在安裝完以上套件後就開始複製

Manager

  • 安裝 NFS server
  • 只需要安裝在 Manager
    ​​​​sudo apt install nfs-kernel-server
    

Workers

  • 安裝 NFS Client
  • 需要在所有 Worker 上安裝
    ​​​​sudo apt install nfs-common
    

Ubuntu 使用的套件管理工具是 apt
如果使用其他 Linux 發行版,使用的工具可能不同 (例: CentOS 使用 yum)
apt 換成對應管理工具的名稱就可以正常執行

設定 Hostname

  • 如果採用複製的方式,所有機器上的 hostname 會相同,不利於辨識
  • 編輯 /etc/hostname 設定檔,可以修改 hostname
    ​​​​sudo vim /etc/hostname
    ​​​​
    ​​​​或
    ​​​​
    ​​​​sudo nano /etc/hostname
    
  • 重新登入後可以看到 hostname 已經改變
  • Hostname 沒有特定規則,只要能讓自己方便辨識就好,我使用的是
    • Manager: mpi-mgr
    • Worker: mpi-w0, mpi-w1

設定網卡

  • ifconfig,查詢目前的網卡資訊
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
    • 通常 192.168 開頭的就是 Host-Only
    • 這邊我拿到的 IP address 是 192.168.34.125,遮罩是 255.255.255.0
      • 代表使用的子網路是 192.168.34.0/24
      • 每台電腦上的設定不一定相同 (不一定也是 192.168.34.0),操作時要依照自己的實際情況調整
    • 記下自己網卡的名稱和子網路,以我的為例
      • 網卡名稱: enp0s8
      • 子網路: 192.168.34.0/24
  • 根據我的子網路,我能使用的 IP address 必須是 192.168.34 開頭,也就是 192.168.34.XX
  • XX 可以自行決定,只要每一台機器不重複就可以
  • 但子網路中,通常有幾個位置是保留做特殊用途的,所以 XX 盡量避開
    • 0, 1, 100, 255
    • 且盡量使用 100 以下的數字 (2~99)
  • 我使用的設定如下
    • mpi-mgr: 192.168.34.40
    • mpi-w0: 192.168.34.41
    • mpi-w1: 192.168.34.42
  • 編輯 /etc/netplan/00-installer-config.yaml
    • 可以使用任何編輯器,例如 nanovim
    • 因為是系統設定檔,最前面記得加 sudo
      ​​​​​​​​sudo nano /etc/netplan/00-installer-config.yaml
      ​​​​​​​​
      ​​​​​​​​或
      ​​​​​​​​
      ​​​​​​​​sudo vim /etc/netplan/00-installer-config.yaml
      
    • 原先內容會類似這樣
      ​​​​​​​​# This is the network config written by 'subiquity'
      ​​​​​​​​network:
      ​​​​​​​​  ethernets:
      ​​​​​​​​    enp0s3:
      ​​​​​​​​      dhcp4: true
      ​​​​​​​​    enp0s8:
      ​​​​​​​​      dhcp4: true
      ​​​​​​​​  version: 2
      
    • 刪除 Host-Only 的 dhcp 設定,並加入靜態 IP 設定
      • 靜態 IP 的格式是
        ​​​​​​​​​​​​addresses: [ address1, address2, ... ]
        
      • 如果要把 IP 設定為 192.168.34.40
        ​​​​​​​​​​​​addresses: [ 192.168.34.40/24 ]
        
      • 完整檔案如下
        ​​​​​​​​​​​​# This is the network config written by 'subiquity'
        ​​​​​​​​​​​​network:
        ​​​​​​​​​​​​  ethernets:
        ​​​​​​​​​​​​    enp0s3:
        ​​​​​​​​​​​​      dhcp4: true
        ​​​​​​​​​​​​    enp0s8:
        ​​​​​​​​​​​​      addresses: [192.168.34.40/24]
        ​​​​​​​​​​​​  version: 2
        
  • 存檔後,執行下面指令,啟用新的設定
    ​​​​sudo netplan apply
    
  • ifconfig 確認是否拿到正確 IP
  • 按照上述步驟,分別設定好每一個 nodes 上的靜態 IP
  • 使用 ping 可以檢查設定是否成功
    • mpi-mgr,ping mpi-w0, mpi-w1
      ​​​​​​​​ping 192.168.34.41
      ​​​​​​​​ping 192.168.34.42
      
    • 最好在本機上也嘗試看看能不能 ping 到虛擬機

編輯 hosts 檔案

  • /etc/hosts 是 Linux 系統中的設定檔,可以紀錄機器的 IP 和對應的名稱
  • 設定好後,就可以用名稱代替該機器的 IP,方便設定和維護
  • 設定檔格式如下
    ​​​​<ip_address> <name>
    
  • /etc/hosts 加入以下內容
    ​​​​192.168.34.40 mpi-mgr
    ​​​​192.168.34.41 mpi-w0
    ​​​​192.168.34.42 mpi-w1
    
    • 就可以在指令中用名稱取代 IP
      ​​​​​​​​ping mpi-w0
      ​​​​​​​​
      ​​​​​​​​等同
      ​​​​​​​​
      ​​​​​​​​ping 192.168.34.41
      
  • 在所有 nodes 都進行以上設定

設定 SSH

  • 在 manager 中,嘗試用 ssh 登入其他 nodes
    ​​​​ssh user@mpi-w0
    
    • user 要換成你的使用者名稱,user 必須是存在於 mpi-w0 的使用者
    • 如果連線成功,先下 logout 登出,切換回 manager
  • 在 manager,切換到 ~,建立目錄 .ssh,並切換進去
    ​​​​cd ~
    ​​​​sudo mkdir .ssh
    ​​​​cd .ssh
    
    • .ssh 是隱藏資料夾,直接下 ls 是看不到的
      • ls -a 可以顯示隱藏資料夾
    • .ssh 可能已經存在,可以直接使用,不需要刪除
  • 產生 RSA Key,並把產出的檔案 id_rsa.pub,改名為 authorized_keys
    ​​​​ssh-keygen -t rsa
    ​​​​cp id_rsa.pub authorized_keys
    
    • 產生 RSA Key 時,會詢問一些資訊
    • 可以全部使用預設,一直按 enter 就好
  • 把 RSA key 複製給所有 worker
    ​​​​ssh-copy-id user@mpi-w0
    ​​​​ssh-copy-id user@mpi-w1
    ​​​​.
    ​​​​.
    ​​​​.
    
  • 再次使用 ssh 連線到其他機器
    ​​​​ssh user@mpi-w0
    
    • 如果不須要密碼就表示設定成功

設定 NFS

  • 在 manager 中,建立一個目錄,並修改權限,用來和所有 nodes 共享
    ​​​​cd ~
    ​​​​mkdir mpi
    ​​​​chmod 777 mpi
    
    • 目錄名稱及位置可以自行決定,不一定要和我一樣
  • 進入剛建立的目錄,下 pwd 取得完整路徑並複製
    ​​​​cd mpi
    ​​​​pwd
    
    • 以我的為例,目錄的路徑是
      ​​​​​​​​/home/pj/mpi
      
  • 編輯 NFS 設定檔,把剛剛的目錄共享給其他 nodes
    ​​​​sudo nano /etc/exports
    
    • 設定檔格式如下
      ​​​​​​​​<目錄位置> <host> (<權限>)
      
      • host 可以是 IP 或是 hostname
    • 加入以下內容
      ​​​​​​​​/home/pj/mpi mpi-w0(rw,sync,no_subtree_check)
      ​​​​​​​​/home/pj/mpi mpi-w1(rw,sync,no_subtree_check)
      
      • 路徑要記得換成你自己的
  • 重新載入設定檔,並重啟服務
    ​​​​sudo exportfs -a
    ​​​​sudo systemctl restart nfs-kernel-server
    
  • 在所有 worker 中也建立一個目錄,用來連接 manager 上的共享目錄
    • 目錄不一定要用相同路徑
    ​​​​cd ~
    ​​​​mkdir mpi
    
  • 把目錄掛載到 manager 的共享資料夾
    ​​​​sudo mount mpi-mgr:/home/pj/mpi ~/mpi
    
    • 路徑記得換成你自己的
  • 在目錄中加入一個檔案,用其他機器查看該目錄中是否有出現新增的檔案
    • 在 manager 新增一個檔案到共用目錄中
      ​​​​​​​​touch ~/mpi/test_file
      
    • 在 worker 檢查共用目錄,是否有剛剛新增的檔案
      ​​​​​​​​cd ~/mpi
      ​​​​​​​​ls
      
  • 目前的設定,只要 重新開機 目錄就 不會掛載
    • 如果要 開機就自動掛載,要修改 worker 上的 /etc/fstab
      ​​​​​​​​sudo nano /etc/fstab
      
    • 加入以下內容,路徑要記得修改
      ​​​​​​​​mpi-mgr:/home/pj/mpi  /home/pj/mpi  nfs  defaults  0  0
      

執行 MPI 程式

  • 在 Manager,切換到共用目錄
    ​​​​cd ~/mpi
    
  • 新增一個檔案,儲存所有 nodes 的 hostname
    • 檔案名稱、副檔名不限,我把檔案命名成 hosts.list
    • 檔案內容如下
      ​​​​​​​​mpi-mgr
      ​​​​​​​​mpi-w0
      ​​​​​​​​mpi-w1
      
  • 新增一個 C 程式碼檔案,貼上下列程式碼
    • 名稱不限,我命名為 hello_mpi.c
    ​​​​#include <mpi.h>
    ​​​​#include <stdio.h>
    
    ​​​​int main(int argc, char** argv) {
    ​​​​    // Initialize the MPI environment
    ​​​​    MPI_Init(NULL, NULL);
    
    ​​​​    // Get the number of processes
    ​​​​    int world_size;
    ​​​​    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    
    ​​​​    // Get the rank of the process
    ​​​​    int world_rank;
    ​​​​    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    
    ​​​​    // Get the name of the processor
    ​​​​    char processor_name[MPI_MAX_PROCESSOR_NAME];
    ​​​​    int name_len;
    ​​​​    MPI_Get_processor_name(processor_name, &name_len);
    
    ​​​​    // Print off a hello world message
    ​​​​    printf("Hello world from processor %s, rank %d out of %d processors\n",
    ​​​​           processor_name, world_rank, world_size);
    
    ​​​​    // Finalize the MPI environment.
    ​​​​    MPI_Finalize();
    ​​​​    return 0;
    ​​​​}
    
  • mpicc 編譯,使用方式和 gcc 相同
    ​​​​mpicc hello_mpi.c -o hello_mpi
    
  • mpirun 執行編譯好的檔案,不加任何選項會只在目前機器上執行
    ​​​​mpirun hello_mpi
    
    Output
    ​​​​Hello world from processor mpi-mgr, rank 0 out of 2 processors
    ​​​​Hello world from processor mpi-mgr, rank 1 out of 2 processors
    
  • 加上 --hostfile <host_file>,程式會執行在 host_file 中列出的所有機器上
    • 這邊 host_file 就可以是剛剛寫的 hosts.list
    ​​​​mpirun --hostfile ./hosts.list hello_mpi
    
    Output
    ​​​​Hello world from processor mpi-mgr, rank 0 out of 6 processors
    ​​​​Hello world from processor mpi-mgr, rank 1 out of 6 processors
    ​​​​Hello world from processor mpi-w0, rank 2 out of 6 processors
    ​​​​Hello world from processor mpi-w0, rank 3 out of 6 processors
    ​​​​Hello world from processor mpi-w1, rank 4 out of 6 processors
    ​​​​Hello world from processor mpi-w1, rank 5 out of 6 processors