# Diskless system (简体中文)

From ArchWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

相关文章

- NFS
- NFS Troubleshooting
- PXE
- Mkinitcpio#Using_net
- iSCSI Boot

翻译状态：本文是 Diskless system 的翻译。上次翻译日期：2020-05-13。如果英文版本有所更改，则您可以帮助同步翻译。

引用自 Gentoo Wiki:无盘节点

  一台无盘机器是一台没有任何诸如硬盘、软盘驱动器或CD-ROM等常见引导设备的PC。无盘节点引导自网络，并需要一台服务器来提供当作本地硬盘来使用的存储空间。

## 服务端配置

首先我们应当安装如下组件:

- 用于向无盘节点分配IP地址的 DHCP 服务端。
- 用于分发启动镜像的 TFTP 服务端 （所有PXE镜像必需）。
- 选择 (NFS 或 NBD) 中的一种作为存放和传输无盘节点的 Arch 安装副本的网络存储服务。

注意： dnsmasq 能够同时兼任 DHCP 和 TFTP 服务器。更多信息请见 Dnsmasq (简体中文)。

### DHCP

安装并配置 ISC dhcp:

    /etc/dhcpd.conf

    allow booting;
    allow bootp;

    authoritative;

    option domain-name-servers 10.0.0.1;

    option architecture code 93 = unsigned integer 16;

    group {
        next-server 10.0.0.1;

        if option architecture = 00:07 {
            filename "/grub/x86_64-efi/core.efi";
        } else {
            filename "/grub/i386-pc/core.0";
        }

        subnet 10.0.0.0 netmask 255.255.255.0 {
            option routers 10.0.0.1;
            range 10.0.0.128 10.0.0.254;
        }
    }

注意： `next-server` 应为 TFTP 服务端监听的IP地址; 你需要酌情更改配置中的地址以匹配你已有的网络环境。

RFC 4578 定义了"客户机架构类型（Client System Architecture Type）" 的 dhcp 参数。在如上配置中，如果 PXE 客户机（暨无盘系统）请求了 x86_64-efi 镜像 (类型 0x7) 服务端将返回对应的文件, 否则自动回落到 legacy 镜像。这样，同一网络中的 UEFI 和 legacy BIOS 均能正常启动。

然后启动 ISC DHCP systemd (简体中文) 服务。

### TFTP

TFTP 用于向无盘系统传输 启动器、内核以及 initramfs。

将 TFTP 根目录设置为 `/srv/arch/boot`。参阅 Tftpd server 配置安装并配置。

### 网络存储

NFS 与 NBD 的主要区别是，尽管两者均允许你为多个无盘系统使用同一份安装完毕的 Arch Linux，在使用 NBD 时 (由于其直接与文件系统交互的本质) 你将必需使用 `CopyOnWrite` 的模式, 并将导致在无盘系统断开连接时丢弃所有改动。然而在一些场景中，这是一项不可多得的优势。

#### NFS

在服务端安装 nfs-utils。

你需要将 Arch 安装副本的根目录加入 NFS (简体中文) 的共享（“导出”）列表:

    /etc/exports

    /srv       *(rw,fsid=0,no_root_squash,no_subtree_check)
    /srv/arch  *(rw,no_root_squash,no_subtree_check)

然后启动 NFS 服务: `rpc-idmapd` `rpc-mountd`.

#### NBD

安装并配置 nbd。

    /etc/nbd-server/config

    [generic]
        user = nbd
        group = nbd
    [arch]
        exportname = /srv/arch.img
        copyonwrite = false

注意：

- 如果你需要多台无盘系统同时启动改镜像，请将 `copyonwrite` 设为 `true`；详情请参阅 nbd-server(5)。
- 可能需要使用 chown 将 exportname 目录的所有权赋予 `nbd` 用户。

启动 `nbd` systemd 服务。

## 无盘系统配置

接下来我们将在服务器端的子目录中创建一个完整的 Arch Linux 安装副本。启动无盘机时，其将从 DHCP 服务器获取一个 IP 地址，而后通过 PXE 启动并挂载这份安装副本作为根目录。

### 安装目录创建

创建一个至少 1GB 的 sparse file 并格式化为 btrfs。 (你当然也可以使用其他块设备如实体硬盘或 LVM)。

注意： 对于 NBD，创建一个单独的文件系统是必须的；但对于 NFS 这是可选的，故可酌情忽略或跳过。

    # truncate -s 1G /srv/arch.img
    # mkfs.btrfs /srv/arch.img
    # export root=/srv/arch
    # mkdir -p "$root"
    # mount -o loop,compress=lzo /srv/arch.img "$root"

### Bootstrap 安装

安装 devtools 和 arch-install-scripts, 然后运行 `pacstrap` 以为无盘系统 安装必须的软件包:

    # pacstrap -d "$root" base linux linux-firmware mkinitcpio-nfs-utils nfs-utils

注意： 在任何配置中 mkinitcpio-nfs-utils 都必须安装：它将提供早期启动过程中所需的 `ipconfig`。

现在应当生成好 initramfs。

#### NFS

要使 NFSv4 挂载正常工作，需要轻微改动 `net` hook (这不被默认的`net` hook：`nfsmount` 所支持)。

    # sed s/nfsmount/mount.nfs4/ "$root/usr/lib/initcpio/hooks/net" > "$root/usr/lib/initcpio/hooks/netnfs4"
    # cp $root/usr/lib/initcpio/install/net{,nfs4}

此时需要备份 `net` 以防止其在 mkinitcpio-nfs-utils 升级时被覆盖.

Edit `$root/etc/mkinitcpio.conf` and add `nfsv4` to `MODULES`, `netnfs4` to `HOOKS`, and `/usr/bin/mount.nfs4` to `BINARIES`.

然后 chroot 到安装副本的根目录并执行 mkinitcpio:

    # arch-chroot "$root" mkinitcpio -p linux

#### NBD

在无盘系统的 Arch 安装副本中安装 mkinitcpio-nbdAUR。使用 makepkg (简体中文) 构建并安装它：

    # pacman --root "$root" --dbpath "$root/var/lib/pacman" -U mkinitcpio-nbd-0.4-1-any.pkg.tar.xz

然后你需要将 `HOOKS` array 中 `net` 之后加入 `nbd`； `net` 将负责配置网络, 但只要不在 kernel 行中指定，它不会尝试 NFS 挂载。

## 配置无盘系统

在上述步骤完成后，你仍需要时情况完成主机名，时区，区域设置，键盘布局等其他 Installation guide (简体中文) 提及的配置步骤。

### 启动器

#### GRUB

This article or section is a candidate for merging with GRUB.

Notes: (Discuss in Talk:Diskless system (简体中文)#)

尽管没有详细文档, GRUB 支持从 PXE 加载：

    # pacman --root "$root" --dbpath "$root/var/lib/pacman" -S grub

使用 `grub-mknetdir` 在目标系统（无盘系统的 Arch 安装副本）中创建一个 grub prefix：

    # arch-chroot "$root" grub-mknetdir --net-directory=/boot --subdir=grub

幸运的是，`grub-mknetdir` 为所有已编译/安装的目标创建 prefix, 且 grub 的维护者在同一包中提供了两种架构, 所以 `grub-mknetdir` 仅需执行一次。

现在我们创建一个 GRUB 配置:

    # vim "$root/boot/grub/grub.cfg"

    menuentry "Arch Linux" {
        linux /vmlinuz-linux quiet add_efi_memmap ip=:::::eth0:dhcp nfsroot=10.0.0.1:/arch
        initrd /initramfs-linux.img
    }

GRUB 黑魔法将会自动设置 `set root=(tftp,10.0.0.1)`，这样内核和 initramfs 将自动通过 TFTP 传输过来，不过当你有其他非 TFTP 的启动项时，你仍希望显式声明这些配置。

注意： 根据需要依照PXELINUX修改你的于NBD相关的内核行配置。

#### PXELINUX

PXELINUX 由 syslinux 提供，详见 PXELINUX。

### 额外的挂载点

#### NBD 根

late boot 时你需要将根分区的文件系统切换为可读写（`rw`）并且启动 `compress=lzo` 以获得相较于 NFS 可观的性能提升。

    # vim "$root/etc/fstab"

    /dev/nbd0  /  btrfs  rw,noatime,compress=lzo  0 0

#### 程序状态目录

The factual accuracy of this article or section is disputed.

Reason: 当 /var/log/journal 为 tmpfs 或不存在时，systemd 默认不会进行持久日志记录。 (Discuss in Talk:Diskless system (简体中文)#)

你可以将 `/var/log` 挂载为例如 tmpfs 的文件系统，这样多台主机的日志将不会意外混杂在一起。对于 `/var/spool/cups` 亦可实行此操作，这样 20 个使用相同 spool 的 CUPS 不会互相打架然后执行进行 1498 份打印工作并在一夜之间吃掉整摞纸（或更糟：墨盒）。

    # vim "$root/etc/fstab"

    tmpfs   /var/log        tmpfs     nodev,nosuid    0 0
    tmpfs   /var/spool/cups tmpfs     nodev,nosuid    0 0

对于有某种唯一状态或数据库的软件，最好的配置是为每台无盘主机配置唯一的储存目录。例，如果你想要运行 puppet 你可以简单地在 puppet 的 systemd unit file 中使用 `%H` 标识符:

    # vim "$root/etc/systemd/system/puppetagent.service"

    [Unit]
    Description=Puppet agent
    Wants=basic.target
    After=basic.target network.target

    [Service]
    Type=forking
    PIDFile=/run/puppet/agent.pid
    ExecStartPre=/usr/bin/install -d -o puppet -m 755 /run/puppet
    ExecStart=/usr/bin/puppet agent --vardir=/var/lib/puppet-%H --ssldir=/etc/puppet/ssl-%H

    [Install]
    WantedBy=multi-user.target

Puppet-agent 将会在 vardir 或 ssldir 不存在时自动创建之。

如果上述方法都不适用，你还可以选择使用 systemd generator 来针对当前主机创建一个 mount unit，不幸的是 %H 标识符无法使用。

## 无盘机启动

### NBD

The factual accuracy of this article or section is disputed.

Reason: 在服务端启动了CopyOnWrite特性时，所有无盘系统应当均有效地只读挂载了根分区所在的文件系统，所以理论上在NBD服务器上读写挂载是安全的。 (Discuss in Talk:Diskless system (简体中文)#)

当使用 NBD 作为网络存储服务时，你需要无盘系统启动前确保卸载（`umount`）安装副本所在的块设备。

这一特性使得内核更新的过程十分有趣：当客户机开机时你不能挂载它所使用的文件系统, 这意味着你需要用一个单独的内核来执行内核更新。

首先从客户端安装副本复制 `$root/boot` 到你的 tftp 根目录 (通常即 `/srv/boot`).

    # cp -r "$root/boot" /srv/boot

然后在客户机启动前卸载 `$root`。

    # umount "$root"

注意： 如上配置中如需升级内核,你需要在开始内核更新前于无盘机中使用 NFS (简体中文) 在 fstab 中挂载 `/srv/boot`，或是在客户机于NBD断开后手动挂载客户机文件系统。

## 参阅

- kernel.org: Mounting the root filesystem via NFS (nfsroot)
- syslinux.org: pxelinux FAQ

Category:

- Installation process (简体中文)

Hidden categories:

- Pages or sections flagged with Template:Merge
- Pages or sections flagged with Template:Accuracy