尝试在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 route
和ifconfig
等指令检查宿主机的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_SOCKET
和select LIBPOSIX_EVENT
的参数. -
修改断言情况,需要在文件 修改 .unikraft/unikraft/lib/posix-socket/include/uk/socket_driver.h 下的代码,修改如下
Text1// __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.