如何搭建树莓派集群
为什么要搭建一个物理集群呢?如今,你可以登录亚马逊、Digital Ocean 或其他任何云服务提供商的平台,在几秒钟内就能创建一台虚拟机。但云服务器不过是别人的计算机:树莓派集群是一个低成本且用途广泛的系统,可用于各类与集群计算相关的技术,而且你能完全掌控构成它的设备。从零开始搭建某些东西,能让你学到在别处学不到的知识。
我们要构建的内容
集群接线图
我们要组建一个由八个节点组成的集群,并将其连接到一台可管理交换机上。其中一个节点将作为所谓的“头”节点:该节点会通过一个USB3以太网转接器,额外配备一条千兆以太网连接到局域网/广域网,同时通过一个USB3转SATA连接器挂载一块1TB的外置固态硬盘。头节点将像平常一样从SD卡启动,而其他七个节点——“计算”节点——将配置为网络启动,头节点充当启动服务器,操作系统镜像则存储在外置磁盘上。除了作为网络启动卷,这块1TB的磁盘还将设置一个临时分区,共享给集群中的所有计算节点。我们的八块树莓派主板都将安装树莓派PoE+ HAT(以太网供电扩展板)。这意味着,由于我们使用的是支持PoE+的交换机,因此每个节点只需连接一根以太网线缆,无需单独的USB集线器为其供电。
所需材料
物品清单
- 8个树莓派4
- 8个树莓派PoE+ HAT(以太网供电扩展板)
- 8口千兆PoE交换机
- USB 3转千兆以太网适配器
- USB 3转SATA适配器
- SATA接口固态硬盘
- 8根以太网线缆
- 16GB SD卡
- 集群机箱
组建一个树莓派集群(有时也称为“荆棘丛”)所需的零件清单可长可短,这取决于你打算构建的集群的规模和类型。所以在开始订购组建集群的零件之前,先想好你希望集群实现什么功能,这一点很重要。以上清单是我们组建8个树莓派的集群所用到的,但你的需求很可能有所不同。
你需要一整套树莓派电脑,如果打算像我们一样通过以太网供电(PoE),那你就需要相应数量的树莓派PoE+ HAT扩展板和一台合适的PoE+交换机。除此之外,你还需要一张Micro SD卡、一些以太网线缆、一个USB转以太网适配器、一根USB转SATA转接线以及一块大小合适的固态硬盘,另外还需要某种机箱,在购买完所有组件后将它们组装进去。机箱既可以是定制设计的“集群机箱”,或者根据你构建集群后打算用它做什么,也可以选择某种可安装在机架上的机箱。
不过,在选择组件方面有很大的灵活性,具体取决于你组建集群的实际用途。例如,根据你预计在集群上运行的任务类型,你也许可以使用更便宜的2GB或1GB内存的板子,而不一定非要用我所使用的4GB型号。或者,每个节点配备本地磁盘可能很重要,所以你可能需要考虑为每块板子连接一块磁盘来提供本地存储。
然而,在考虑构建集群时,最大的选择或许在于如何为节点供电。我们这个集群使用的是PoE供电,这需要在每个节点上添加一块PoE+ HAT扩展板,并购买一台更昂贵的能够为树莓派板子供电的交换机:对于较大规模的集群来说,这可能是最佳方法。对于较小规模的集群,你可以考虑通过USB集线器为节点供电,而对于最小规模的集群(也许4个节点或更少),则可以直接为每个节点单独连接电源供电。
自制USB风扇
如果你决定使用以太网供电(PoE)为集群供电,你会发现可能得制作一些特制线缆。例如,我用的机箱后部风扇原本是要连接到树莓派的通用输入输出(GPIO)排针,但由于我们使用树莓派PoE+ HAT为节点供电,就无法使用这些GPIO排针了。
所以,至少对我来说,是时候找些废旧USB线来制作线缆了。如果你剪下USB线的一端并剥开塑料外皮,会看到里面有四根线;这些线通常包裹在绝缘金属屏蔽层内。线缆内的线又细又脆弱,所以如果有屏蔽层,要小心地剥开。你要找的是红色(+5V)和黑色(GND,接地)的线。另外两根线,通常是白色和绿色,用于传输数据。你可以直接把这两根数据线剪掉,用不上它们。
将风扇的红色和黑色电线,焊接到USB线中的红色和黑色电线上。 这里最好的做法是,在每个单独的焊接点上套上一小段热缩管,然后在两个焊接点上再套上一段稍大的热缩管。这样就能在风扇和新线缆的USB插头端之间,形成电气绝缘且机械稳固的连接。
我使用的集群机箱后部安装了四个风扇。我打算将左边的两个风扇连接到头节点供电,如果头节点需要更多USB接口,也可能从左边第一个计算节点供电;右边的两个风扇则由最右边的计算节点供电。
你可能最常在这种情况下需要特制线缆:由于无法使用通用输入输出(GPIO)排针,所以要通过USB为风扇供电。但也有其他可能需要特制线缆的情况。例如,几年前我搭建一个集群时,需要制作一根线缆,以便通过USB集线器而非+5V电源为一台以太网交换机供电。
配置树莓派
首先,按照“入门指南”文档来设置你的树莓派。对于操作系统,选择“Raspberry Pi OS(其他)”>“Raspberry Pi OS Lite”以进行无桌面模式运行(无需鼠标和键盘)。
在操作系统定制阶段,按如下方式编辑设置:
- 输入你选择的主机名(本教程建议使用pi-cluster)
- 输入用户名(本教程建议使用pi)和密码;之后进行身份验证时会用到
- 勾选“配置无线局域网”旁边的复选框,以便树莓派能自动连接Wi-Fi
- 输入你的网络SSID(名称)和密码;你可以在Wi-Fi设置中或路由器上的标签找到这些信息
- 勾选“启用SSH”旁边的复选框,这样我们就能在无需鼠标和键盘的情况下连接到树莓派
构建头节点
具体的连接方式取决于你的集群组件,以及你是否购置了机箱,更确切地说,取决于你所拥有的机箱类型。我打算将头节点安装在机箱最左侧的位置。这样我就能用一颗安装螺丝将固态硬盘固定在机箱一侧内壁上。
$ ssh <username>@pi-cluster.local
<username>@pi-cluster.local's password:
$
如果我们输入“nmcli”来查看网络配置,
$ nmcli
wlan0: connected to preconfigured
"Broadcom BCM43438 combo and Bluetooth Low Energy"
wifi (brcmfmac), DC:A6:32:6A:16:91, hw, mtu 1500
inet4 10.3.194.40/22
route4 10.3.192.0/22 metric 600
route4 default via 10.3.194.1 metric 600
inet6 2001:4d4e:300:c2:1fd1:9c44:f362:3805/64
inet6 fe80::a725:b6cc:ce19:3caf/64
route6 fe80::/64 metric 1024
route6 2001:4d4e:300:c2::/64 metric 600
route6 default via fe80::dccc:45ff:fe78:a3cc metric 600
lo: connected (externally) to lo
"lo"
loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536
inet4 127.0.0.1/8
inet6 ::1/128
eth0: disconnected
"eth0"
1 connection available
ethernet (bcmgenet), DC:A6:32:6A:16:90, hw, mtu 1500
DNS configuration:
servers: 10.3.31.1
domains: pitowers.org
interface: eth1
servers: fe80::8498:d3ff:fe31:8eac
interface: eth1
servers: 10.3.194.1
domains: pitowers.org
interface: wlan0
servers: fe80::dccc:45ff:fe78:a3cc
interface: wlan0
$
你会看到wlan0通过10.3.* 网段的地址连接到了我们的本地网络,而插入交换机的eth0处于断开状态。在这个项目后续过程中,我们会通过将头节点转变为一个DHCP服务器来解决这个问题,该服务器将为每个计算节点以及我们的智能交换机分配IP地址。
添加第二条以太网连接
我们能够通过网络访问头节点,是因为在设置SD卡时配置了无线接口wlan0。然而,将集群通过有线方式连接到网络会更好,而不是依赖无线连接,因为我们可能需要来回传输大文件,并且有线接口要稳定得多。为此,我们需要额外添加一条以太网连接,所以我要给头节点添加一个USB 3转千兆以太网适配器。我们会让板载以太网接口(eth0)连接到PoE交换机,作为集群的内部连接,同时使用第二条以太网连接(eth1)与外部网络通信。
在大多数情况下,eth1会由网络管理器自动激活,并从局域网的DHCP服务器获取一个IP地址。插入适配器后,我们应该会看到类似这样的信息:
这是在命令行中输入nmcli后的结果中新增的内容。
eth1: connected to Wired connection 2
"Realtek RTL8153"
ethernet (r8152), 00:E0:4C:68:1D:DA, hw, mtu 1500
ip4 default, ip6 default
inet4 10.3.31.194/24
route4 10.3.31.0/24 metric 100
route4 default via 10.3.31.1 metric 100
inet6 2001:4d4e:300:1f:6f2a:f4b1:65a8:b420/64
inet6 fe80::7a88:6d47:4554:bd80/64
route6 fe80::/64 metric 1024
route6 2001:4d4e:300:1f::/64 metric 100
route6 default via fe80::8498:d3ff:fe31:8eac metric 100
我们将保持板载以太网接口eth0连接到以太网交换机,作为集群的内部连接。在内部,我们将为集群分配192.168.50.*/24网段的地址,头节点的IP地址为192.168.50.1。
$ sudo nmcli con mod "Wired connection 1" ipv4.addresses 192.168.50.1/24 ipv4.method manual
$ sudo nmcli con down "Wired connection 1"
$ sudo nmcli con up "Wired connection 1"
然后,如果一切按计划进行,你应该会看到类似这样的内容:
$ nmcli
eth1: connected to Wired connection 2
"Realtek RTL8153"
ethernet (r8152), 00:E0:4C:68:1D:DA, hw, mtu 1500
ip4 default, ip6 default
inet4 10.3.31.194/24
route4 10.3.31.0/24 metric 100
route4 default via 10.3.31.1 metric 100
inet6 2001:4d4e:300:1f:6f2a:f4b1:65a8:b420/64
inet6 fe80::7a88:6d47:4554:bd80/64
route6 fe80::/64 metric 1024
route6 2001:4d4e:300:1f::/64 metric 100
route6 default via fe80::8498:d3ff:fe31:8eac metric 100
wlan0: connected to preconfigured
"Broadcom BCM43438 combo and Bluetooth Low Energy"
wifi (brcmfmac), DC:A6:32:6A:16:91, hw, mtu 1500
inet4 10.3.194.40/22
route4 10.3.192.0/22 metric 600
route4 default via 10.3.194.1 metric 600
inet6 2001:4d4e:300:c2:1fd1:9c44:f362:3805/64
inet6 fe80::a725:b6cc:ce19:3caf/64
route6 fe80::/64 metric 1024
route6 2001:4d4e:300:c2::/64 metric 600
route6 default via fe80::dccc:45ff:fe78:a3cc metric 600
eth0: connected to Wired connection 1
"eth0"
ethernet (bcmgenet), DC:A6:32:6A:16:90, hw, mtu 1500
inet4 192.168.50.1/24
route4 192.168.50.0/24 metric 101
inet6 fe80::a5a8:6819:ddc6:6b2f/64
route6 fe80::/64 metric 1024
lo: connected (externally) to lo
"lo"
loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536
inet4 127.0.0.1/8
inet6 ::1/128
DNS configuration:
servers: 10.3.31.1
domains: pitowers.org
interface: eth1
servers: fe80::8498:d3ff:fe31:8eac
interface: eth1
servers: 10.3.194.1
domains: pitowers.org
interface: wlan0
servers: fe80::dccc:45ff:fe78:a3cc
interface: wlan0
$
配置DHCP服务器
现在我们通过eth1拥有了一条通向外部网络的 “第二个” 千兆以太网连接,并且板载以太网已配置了静态IP地址,接下来该把树莓派设置为eth0上集群的DHCP服务器了。首先要安装DHCP服务器软件本身:
$ sudo apt install isc-dhcp-server
然后按如下方式编辑 /etc/dhcp/dhcpd.conf 文件:
ddns-update-style none;
authoritative;
log-facility local7;
# No service will be given on this subnet
subnet 10.3.31.0 netmask 255.255.255.0 {
}
# The internal cluster network
group {
option broadcast-address 192.168.50.255;
option routers 192.168.50.1;
default-lease-time 600;
max-lease-time 7200;
option domain-name "cluster";
option domain-name-servers 8.8.8.8, 8.8.4.4;
subnet 192.168.50.0 netmask 255.255.255.0 {
range 192.168.50.20 192.168.50.250;
# Head Node
host cluster {
hardware ethernet dc:a6:32:6a:16:90;
fixed-address 192.168.50.1;
}
}
}
然后编辑 /etc/default/isc - dhcp - server文件,以适配我们新的服务器设置:
DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
DHCPDv4_PID=/var/run/dhcpd.pid
INTERFACESv4="eth0"
以及 /etc/hosts 文件:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 cluster
192.168.50.1 cluster
然后你可以重启头节点,以启动DHCP服务。
我们已完成相关设置,未知的已知主机将从192.168.50.20开始分配IP地址。一旦我们知道计算节点的MAC地址,就可以将它们添加到 /etc/dhcp/dhcpd.conf文件中,这样它们后续就能获取静态IP地址,而不是每次启动时随机获取。重启后,如果你为集群使用的是可管理交换机(比如我用的网件交换机,它会自行获取一个IP地址),重新登录头节点,就可以检查DHCP服务是否正常工作:
$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC IP hostname valid until manufacturer
==================================================================================
80:cc:9c:94:53:35 192.168.50.20 GS308EPP 2021-12-06 14:19:52 NETGEAR
$
否则,你得等到添加第一个节点,因为非管理型交换机不会主动请求自身的地址。不过,如果你用的是管理型交换机,你很可能希望在集群内给它分配一个静态IP地址,方法与头节点类似,将相关信息添加到 /etc/dhcp/dhcpd.conf 和 /etc/hosts 文件中。我给交换机设置的主机名是 “switch” :
192.168.50.1 cluster
192.168.50.254 switch
并将192.168.50.254 作为分配的IP地址:
subnet 192.168.50.0 netmask 255.255.255.0 {
range 192.168.50.20 192.168.50.250;
# Head Node
host cluster {
hardware ethernet dc:a6:32:6a:16:90;
fixed-address 192.168.50.1;
}
# NETGEAR Switch
host switch {
hardware ethernet 80:cc:9c:94:53:35;
fixed-address 192.168.50.254;
}
}
添加外置磁盘
为了实现计算节点的网络引导,我们需要更大的空间。你可以通过将闪存盘插入头节点的其中一个USB端口来解决,但我打算使用一根USB 3转SATA转接线,连接实验室架子上一块1TB的固态硬盘,这样就能为集群提供充足的数据存储空间。我将这块硬盘连接到头节点的其中一个USB 3接口上,用GUID分区表对其进行格式化,并在磁盘上创建一个单一的ext4分区。
$ sudo parted -s /dev/sda mklabel gpt
$ sudo parted --a optimal /dev/sda mkpart primary ext4 0% 100%
$ sudo mkfs -t ext4 /dev/sda1
mke2fs 1.46.2 (28-Feb-2021)
Creating filesystem with 244175218 4k blocks and 61046784 inodes
Filesystem UUID: 1a312035-ffdb-4c2b-9149-c975461de8f2
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
$
然后,我们可以手动挂载磁盘,检查一切是否正常:
$ sudo mkdir /mnt/usb
$ sudo mount /dev/sda1 /mnt/usb
$ sudo systemctl daemon-reload
然后,通过在 `/etc/fstab` 文件中添加以下内容,确保系统启动时磁盘能自动挂载:
/dev/sda1 /mnt/usb auto defaults,user 0 1
你应确保在重启前能手动挂载该磁盘,因为如果磁盘不可用,将其作为一项内容添加到/etc/fstab文件中,可能会导致树莓派在启动时挂起。
让集群能够使用该磁盘
我们希望让整个集群都能使用这块磁盘。你需要安装NFS服务器软件:
$ sudo apt install nfs-kernel-server
创建一个可供共享的挂载点:
$ sudo mkdir /mnt/usb/scratch
$ sudo chown pi:pi /mnt/usb/scratch
$ sudo ln -s /mnt/usb/scratch /scratch
然后,编辑 `/etc/exports` 文件,添加你希望能够挂载该磁盘的IP地址列表:
/mnt/usb/scratch 192.168.50.0/24(rw,sync)
这里我们将其导出到 `192.168.50.0/24`,这是 “192.168.50.0 到 192.168.50.254 之间所有IP地址” 的简写。
完成这些操作后,你应该启用并启动 `rpcbind` 和 `nfs-server` 服务:
$ sudo systemctl enable rpcbind.service
$ sudo systemctl start rpcbind.service
$ sudo systemctl enable nfs-server.service
$ sudo systemctl start nfs-server.service
最后,重启系统:
$ sudo reboot
添加第一个节点
我们要将计算节点设置为从我们的头节点进行网络引导。为此,我们首先必须为计算节点配置网络引导。树莓派不同型号的配置方法有所不同。不过,对于树莓派4而言,开发板必须先从SD卡启动一次,然后使用`raspi - config`命令行工具配置启动顺序。启用网络引导
最简便的方法是使用树莓派镜像写入软件,将树莓派OS Lite(64位)烧录到另一张SD卡上。在开发板启动前,无需像对头节点那样进行特殊配置,只需启用SSH即可。 注意:请勿配置或启用无线局域网。 接下来,启动连接到集群交换机的开发板:在我们最初的头节点旁边,有第二台通过PoE+供电的树莓派4。
该开发板在从头节点的DHCP服务器获取IP地址后,应该会启动并在集群子网中可见。我们可以在头节点上使用`dhcp - lease - list`查看集群网络情况:
$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC IP hostname valid until manufacturer
===============================================================================================
dc:a6:32:6a:16:87 192.168.50.21 raspberrypi 2021-12-07 11:54:29 Raspberry Pi Ltd
$
```
现在我们可以继续通过SSH连接到新的开发板,并使用命令行中的`raspi - config`启用网络引导:
$ ssh pi@192.168.50.21
$ sudo raspi-config
选择“高级选项”>“启动顺序”>“网络引导”。然后,你需要重启设备,以便将启动顺序的更改写入引导加载程序EEPROM。
如果你在尝试启用网络引导时收到错误,提示“未找到EEPROM bin文件”,那么在继续操作之前,你需要更新树莓派的固件。运行以下命令:
$ sudo apt install rpi-eeprom
$ sudo rpi-eeprom-update -d -a
$ sudo reboot
然后,在节点重启后,再次尝试设置网络引导。
树莓派重启后,使用`vcgencmd`检查启动顺序:
$ vcgencmd bootloader_config
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
[all]
BOOT_ORDER=0xf21
$
此时你应该会看到`BOOT_ORDER`为0xf21,这表明树莓派将首先尝试从SD卡启动,然后尝试从网络启动。在继续下一步之前,我们需要记录下树莓派的以太网MAC地址和序列号。
$ ethtool -P eth0
Permanent address: dc:a6:32:6a:16:87
$ grep Serial /proc/cpuinfo | cut -d ' ' -f 2 | cut -c 9-16
6a5ef8b0
$
之后,你可以关闭开发板(至少目前是这样),并取出SD卡。
将头节点设置为引导服务器
我们现在需要将头节点配置为引导服务器。这里有几种选择,但我们将使用现有的DHCP服务器以及一个独立的TFTP服务器。你应该为该服务器创建一个挂载点并进行安装:
$ sudo apt install tftpd-hpa
$ sudo apt install kpartx
$ sudo mkdir /mnt/usb/tftpboot
$ sudo chown tftp:tftp /mnt/usb/tftpboot
编辑 `/etc/default/tftpd-hpa` 文件:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/mnt/usb/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure --create"
然后,重启服务:
$ sudo systemctl restart tftpd-hpa
接下来我们需要设置引导镜像,并且每个客户端都要创建一个镜像。第一步是从网上获取最新镜像并挂载,以便我们进行一些修改,然后挂载镜像内的分区,这样就能将内容复制到外部磁盘:
$ sudo su
# mkdir /tmp/image
# cd /tmp/image
# wget -O raspios_lite_latest.img.xz https://downloads.raspberrypi.com/raspios_lite_arm64_latest
# xz -d raspios_lite_latest.img.xz
# kpartx -a -v *.img
# mkdir bootmnt
# mkdir rootmnt
# mount /dev/mapper/loop0p1 bootmnt/
# mount /dev/mapper/loop0p2 rootmnt/
# mkdir -p /mnt/usb/rpi1
# mkdir -p /mnt/usb/tftpboot/6a5ef8b0
# cp -a rootmnt/* /mnt/usb/rpi1
# cp -a bootmnt/* /mnt/usb/rpi1/boot/firmware
其中“6a5ef8b0”是我们之前获取的第一个节点的序列号。
之后,我们可以自定义根文件系统:
# touch /mnt/usb/rpi1/boot/firmware/ssh
# echo pi:$(echo 'raspberry' | openssl passwd -6 -stdin) > /mnt/usb/rpi1/boot/firmware/userconf.txt
# sed -i /UUID/d /mnt/usb/rpi1/etc/fstab
# echo "192.168.50.1:/mnt/usb/tftpboot/6a5ef8b0 /boot/firmware nfs defaults,vers=3 0 0" >> /mnt/usb/rpi1/etc/fstab
# echo "console=serial0,115200 console=tty root=/dev/nfs nfsroot=192.168.50.1:/mnt/usb/rpi1,vers=3 rw ip=dhcp rootwait" > /mnt/usb/rpi1/boot/firmware/cmdline.txt
然后将其添加到头节点的 `/etc/exports` 文件中:
# echo "/mnt/usb/rpi1 192.168.50.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
然后清理一下:
# systemctl restart rpcbind
# systemctl restart nfs-server
# umount bootmnt/
# umount rootmnt/
# cd /tmp; rm -rf image
# exit
$
最后,我们需要按如下方式编辑 `/etc/dhcp/dhcpd.conf` 文件:
ddns-update-style none;
authoritative;
log-facility local7;
option option-43 code 43 = text;
option option-66 code 66 = text;
# No service will be given on this subnet
subnet 10.3.31.0 netmask 255.255.255.0 {
}
# The internal cluster network
group {
option broadcast-address 192.168.50.255;
option routers 192.168.50.1;
default-lease-time 600;
max-lease-time 7200;
option domain-name "cluster";
option domain-name-servers 8.8.8.8, 8.8.4.4;
subnet 192.168.50.0 netmask 255.255.255.0 {
range 192.168.50.20 192.168.50.250;
# Head Node
host cluster {
hardware ethernet dc:a6:32:6a:16:90;
fixed-address 192.168.50.1;
}
# NETGEAR Switch
host switch {
hardware ethernet 80:cc:9c:94:53:35;
fixed-address 192.168.50.254;
}
host rpi1 {
option root-path "/mnt/usb/tftpboot/";
hardware ethernet dc:a6:32:6a:16:87;
option option-43 "Raspberry Pi Boot";
option option-66 "192.168.50.1";
next-server 192.168.50.1;
fixed-address 192.168.50.11;
option host-name "rpi1";
}
}
}
并重启我们的树莓派:
$ sudo reboot
让节点进行网络引导
确保已从计算节点中取出SD卡,然后将树莓派重新接入交换机。如果你手头有多余的显示器,不妨将其连接到HDMI端口,这样在节点启动时,你就能查看诊断屏幕。
如果一切顺利,开发板应能顺利启动。尽管还有一些地方需要整理,但现在你应该能够直接通过SSH连接到计算节点。
$ ssh pi@192.168.50.11
pi@192.168.50.11's password:
$
如果你在显示器上查看了启动信息,或者检查了日志,就会发现我们的镜像并非完全干净地启动。如果你重新登录到计算节点,可以通过关闭树莓派首次启动时自动调整文件系统大小的功能,以及卸载交换空间守护进程,确保以后不会出现这种情况。
$ sudo systemctl disable resize2fs_once.service
$ sudo systemctl disable sshswitch.service
$ sudo apt remove dphys-swapfile
接下来,我们应使用`raspi - config`命令行工具,将主机名从默认的“raspberrypi”更改为“rpi1”:
$ sudo raspi-config
选择“系统选项”>“主机名”来更改计算节点的主机名,然后选择“是”进行重启。
最后,为了让操作更简便一些,避免每次都要使用计算节点和头节点的IP地址,我们可以在头节点和计算节点的`/etc/hosts`文件中添加当前及未来的计算节点信息:
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 cluster
192.168.50.1 cluster
192.168.50.254 switch
192.168.50.11 rpi1
192.168.50.12 rpi2
192.168.50.13 rpi3
192.168.50.14 rpi4
192.168.50.15 rpi5
192.168.50.16 rpi6
192.168.50.17 rpi7
挂载共享磁盘
通常情况下,如果要挂载网络磁盘,我们会使用`autofs`,而不是直接在`/etc/fstab`文件中添加条目。但在这里,由于整个根文件系统都是通过网络挂载的,这么做似乎多此一举。计算节点重启后,重新登录,添加一个挂载点:
$ sudo mkdir /scratch
$ sudo chown pi:pi scratch
在`/etc/fstab`文件中添加共享磁盘的挂载信息:
192.168.50.1:/mnt/usb/scratch /scratch nfs defaults 0 0
然后,重启计算节点:
$ sudo reboot
无密码的安全SSH登录
在集群头节点和计算节点之间频繁使用安全外壳登录,且每次都要输入密码,这会相当麻烦。所以,我们通过生成公私钥对来实现无密码的安全外壳登录。在计算节点上,你应编辑 `/etc/ssh/sshd_config` 文件,启用公钥登录:
PubkeyAuthentication yes
PasswordAuthentication yes
PermitEmptyPasswords no
然后重启sshd服务器:
$ sudo systemctl restart ssh
接着回到头节点,我们需要生成公私钥对,并将公钥分发到计算节点。被询问时,使用空密码短语。
$ ssh-keygen -t rsa -b 4096 -C "pi@cluster"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/pi/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/pi/.ssh/id_rsa
Your public key has been saved in /home/pi/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:XdaHog/sAf1QbFiZj7sS9kkFhCJU9tLN0yt8OvZ52gA pi@cluster
The key's randomart image is:
+---
[RSA 4096]----+
| ...o *+o |
| ...+o+*o . |
| .o.=.B++ .|
| = B.ooo |
| S * Eoo |
| .o+o= |
| ..+=o. |
| ..+o +.|
| . +o.|
+----
[SHA256]-----+
$ ssh-copy-id -i /home/pi/.ssh/id_rsa.pub pi@rpi1
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/pi/.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
pi@rpi1's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'pi@rpi1'"
and check to make sure that only the key(s) you wanted were added.
$
之后,你应该就能无需输入密码登录到计算节点。
访问外部网络
目前我们的计算节点存在一个问题,就是无法访问局域网。现在计算节点只能看到头节点,等我们添加更多节点后,最终也只能看到其他计算节点。但我们可以解决这个问题!在头节点上,编辑 `/etc/sysctl.conf` 文件,取消注释以下这一行:
net.ipv4.ip_forward=1
激活转发功能后,我们需要配置iptables:
$ sudo apt install iptables
$ sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
$ sudo iptables -A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
$ sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
然后在 `/etc/rc.local` 文件中,在 `exit 0` 这一行的正上方添加一行,以便在启动时加载规则表:
_IP=$(hostname -I) || true
if
[ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
iptables-restore < /etc/iptables.ipv4.nat
exit 0
最后重启:
$ sudo reboot
注意:如果你让计算节点保持运行状态,应该先登录并关闭它,因为计算节点的根文件系统位于连接到头节点的磁盘上。
添加下一个计算节点
添加其余的计算节点要比添加第一个节点简单得多,因为我们现在可以使用定制好的镜像,避免像为第一个计算节点那样做很多繁杂的工作。
继续取出SD卡,启动连接到集群交换机的下一个树莓派。
开发板在从头节点的DHCP服务器获取IP地址后,应该会启动并在集群子网中可见。我们可以在头节点上使用`dhcp-lease-list`查看集群网络情况。
$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC IP hostname valid until manufacturer
===============================================================================================
dc:a6:32:6a:15:e2 192.168.50.21 raspberrypi 2021-12-08 21:15:00 Raspberry Pi Ltd
$
现在我们可以继续通过SSH连接到新的开发板,并再次使用命令行中的`raspi - config`为该开发板启用网络引导:
$ rm /home/pi/.ssh/known_hosts
$ ssh <username>@129.168.50.21
$ sudo raspi-config
选择“高级选项”>“启动顺序”>“网络引导”。然后,你需要重启设备,以便将启动顺序的更改写入引导加载程序EEPROM。树莓派重启后,使用`vcgencmd`检查启动顺序:
$ vcgencmd bootloader_config
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
[all]
BOOT_ORDER=0xf21
$
此时应该显示`BOOT_ORDER`为0xf21,这表明树莓派将首先尝试从SD卡启动,然后尝试从网络启动。在继续下一步之前,我们需要记录下树莓派的以太网MAC地址和序列号。
$ ethtool -P eth0
Permanent address: dc:a6:32:6a:15:e2
$ grep Serial /proc/cpuinfo | cut -d ' ' -f 2 | cut -c 9-16
54e91338
$
之后,你可以关闭开发板(至少目前是这样),并取出SD卡。
回到我们的头节点,我们可以使用已经配置好的镜像作为下一个计算节点操作系统的基础。
$ sudo su
$ mkdir -p /mnt/usb/rpi2
$ cp -a /mnt/usb/rpi1/* /mnt/usb/rpi2
$ mkdir -p /mnt/usb/tftpboot/54e91338
$ echo "/mnt/usb/rpi2/boot/firmware /mnt/usb/tftpboot/54e91338 none defaults,bind 0 0" >> /etc/fstab
$ echo "/mnt/usb/rpi2 192.168.50.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
$ exit
$
然后我们需要编辑`/mnt/usb/rpi2/boot/firmware/cmdline.txt`,将`rpi1`替换为`rpi2`:
console=serial0,115200 console=tty root=/dev/nfs nfsroot=192.168.50.1:/mnt/usb/rpi2,vers=3 rw ip=dhcp rootwait
同样地,编辑`/mnt/usb/rpi2/etc/hostname`:
rpi2
最后,在头节点上编辑`/etc/dhcp/dhcpd.conf`文件:
host rpi2 {
option root-path "/mnt/usb/tftpboot/";
hardware ethernet dc:a6:32:6a:15:e2;
option option-43 "Raspberry Pi Boot";
option option-66 "192.168.50.1";
next-server 192.168.50.1;
fixed-address 192.168.50.12;
option host-name "rpi2";
}
然后重启头节点:
$ sudo reboot
之后,你应该会看到`rpi1`和`rpi2`都已启动并运行。如果你感兴趣,可以在头节点上安装`nmap`,以便更好地查看我们的集群网络:
$ sudo apt install nmap
$ nmap 192.168.50.0/24
Starting Nmap 7.80 ( https://nmap.org ) at 2021-12-09 11:40 GMT
Nmap scan report for cluster (192.168.50.1)
Host is up (0.0018s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
22/tcp open ssh
111/tcp open rpcbind
2049/tcp open nfs
Nmap scan report for rpi1 (192.168.50.11)
Host is up (0.0017s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
22/tcp open ssh
Nmap scan report for rpi2 (192.168.50.12)
Host is up (0.00047s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
22/tcp open ssh
Nmap scan report for switch (192.168.50.254)
Host is up (0.014s latency).
Not shown: 999 filtered ports
PORT STATE SERVICE
80/tcp open http
Nmap done: 256 IP addresses (4 hosts up) scanned in 6.91 seconds
$
添加其余节点
现在添加剩下的五个计算节点或多或少是一个机械性的过程。你需要按照我们为`rpi2`所经历的过程,对`rpi3`、`rpi4`、`rpi5`、`rpi6`和`rpi7`进行操作。为每个新的计算节点替换相应的MAC地址、序列号和主机名:
主机名 | MAC地址 | 序列号 |
---|---|---|
rpi1 | dc:a6:32:6a:16:87 | 6a5ef8b0 |
rpi2 | dc:a6:32:6a:15:e2 | 54e91338 |
rpi3 | dc:a6:32:6a:15:16 | 6124b5e4 |
rpi4 | dc:a6:32:6a:15:55 | 52cddb85 |
rpi5 | dc:a6:32:6a:16:1b | a0f55410 |
rpi6 | dc:a6:32:6a:15:bb | c5fb02d3 |
rpi7 | dc:a6:32:6a:15:4f | f57fbb98 |
在启动最后一个计算节点时,我还顺便将剩下的两根特制电缆连接到最后一个节点,为我机箱中最右边的风扇供电。
控制你的树莓派集群
现在我们所有的节点都已启动并运行,我们需要一些集群控制工具。我最喜欢的工具之一是parallel-ssh工具包。你可以在头节点的命令行中安装它:
$ apt install pssh
除了出色的ParallelSSH Python库(允许你构建自己的集群自动化)之外,这将安装一些命令行工具,如parallel - ssh、parallel - scp、parallel - rsync、parallel - slurp和parallel - nuke。这些工具可以帮助你在头节点和计算节点之间运行和控制作业,以及移动和复制文件。要使用这些命令行工具,你需要创建一个包含所有计算节点的主机文件,我将我的文件保存为家目录中的`.pssh_hosts`:
$ cat .pssh_hosts
rpi1
rpi2
rpi3
rpi4
rpi5
rpi6
rpi7
$
创建文件后,我们可以使用命令行工具在我们的七个计算节点上执行命令等操作。
$ parallel-ssh -i -h .pssh_hosts free -h
[1] 12:10:15 [SUCCESS] rpi4
total used free shared buff/cache available
Mem: 3.8Gi 56Mi 3.7Gi 8.0Mi 64Mi 3.7Gi
Swap: 0B 0B 0B
[2] 12:10:15 [SUCCESS] rpi1
total used free shared buff/cache available
Mem: 3.8Gi 55Mi 3.7Gi 8.0Mi 64Mi 3.7Gi
Swap: 0B 0B 0B
[3] 12:10:15 [SUCCESS] rpi2
total used free shared buff/cache available
Mem: 3.8Gi 55Mi 3.7Gi 8.0Mi 64Mi 3.7Gi
Swap: 0B 0B 0B
[4] 12:10:15 [SUCCESS] rpi7
total used free shared buff/cache available
Mem: 3.8Gi 56Mi 3.7Gi 8.0Mi 97Mi 3.6Gi
Swap: 0B 0B 0B
[5] 12:10:15 [SUCCESS] rpi3
total used free shared buff/cache available
Mem: 3.8Gi 55Mi 3.7Gi 16Mi 104Mi 3.6Gi
Swap: 0B 0B 0B
[6] 12:10:15 [SUCCESS] rpi5
total used free shared buff/cache available
Mem: 3.8Gi 55Mi 3.7Gi 16Mi 72Mi 3.6Gi
Swap: 0B 0B 0B
[7] 12:10:15 [SUCCESS] rpi6
total used free shared buff/cache available
Mem: 3.8Gi 55Mi 3.7Gi 8.0Mi 64Mi 3.7Gi
Swap: 0B 0B 0B
$
不过你要注意,结果返回的顺序可能是随机的,这取决于每个计算节点上命令执行的速度。
添加远程关机服务
虽然parallel-ssh是一个很棒的工具,可以让你在集群中部署软件和执行其他任务,但有时你可能只想用一个命令干净利落地关闭集群。有很多方法可以实现这一点,最简单的方法就是编写一个 shell 脚本,登录到每个计算节点并关闭它们,然后再关闭头节点本身。或者,你也可以部署类似rshutdown服务的东西,并相应地编辑命令。
进一步拓展你的树莓派集群
到目前为止,我们构建的集群相当灵活,现在我们有了一个坚实的基础,可以根据我们对集群的确切需求开始安装软件。例如,如果我们要构建一个用于建模的计算集群,我们可能会考虑安装MPI和OpenMP,以便在集群上进行并行处理。或者,你可能希望构建一个集群来托管Kubernetes。
评论
发表评论