Stratovirt + Unikraft + Redis

 技术  stratovirt  unikraft 󰈭 2267字

尝试在stratovirt虚拟机上运行基于unikraft的redis, 并测试1G内存可以运行多少个实例, 但是行百里者半九十, 折腾了半天的网桥和DHCP, 又换了红帽, arch和debian系列的rootfs, 最终ubuntu总算把kraft成功build起来, 结果最后一步死活不行, 所以姑且记录一下, 但是意义寥寥…

基于stratovirt实现unikraft redis

安装stratovirt虚拟机

首先下载源码并编译项目.

1git clone https://gitee.com/openeuler/stratovirt.git
2cargo build --release --target ${arch}-unknown-linux-gnu

获取linux kernel镜像:

1wget https://repo.openeuler.org/openEuler-22.09/stratovirt_img/x86_64/std-vmlinuxz -O std-vmlinux.bin

在rootfs的选择上, openEuler社区提供了打包好的rootfs系统, 但是该Linux系统是基于RedHat的发行版, 且默认的空间大小只有1G, 不能满足安装各类软件包的需求, 并且发现对unikraft的兼容性不好. 遂又单独下载了Debian系的发行版进行尝试, 这里选用Ubuntu的rootfs镜像文件.

1# 社区提供的rootfs
2# wget https://repo.openeuler.org/openEuler-22.09/stratovirt_img/x86_64/openEuler-22.09-stratovirt-x86_64.img.xz -O rootfs.img.xz
3
4# Ubuntu
5wget https://uk.lxd.images.canonical.com/images/ubuntu/bionic/amd64/default/20221115_07:42/rootfs.tar.xz

创建镜像文件, 为其分配足够的空间(10G), 将压缩包中的目录结构拷贝进入该镜像文件, 最后chroot进入该系统, 为root用户设置密码即可.

 1$ touch ubuntu.img
 2$ dd if=/dev/zero of=./ubuntu.img bs=1G count=10
 3$ mkfs.ext4 ubuntu.img
 4 
 5$ sudo mount ubuntu.img /mnt
 6$ sudo mv PATH/TO/rootfs.tar.xz /mnt
 7$ cd /mnt
 8$ tar -xvf rootfs.tar.xz
 9 
10$ sudo arch-chroot /mnt
11
12# in Ubuntu rootfs
13$ passwd
14...

至此, 已经可以启动stratovirt虚拟机了.

1stratovirt/target/release/stratovirt \
2	-kernel  vmlinux.bin\
3	-smp 1 \
4	-m 1024m \
5	-append "console=ttyS0 pci=off reboot=k rw quiet panic=1 root=/dev/vda" \
6	-drive file=ubuntu.img,id=rootfs,direct=off \
7	-device virtio-blk-device,drive=rootfs,id=rootfs \
8	-qmp unix:stratovirt.sock,server,nowait \
9	-serial stdio

效果如下:

配置虚拟网卡

此时, 我们有了一个stratovirt虚拟机, 但是该虚拟机仍然无法上网, 为此需要为其配备虚拟网卡, 连通网络.

tap是一个虚拟的二层设备, 通过虚拟网桥与宿主机真实的网卡相连接, 从而可以实现虚拟机网络.

1$ brctl addbr qbr0
2$ ip tuntap add tap0 mode tap
3$ brctl addif qbr0 tap0
4$ ifconfig qbr0 up; ifconfig tap0 up

需要注意, 网桥的不当配置可能会导致宿主机无法上网, 因而需要仔细关注IP地址和路由的设置.

首先通过ip routeifconfig等指令检查宿主机的IP和路由情况, 发现联通校园网, 有线网卡IP为192.168.0.37, 且通过192.168.1.1作为DHCP服务器. 因而将该网卡加入到上述创建的qbr0网桥中, 并禁用该接口, 仅仅保留qbr0启用, 来保证外界的正确路由.

1# 加入本机的真实物理网卡
2$ btctl addif enp58s0
3$ ip link set enp58s0 down
4$ ip link set qbr0 up
5$ ifconfig qbr0 192.168.0.100

此时, 宿主机应该能够借助网桥qbr0与互联网互相连通. 下面配置虚拟机的虚拟网卡, 并为其配置路由信息.

在stratovirt中添加参数, 启用虚拟设备tap:

1-netdev tap,id=tap123,ifname=tap0,vhost=on\
2-device virtio-net-device,netdev=tap123,id=tapid,mac=12:34:56:78:9A:BC \

再次进入到虚拟机, 此时查看ip link会多出来一个eth2, 拥有预设的MAC地址12:34:56:78:9A:BC, 因而可以确定这就是我们为其分配的Tap设备. 启用tap, 为其分配IP, 同时指定DHCP服务器. 此时虚拟机可以ping通宿主机, 也能ping通互联网的IP地址.

1ip link set eth2 up 
2ip addr add dev eth2 192.168.0.101/23 
3ip route add default via 192.168.1.1 dev eth2 proto dhcp src 192.168.0.101 metric 100 

为了能够解析域名, 再次为虚拟机配置DNS服务器的地址.

1cat << EOF > /etc/resolv.conf
2nameserver 114.114.114.114
3nameserver 8.8.8.8
4EOF

至此, 虚拟机能够正常访问到互联网.

安装Unikraft/kraft

根据github kraft说明, 安装依赖库.

1apt-get install -y --no-install-recommends build-essential libncurses-dev libyaml-dev flex git wget socat bison unzip uuid-runtime;

再通过pip3安装kraft管理器:

1pip3 install git+https://github.com/unikraft/kraft.git@staging

在通过python-pip安装kraft时会出现几个问题:

  • 由于不可抗力, 对github的访问受限, 因而只能将源码下载到本地后再本地安装, 具体来说需要以下几步:
1# 安装依赖
2pip install -r requirement.txt
3
4# 通过setup.py安装kraft
5python3 setup.py build
6python3 setup.py install
  • 经过测试, 若python3的版本低于3.6则会产生错误(SyntaxError: future feature annotations is not defined ), 而ubuntu默认的python3版本较低, 需要升级后才能成功安装kraft. 但是Debian系的apt对包的管理好像较为混乱, 导致ubuntu上同时存在多个大小版本的python和pip; 反复尝试后未果, 只能通过pyenv创建虚拟环境, 在其中运行高版本的python和pip, 安装karft.
 1# 安装pyenv
 2curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
 3
 4# 增加环境变量, 启用pyenv
 5export PATH="$HOME/.pyenv/bin:$PATH"
 6eval "$(pyenv init -)"
 7eval "$(pyenv virtualenv-init -)"
 8
 9# 安装高版本python, 并全局启用
10pyenv install 3.9
11pyenv global 3.9

至此, kraft安装成功.

配置kraft redis

根据github app-redis的说明, 获取kraft.yaml. 由于我们目前已经在虚拟环境stratovirt中, 因而采用linuxu作为kraft的目标平台, 直接在当前环境中执行应用, 而不再采用kvm(qemu)再创建一层虚拟机的形式.

1kraft init
2kraft configure -p linuxu -m x86_64
3kraft build

在configure和build阶段, 存在诸多问题:

  • 首先需要修改kraft.yaml中的version为一个合法的字符串, 这里改为0.10即可.

  • 需要修改select, poll的动态链接情况, 在.unikraft/libs/redis/Config.uk中的选项LIBREDIS_COMMON中加入select LIBPOSIX_SOCKETselect LIBPOSIX_EVENT的参数.

  • 修改断言情况,需要在文件 修改 .unikraft/unikraft/lib/posix-socket/include/uk/socket_driver.h 下的代码,修改如下

    1// __used __section("." _POSIX_SOCKET_FAMILY_SECNAME(lib, fam))
    2__used __align(8) __section("." _POSIX_SOCKET_FAMILY_SECNAME(lib, fam))
    3
    4// struct posix_socket_driver
    5struct __align(8) posix_socket_driver

    使得结构体进行强制对齐。防止在运行libposix_socket下的driver.c时,socket->ops由于结构体不对齐导致断言失败的问题。

最终编译成功后, 运行kraft run, 启动redis.

但是运行后程序立刻结束, 且没有Log可以检查, 同时光标也消失.

最终的问题始终无法解决, 比较怀疑是kraft+redis的bug.

参考资料

性能测试-内存底噪

Stratovirt22.09用户指南

Unikraft 文档

嗨! 这里是 rqdmap 的个人博客, 我正关注 GNU/Linux 桌面系统, Linux 内核, 后端开发, Python, Rust 以及一切有趣的计算机技术! 希望我的内容能对你有所帮助~
如果你遇到了任何问题, 包括但不限于: 博客内容说明不清楚或错误; 样式版面混乱等问题, 请通过邮箱 rqdmap@gmail.com 联系我!
修改记录:
  • 2024-01-05 00:01:57合并小众分类的文章
  • 2023-05-29 23:05:14大幅重构了python脚本的目录结构,实现了若干操作博客内容、sqlite的助手函数;修改原本的文本数 据库(ok)为sqlite数据库,通过嵌入front-matter的page_id将源文件与网页文件相关联
  • 2023-05-08 21:44:36博客架构修改升级
  • 2022-11-20 17:46:12修改了居中的样式
  • 2022-11-19 20:22:28Stratovirt: First commit
Stratovirt + Unikraft + Redis