注意
本文档适用于 Ceph 的开发版本。
测试Linux内核CephFS驱动程序变更
本指南将解释一种(带有个人偏好)针对开发集群测试Linux内核客户端的方法。我们将尽量减少对内核构建或任何相关最佳实践的现有知识假设。
注意
对于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
注意
您也可以使用Ceph内核QA配置来构建内核。
现在我们有了一个内核配置,它包含了您正在构建的架构的合理默认值。下一步是启用将构建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替代品)。
注意
最好不要将任何内容构建为内核模块。否则,您将需要在虚拟机的根驱动器上运行make modules_install。
现在,合并配置。
scripts/kconfig/merge_config.sh .config ~/.ceph.config
最后,构建内核
make -j
注意
本文档不讨论如何获取您发行版的相关实用程序来实际构建内核,例如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并设置vstart集群。它有足够的资源使Ceph构建非常快(冷构建约5分钟),并且有本地磁盘资源来运行一个像样的vstart集群。
为了避免使本文档过于复杂,我将介绍用于测试内核的以下主要配置:
在创建内核虚拟机的机器和sepia-bounce虚拟机之间设置wireguard隧道
使用
systemd-resolved作为DNS解析器,并监听192.168.20.2(而不是仅监听localhost)连接到sepia VPN并使用systemd resolved更新脚本配置
systemd-resolved以使用通过sepia VPN的DHCP获取的DNS服务器配置
firewalld以允许wireguard流量,并对流向sepia vpn的流量进行地址伪装和转发
下一步是将内核虚拟机连接到sepia-bounce虚拟机。网络命名空间对于此目的很有用,可以隔离虚拟机的流量/路由规则。对我来说,我使用自定义的systemd一次性单元来编排此过程,它看起来像这样:
# 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来配置它为虚拟机创建的tap设备
#!/bin/bash
tap=$1
ip link set "$tap" master br0
ip link set dev "$tap" up
它只是简单地将新的tap设备插入到网桥中。
这一切都很好,但我们现在缺少最后一个关键步骤。虚拟机的IP地址是什么?有两种选择:
配置静态IP,但必须修改虚拟机的根设备网络堆栈配置
使用DHCP并配置虚拟机的根设备始终使用dhcp来配置其以太网设备地址
第二种选择设置起来更复杂,因为您现在必须运行DHCP服务器,但它为测试时根据需要添加更多虚拟机提供了最大的灵活性。
修改后(或“hacked”)的标准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(netns中网桥的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团队管理的ceph kernel git repository中有3个静态分支:
for-linus:由主要Ceph维护者管理的分支,用于与Linus Torvalds(上游)共享变更。不要推送到此分支。
master:计划发送给Linus的补丁的暂存区。不要推送到此分支。
testing:需要更广泛QA测试(通过夜间构建或常规Ceph QA测试)的各种补丁的暂存区。推送您认为即将准备好接受上游的补丁。
您也可以将一个wip-$feature分支推送到ceph-client.git仓库,该分支将由Jenkins构建。然后可以在Shaman中查看构建结果。
一旦内核分支构建完成,您可以通过fs CephFS QA套件进行测试
$ teuthology-suite ... --suite fs --kernel wip-$feature --filter k-testing
k-testing过滤器正在寻找通常为常规QA设置内核testing分支的片段。也就是说,fs套件会定期针对内核testing分支中的内容运行测试。我们正在通过--kernel wip-$featuree开关覆盖内核分支的选择。
注意
如果不过滤k-testing,fs套件还将运行使用ceph-fuse或stock内核的作业、libcephfs测试以及其他在评估内核变更时可能不感兴趣的测试。
实际的覆盖是通过k-testing.yaml片段中的Lua合并脚本控制的。有关详细信息,请参阅该文件。