注意

本文档适用于 Ceph 开发版本。

测试Linux内核CephFS驱动程序的变化

本快速入门将解释一种(主观的)方法来测试 Linux 内核客户端与开发集群。我们将尽量减少对如何进行内核构建或任何相关最佳实践的先验知识的假设。

Note

对于 Ceph 的内核开发,有很多完全有效的方法。本指南是作者自己环境的快速入门。您可能会决定以非常不同的方式来做事情。

第一步:构建内核

克隆内核:

git init linux && cd linux
git remote add torvalds git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
git remote add ceph https://github.com/ceph/ceph-client.git
git fetch && git checkout torvalds/master

配置内核:

make defconfig

Note

您也可以使用Ceph 内核质量配置来构建内核。

现在我们有一个针对您正在构建的架构具有合理默认值的内核配置。接下来要做的就是在构建 Ceph 和/或提供我们进行测试所需的功能时启用配置。

cat > ~/.ceph.config <<EOF
CONFIG_CEPH_FS=y
CONFIG_CEPH_FSCACHE=y
CONFIG_CEPH_FS_POSIX_ACL=y
CONFIG_CEPH_FS_SECURITY_LABEL=y
CONFIG_CEPH_LIB_PRETTYDEBUG=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DYNAMIC_DEBUG_CORE=y
CONFIG_FRAME_POINTER=y
CONFIG_FSCACHE
CONFIG_FSCACHE_STATS
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_ALGS=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_XFS_FS=y
EOF

除了启用与 Ceph 相关的配置之外,我们还启用了某些有用的调试配置和 XFS(如果需要,作为 ext4 的替代方案用于我们的根文件系统)。

Note

不要将任何内容作为内核模块构建是一个好主意。否则,您将需要make modules_install在虚拟机的根驱动器上。

现在,合并配置。

scripts/kconfig/merge_config.sh .config ~/.ceph.config

最后,构建内核:

make -j

Note

本文档不讨论如何获取与您的发行版相关的实用程序来实际构建内核,例如 gcc。请使用您选择的搜索引擎来学习如何做。

第二步:创建虚拟机

虚拟机是测试内核客户端的几个原因的良好选择:

  • 您可以更轻松地监控和配置虚拟机的网络。

  • 您可以非常快速地测试对内核的更改(构建 -> 挂载在不到 10 秒内)。

  • 内核中的错误不会崩溃您的机器。

  • 您有一套工具可用于在运行中的内核上进行分析。

您需要做出的主要决定是您想使用哪个 Linux 发行版。本文档使用 Arch Linux,因为作者熟悉它。我们还使用 LVM 来创建一个卷。您可以使用分区或您喜欢的任何机制来创建一个块设备。通常,这个块设备将在测试中重复使用。您可能想使用快照来避免虚拟机以某种方式损坏您的根磁盘并迫使您重新开始。

# create a volume
VOLUME_GROUP=foo
sudo lvcreate -L 256G "$VOLUME_GROUP" -n $(whoami)-vm-0
DEV="/dev/${VOLUME_GROUP}/$(whoami)-vm-0"
sudo mkfs.xfs "$DEV"
sudo mount "$DEV" /mnt
sudo pacstrap /mnt base base-devel vim less jq
sudo arch-chroot /mnt
# # delete root's password for ease of login
# passwd -d root
# mkdir -p /root/.ssh && echo "$YOUR_SSH_KEY_PUBKEY" >> /root/.ssh/authorized_keys
# exit
sudo umount /mnt

一旦完成,我们应该能够运行一个虚拟机:

qemu-system-x86_64 -enable-kvm -kernel $(pwd)/arch/x86/boot/bzImage -drive file="$DEV",if=virtio,format=raw -append 'root=/dev/vda rw'

您应该看到类似以下输出:

VNC server running on ::1:5900

您可以使用以下方式查看该控制台:

vncviewer 127.0.0.1:5900

恭喜,您已经运行了一个正在运行您刚刚构建的内核的虚拟机。

第三步:网络化虚拟机

这是“困难的部分”,并且需要根据您想要做什么来进行最多的定制。对于本作者来说,我目前有一个开发设置,如下所示:

  sepian netns
 ______________
|              |
| kernel VM    |              sepia-bounce VM      vossi04.front.sepia.ceph.com
|  -------  |  |                  ------                    -------
|  |     |  |  | 192.168.20.1     |    |                    |     |
|  |     |--|--|- <- wireguard -> |    |  <-- sepia vpn ->  |     |
|  |_____|  |  |     192.168.20.2 |____|                    |_____|
|          br0 |
|______________|

sepia-bounce 虚拟机用作 sepia 实验室的反弹框。它可以代理 ssh 连接、路由任何 sepia 绑定的流量,或作为 DNS 代理。使用 sepia-bounce 虚拟机是可选的,但如果您想为测试创建多个内核虚拟机,则可能很有用。

我喜欢使用 vossi04开发者游乐场来构建 Ceph 并设置一个

为了避免使本文档过于复杂,包含 sepia-bounce 虚拟机的详细信息,我将指出以下主要配置,用于测试内核:

  • 在创建内核虚拟机的机器和 sepia-bounce 虚拟机之间设置一个 wireguard 隧道

  • 使用systemd-resolved作为 DNS 解析器,并在 192.168.20.2 上监听(而不是仅监听 localhost)

  • 连接到 sepiaVPN并使用systemd resolved 更新脚本来配置systemd-resolved使用通过 sepia VPN 从 DHCP 获取的 DNS 服务器

  • 配置firewalld允许 wireguard 流量,并进行伪装和转发流量到 sepia vpn

下一个任务是连接内核虚拟机到 sepia-bounce 虚拟机。网络命名空间可以用于此目的,以隔离虚拟机的流量/路由规则。对我而言,我使用自定义的 systemd one-shot 单元来编排此操作,如下所示:

# create the net namespace
ExecStart=/usr/bin/ip netns add sepian
# bring lo up
ExecStart=/usr/bin/ip netns exec sepian ip link set dev lo up
# setup wireguard to sepia-bounce
ExecStart=/usr/bin/ip link add wg-sepian type wireguard
ExecStart=/usr/bin/wg setconf wg-sepian /etc/wireguard/wg-sepian.conf
# move the wireguard interface to the sepian nents
ExecStart=/usr/bin/ip link set wg-sepian netns sepian
# configure the static ip and bring it up
ExecStart=/usr/bin/ip netns exec sepian ip addr add 192.168.20.1/24 dev wg-sepian
ExecStart=/usr/bin/ip netns exec sepian ip link set wg-sepian up
# logging info
ExecStart=/usr/bin/ip netns exec sepian ip addr
ExecStart=/usr/bin/ip netns exec sepian ip route
# make wireguard the default route
ExecStart=/usr/bin/ip netns exec sepian ip route add default via 192.168.20.2 dev wg-sepian
# more logging
ExecStart=/usr/bin/ip netns exec sepian ip route
# add a bridge interface for VMs
ExecStart=/usr/bin/ip netns exec sepian ip link add name br0 type bridge
# configure the addresses and bring it up
ExecStart=/usr/bin/ip netns exec sepian ip addr add 192.168.0.1/24 dev br0
ExecStart=/usr/bin/ip netns exec sepian ip link set br0 up
# masquerade/forward traffic to sepia-bounce
ExecStart=/usr/bin/ip netns exec sepian iptables -t nat -A POSTROUTING -o wg-sepian -j MASQUERADE

当使用网络命名空间时,我们将使用ip netns exec。有一个方便的功能可以自动将文件绑定挂载到/etc命名空间中,用于通过该命令运行的命令:

# cat /etc/netns/sepian/resolv.conf
nameserver 192.168.20.2

该文件将配置 libc 名称解析堆栈,以将应用程序的 DNS 请求路由到在 sepia-bounce 上运行的systemd-resolved守护进程。因此,在该 netns 中运行的任何应用程序都将能够解析 sepia 主机名:

$ sudo ip netns exec sepian host vossi04.front.sepia.ceph.com
vossi04.front.sepia.ceph.com has address 172.21.10.4

好的,太棒了。我们有一个将流量转发到 sepia VPN 的网络命名空间。下一步是连接运行内核的虚拟机到我们配置的桥。以最直接的方式做这件事是创建一个连接到桥的“tap”设备:

sudo ip netns exec sepian qemu-system-x86_64 \
    -enable-kvm \
    -kernel $(pwd)/arch/x86/boot/bzImage \
    -drive file="$DEV",if=virtio,format=raw \
    -netdev tap,id=net0,ifname=tap0,script="$HOME/bin/qemu-br0",downscript=no \
    -device virtio-net-pci,netdev=net0 \
    -append 'root=/dev/vda rw'

新的相关部分在这里是 (a) 在我们构建的 netns 中执行虚拟机;(b) 一个-netdev命令来配置 tap 设备;(c) 虚拟机的虚拟网络卡。还有一个由 qemu 运行的脚本$HOME/bin/qemu-br0来配置 qemu 为虚拟机创建的 tap 设备:

#!/bin/bash
tap=$1
ip link set "$tap" master br0
ip link set dev "$tap" up

这只是将新的 tap 设备插入桥中。

这一切都很好,但我们现在缺少最后一步关键步骤。虚拟机的 IP 地址是什么?有两种选择:

  1. 配置静态 IP,但虚拟机的根设备网络堆栈配置必须修改

  2. 使用 DHCP 并配置虚拟机的根设备始终使用 dhcp 来配置其以太网设备地址

第二种选择更复杂,因为您现在必须运行一个 DHCP 服务器,但在测试时添加更多虚拟机时提供了最大的灵活性。

修改(或“黑客”)的标准 dhcpd systemd 服务看起来像:

# cat sepian-dhcpd.service
[Unit]
Description=IPv4 DHCP server
After=network.target network-online.target sepian-netns.service
Wants=network-online.target
Requires=sepian-netns.service

[Service]
ExecStartPre=/usr/bin/touch /tmp/dhcpd.leases
ExecStartPre=/usr/bin/cat /etc/netns/sepian/dhcpd.conf
ExecStart=/usr/bin/dhcpd -f -4 -q -cf /etc/netns/sepian/dhcpd.conf -lf /tmp/dhcpd.leases
NetworkNamespacePath=/var/run/netns/sepian
RuntimeDirectory=dhcpd4
User=dhcp
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW
ProtectSystem=full
ProtectHome=on
KillSignal=SIGINT
# We pull in network-online.target for a configured network connection.
# However this is not guaranteed to be the network connection our
# networks are configured for. So try to restart on failure with a delay
# of two seconds. Rate limiting kicks in after 12 seconds.
RestartSec=2s
Restart=on-failure
StartLimitInterval=12s

[Install]
WantedBy=multi-user.target

类似地,引用的 dhcpd.conf:

# cat /etc/netns/sepian/dhcpd.conf
option domain-name-servers 192.168.20.2;
option subnet-mask 255.255.255.0;
option routers 192.168.0.1;
subnet 192.168.0.0 netmask 255.255.255.0 {
    range 192.168.0.100 192.168.0.199;
}

重要的一点是,这告诉虚拟机将流量路由到 192.168.0.1(网ns 中桥的 IP)并且 DNS 可以通过 192.168.20.2 提供(通过 sepia-bounce 虚拟机上的systemd-resolved)。

在虚拟机中,网络看起来像:

[root@archlinux ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
[root@archlinux ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.100/24 metric 1024 brd 192.168.0.255 scope global dynamic enp0s3
valid_lft 28435sec preferred_lft 28435sec
inet6 fe80::5054:ff:fe12:3456/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
[root@archlinux ~]# systemd-resolve --status
Global
        Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Fallback DNS Servers: 1.1.1.1#cloudflare-dns.com 9.9.9.9#dns.quad9.net 8.8.8.8#dns.google 2606:4700:4700::1111#cloudflare-dns.com 2620:fe::9#dns.quad9.net 2001:4860:4860::8888#dns.google

Link 2 (enp0s3)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
        Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 192.168.20.2
DNS Servers: 192.168.20.2

Link 3 (sit0)
Current Scopes: none
        Protocols: -DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported

最后,一些其他网络配置要考虑:

  • 在您的机器上运行虚拟机,完全访问主机网络堆栈。如果您有 sepia vpn,这可能不需要太多配置就会工作。

  • 如上所述,在 netns 中运行虚拟机,但也在同一 netns 中设置 sepia vpn。这有助于避免使用 sepia-bounce 虚拟机。您仍然需要配置桥和 sepia VPN 之间的路由。

  • 如上所述,在 netns 中运行虚拟机,但仅在同一 netns 中使用本地 vstart 集群(可能在另一个虚拟机中)。

第四步:在您的虚拟机中挂载 CephFS 文件系统

本指南使用 sepia 实验室中的一台机器上的 vstart 集群。因为 mon 地址会随着任何新的 vstart 集群而更改,所以它将使我们对通过内核驱动器挂载 CephFS 的虚拟机的任何静态配置失效。因此,我们应该在挂载之前创建一个脚本来获取我们的 vstart 集群配置:

#!/bin/bash
# kmount.sh -- mount a vstart Ceph cluster on a remote machine

# the cephx client credential, vstart creates "client.fs" by default
NAME=fs
# static fs name, vstart creates an "a" file system by default
FS=a
# where to mount on the VM
MOUNTPOINT=/mnt
# cephfs mount point (root by default)
CEPHFS_MOUNTPOINT=/

function run {
    printf '%s\n' "$*" >&2
    "$@"
}

function mssh {
    run ssh vossi04.front.sepia.ceph.com "cd ceph/build && (source vstart_environment.sh; $1)"
}

# create the minimum config (including mon addresses) and store it in the VM's ceph.conf. This is not used for mounting; we're storing it for potential use with `ceph` commands.
mssh "ceph config generate-minimal-conf" > /etc/ceph/ceph.conf
# get the vstart cluster's fsid
FSID=$(mssh "ceph fsid")
# get the auth key associated with client.fs
KEY=$(mssh "ceph auth get-key client.$NAME")
# dump the v2 mon addresses and format for the -o mon_addr mount option
MONS=$(mssh "ceph mon dump --format=json" | jq -r '.mons[] | .public_addrs.addrvec[] | select(.type == "v2") | .addr' | paste -s -d/)

# turn on kernel debugging (and any other debugging you'd like)
echo "module ceph +p" | tee /sys/kernel/debug/dynamic_debug/control
# do the mount! we use the new device syntax for this mount
run mount -t ceph "${NAME}@${FSID}.${FS}=${CEPHFS_MOUNTPOINT}" -o "mon_addr=${MONS},ms_mode=crc,name=${NAME},secret=${KEY},norequire_active_mds,noshare" "$MOUNTPOINT"

那将像这样运行:

$ sudo ip netns exec sepian ssh root@192.168.0.100 ./kmount.sh
...
mount -t ceph fs@c9653bca-110b-4f70-9f84-5a195b205e9a.a=/ -o mon_addr=172.21.10.4:40762/172.21.10.4:40764/172.21.10.4:40766,ms_mode=crc,name=fs,secret=AQD0jgln43pBCxAA7cJlZ4Px7J0UmiK4A4j3rA==,norequire_active_mds,noshare /mnt
$ sudo ip netns exec sepian ssh root@192.168.0.100 df -h /mnt
Filesystem                                   Size  Used Avail Use% Mounted on
fs@c9653bca-110b-4f70-9f84-5a195b205e9a.a=/  169G     0  169G   0% /mnt

如果您遇到困难,可能是:

  • 运行 vstart 集群的节点的防火墙正在阻止您的连接。

  • 您的网络堆栈中存在一些配置错误。

  • 挂载配置不正确。

第五步:在 teuthology 中测试内核更改

ceph 内核 git 仓库中有 3 个静态分支由 Ceph 团队管理:

  • for-linus: 由主要的 Ceph 维护者管理的分支,用于与 Linus Torvalds(上游)共享更改。不要推送到此分支。

  • master: 计划发送给 Linus 的补丁的暂存区。不要推送到此分支。

  • testing用于需要更广泛质量测试(通过夜宵或常规 Ceph 质量测试)的杂项补丁的暂存区。推送到您认为几乎准备好进行上游接受的补丁。

您也可以将wip-$feature分支推送到ceph-client.git仓库,它将由 Jenkins 构建。然后查看Shaman.

一旦内核分支被构建,您可以通过fsCephFS 质量测试套件:

$ teuthology-suite ... --suite fs --kernel wip-$feature --filter k-testing

The k-testingfilter 正在查找通常设置testing内核分支的片段,用于常规质量测试。也就是说,fs套件testing分支中的内容。我们通过--kernel wip-$featuree开关覆盖了该内核分支的选择。

Note

没有k-testingfs套件也将运行使用 ceph-fuse 或标准内核、libcephfs 测试和其他在评估内核更改时可能不感兴趣的测试。

实际的覆盖是通过k-testing.yaml片段中的 Lua 合并脚本控制的。有关更多详细信息,请参阅该文件。

由 Ceph 基金会带给您

Ceph 文档是一个社区资源,由非盈利的 Ceph 基金会资助和托管Ceph Foundation. 如果您想支持这一点和我们的其他工作,请考虑加入现在加入.