osnosn

  博客园 :: 首页 :: 博问 :: 闪存 :: :: 联系 :: 订阅 订阅 :: 管理 ::

kvm_qemu_运行_openwrt_armvirt_img_自己创建combine映像

转载注明来源: 本文链接 来自osnosn的博客,写于 2022-09-08.

参考

kvm 安装

  • 仅字符界面,无 GUI。
    apt install libvirt-daemon-system virtinst qemu-system-arm

方法一

  • 使用armvirt架构的虚拟镜像来测试LEDE
  • openwrt/openwrt/target/linux/armvirt/README
  • 下载 https://mirrors.aliyun.com/openwrt/releases/22.03.0/targets/armvirt/64/
    openwrt-22.03.0-armvirt-64-Image , openwrt-22.03.0-armvirt-64-Image-initramfs , openwrt-22.03.0-armvirt-64-rootfs.cpio.gz , 有 gz 结尾的文件,用 gunzip 解压。
  • 进入 tmux 中,(因为op启动后,所有显示就直接输出了,占用了这个终端。如果套上tmux,就比较方便了。)
    测试 qemu-system-aarch64 -M virt -m 1024m -kernel openwrt-22.03.0-armvirt-64-Image-initramfs -no-reboot -nographic -nic user -nic user -cpu cortex-a53 -smp 4
    OK, 之后退出/杀掉。(这个是跑在内存中,所有更改,重启后都会丢失)
  • 当前目录 mkdir root-armvirt; cd root-armvirt; cpio -idv -F ../openwrt-22.03.0-armvirt-64-rootfs.cpio
    cd ..; tmux;
    qemu-system-aarch64 -nographic -M virt -m 64 -kernel openwrt-22.03.0-armvirt-64-Image \
        -no-reboot -nographic -nic user -nic user -cpu cortex-a53 -smp 4 \
        -fsdev local,id=rootdev,path=root-armvirt/,security_model=none \
        -device virtio-9p-pci,fsdev=rootdev,mount_tag=/dev/root \
        -append 'rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p'
    
  • 这个vm的网络,是和实体机共享网卡的方式,host方式。如果需要开放vm的端口,需要在创建时指定端口的映射。

方法二,用别人创建好的 combine 的 img 映像

  • 没测试的。
    mslovecc/openwrt-armvirt-v22.03
    zhkong/openwrt_arm64_uefi
    cy726/Build-OpenWrt-arm64
  • 以下的测试。
    varoudis/openwrt_arm64_uefi
    Arm64 (or armvirt) with UEFI boot?
  • 下载文件,https://www.dropbox.com/s/gpqdrzv1z9mt0ou/openwrt-arm64-efi-generic-ext4-combined.img.gz?dl=0
    文件75MB,解压后1.2GB。内部空间984MB,Used:221MB,Available:747MB。
  • 这个映像有点问题。不知道哪个服务导致的问题。这个映像里头,有好多不知名的东西。
    • 如果只给一个网卡,op只有lan口,但br-lan和eth0 都会通过dhcp获取到一个IP。致使op会有多个缺省路由,导致op无法访问外网。被op自身防火墙挡住了。
    • 如果给俩个网卡,op有lan和wan。如果lan口有dhcp,lan还是会获取一个ip和网关。最终还是无法上网。
    • 必须给op两个网卡,一个有dhcp做wan,一个无dhcp做lan,才行。
  • 系统的virbr0的default网络,就不动它了。新增一个virbr1 叫 lan-op 的网络,不带DHCP,不带NAT。就是隔离网络,不能连外网。
    • 也可以根据需要,保留nat。去掉<forword mod='nat />的注释即可。
      <!--
       文件名: lan-op.xml
      -->
      <network>
        <name>lan-op</name>
      <!--
        <forward mode='nat'/>
      -->
        <bridge name='virbr1' stp='on' delay='0'/>
        <ip address='192.168.22.22' netmask='255.255.255.0'>
        </ip>
      </network>
      
    • virsh net-define lan-op.xml; virsh net-start lan-op; virsh net-autostart lan-op
  • 执行以下命令,创建vm。
    virt-install \
          --virt-type kvm \
          --name op-arm64 \
          --memory 512 \
          --vcpus 2 \
          --cpu host-passthrough \
          --os-variant linux \
          --network bridge=virbr1,model=virtio \
          --network bridge=virbr0,model=virtio \
          --graphics vnc \
          --import \
          --noautoconsole \
          --autostart \
          --disk path=/var/lib/libvirt/images/openwrt-arm64-efi-generic-ext4-combined.img,bus=virtio,format=raw
    
  • 列出所有的vm,virsh list --all
  • virsh, virt-install 操作,参考【CentOS8_debian11_远程ssh连接_在线安装KVM_虚拟化嵌套_安装客户机openwrt_NAT端口映射
    • 如果操作错误,想删除这个vm。强制关机virsh destroy op-arm64,删除vmvirsh undefine op-arm64
    • 如果不删除这个vm,只禁止自动启动,virsh autostart --disable op-arm64
  • 第一次启动op,修改lan口IP。
    virsh console op-arm64,回车进入shell,修改 /etc/config/network,然后/etc/init.d/network reload 或 restart
    或用 uci命令修改IP,见【制作免配置固件】,【官方文档:The UCI system】。
    uci set network.lan.ipaddr='192.168.xx.10'
    uci commit network
    /etc/init.d/network reload
    
    最后 按 ctrl+] 退出 console。之后就可以使用浏览器访问web配置界面。
  • 配置一下op使用的dns,否则不能解析域名。
    • Network->DHCP and DNS->DNS forwording。如果是内网使用,还要去掉"丢弃RFC1918"项的勾。(有效)。
      命令行,改/etc/config/dhcp,在config dnsmasq中,有list server '8.8.8.8'option rebind_protection '0'
      • 这个映像有问题,在 System->Startup 中,需要禁用 https-dns-proxy 才行。否则会出来捣乱。
    • 或者,设置WAN口,使用自定义dns。(可以)。
    • 或者,设置LAN口,使用自定义dns。(本应该可以。但此映像无效,不知哪个服务在捣乱)。
  • 这个映像的源,指向了 snapshots。修改一下。
    sed -i s_snapshots_releases/22.03.0_ /etc/opkg/distfeeds.conf
    sed -i s_arm64/efi_armvirt/64_ /etc/opkg/distfeeds.conf
  • 修改 /etc/opkg.conf 不检查签名。就可以 opkg update 操作了。
    • 只能装普通包,不能装 kmod 包。
  • 如果使用 armvirt-64 的 sdk 编译了第三方 ipk。
    • 编译的包是基于aarch64_cortex-a53架构的。这个映像是基于aarch64_generic的,会拒绝安装。其实是可以运行的。
    • opkg print-architecture 打印出本系统支持的架构。
    • 解决办法,临时在 /etc/opkg.conf 中加入一行 arch aarch64_cortex-a53 10,装完第三方包后,再删除这一行。
      如果有依赖原版的包。那就把opkg print-architecture输出的内容,加上上面这行,都加进去,装完再删。
  • golang 交叉编译的程序,在op上运行,time.Now()输出的时间,时区不对。是因为op中缺失/etc/localtime文件。
    从Linux系统中copy一个过去就好了。
  • 检查一下,openwrt系统中 ntp服务器的ip,是否能对时成功。有的服务比较依赖时间的准确度。

方法三,自己创建 combine 的 img 映像,自己编译内核

  • 参考【Building OpenWrt from Scratch for ARM64 UEFI ACPI VM

    参考这篇文章的后半部分,创建 img

  • 最终发现,官方的 openwrt-22.03.0-armvirt-64-Image
    缺少这三个支持,CONFIG_EFI_STUB=y, CONFIG_EFI=y, CONFIG_EFI_VARS=y
  • gurb 能启动,kernel无法启动。
  • 注意: 制作 img 中,只需执行 grub-mkimage, 无需执行 grub-install

    参考这篇文章,从源码编译

  • 同时参考【官方文档】。
  • 2022-11月,重新编译内核。从源码编译。op-22.03.2
    # 系统为 debian-11.
    # apt install ... 安装编译所需的必要包
    git clone https://git.openwrt.org/openwrt/openwrt.git  #获取源码
    cd openwrt
    ln -s ../dl dl    #可以创建一个dl目录的链接,与其他的sdk共用一个dl目录,避免重复下载
    git tag
    git checkout v22.03.2  #切到 v22.03.2
    ./scripts/feeds update -a   #这步会重新生成.config文件。下载/更新feeds
    ./scripts/feeds install -a
    wget https://downloads.openwrt.org/releases/22.03.2/targets/armvirt/64/config.buildinfo
    cp config.buildinfo .config  #替换为官方配置
    cat << __END__ >> target/linux/armvirt/config-5.10
    CONFIG_EFI_STUB=y
    CONFIG_EFI=y
    CONFIG_EFI_VARS=y
    CONFIG_ARCH_SUPPORTS_ACPI=y
    CONFIG_ACPI=y
    __END__
    make menuconfig       # 未作修改,直接退出,退出时保存一个新的.config
     # 如果不保存.config,在 make world时也会弹出这个 menuconfig要你保存。
    make -j3 kernel_menuconfig   # 需要下载linux内核源码。进入后,直接退出,未作修改。保存或者不保存都行。
     # kernel配置保存在 target/linux/armvirt/config-5.10
    make -j3 defconfig
    make -j3 download     # 需要下载很多,并发不要开太多
    make clean
    make -j6 world V=s    # 快完成的时候,还会下载几个包
     # make world V=s 会问问题,一路回车用默认值。不保存kernel配置,问的多些。保存了kernel配置,问的少点。
     # 完成后,Image和rootfs都在 bin/targets/armvirt/64/目录中。
     # 完成后,这个源码目录占用14.0GB,其中/dl/目录496MB。
    
  • 2023-03月,重新编译内核。从源码编译。另一次的做法。op-22.03.3
    # 系统为 debian-11.
    # apt install ... 安装编译所需的必要包
    git clone https://git.openwrt.org/openwrt/openwrt.git  #获取源码
    cd openwrt
    ln -s ../dl dl    #可以创建一个dl目录的链接,与其他的sdk共用一个dl目录,避免重复下载
    git tag
    git checkout v22.03.3  #切到 v22.03.3
    ./scripts/feeds update -a   #这步会重新生成.config文件。下载/更新feeds
    ./scripts/feeds install -a
    wget https://downloads.openwrt.org/releases/22.03.3/targets/armvirt/64/config.buildinfo
    cp config.buildinfo .config  #替换为官方配置
    cat << __END__ >> target/linux/armvirt/config-5.10
    CONFIG_EFI_STUB=y
    CONFIG_EFI=y
    CONFIG_EFI_VARS=y
    CONFIG_ARCH_SUPPORTS_ACPI=y
    CONFIG_ACPI=y
    __END__
     # 以上5条不能放到.config中,这是kernel的配置,不是映像包的配置。
    make menuconfig       # 未作修改,直接退出,退出时保存一个新的.config
     # 如果不保存.config,在 make world时也会弹出这个 menuconfig要你保存。
    make -j3 defconfig
    make -j3 download     # 需要下载很多,并发不要开太多
    make -j6 clean world V=s # 快完成的时候,还会下载几个包
     # make world V=s 会问问题,一路回车用默认值。
     # 此次编译,有包冲突。只好用 menuconfig 调整,去掉了很luci等等包。才成功。
     # .config的配置,不影响内核 Image的编译。只影响 root-fs 和 initramfs 中的内容。
     # 完成后,Image和rootfs都在 bin/targets/armvirt/64/目录中。
    
    有个想法:因为只是为了重编内核,不去下载 feeds的东西,应该也可以。(这个想法 未测试,下次再说)
  • 编译后的文件,【备份在这里】。
    • 用 gunzip 解压。
    • 备份文件:
      openwrt-22.03.2-armvirt-64-Image.gz
      openwrt-22.03.2-armvirt-64-generic-ext4-combined-efi.img.gz
      openwrt-22.03.3-armvirt-64-Image.gz
      openwrt-22.03.3-armvirt-64-generic-ext4-combined-efi.img.gz
      
    • rootfs去官网下载,openwrt-22.03.x-armvirt-64-rootfs-ext4.img.gz
  • 制作img启动映像。
    ls -l openwrt-22.03.2-armvirt-64-Image        # 约12MB
    gunzip -k openwrt-22.03.2-armvirt-64-rootfs-ext4.img.gz  # 得到约105MB的img文件
    dd if=/dev/zero of=disk.img bs=1M count=200   # 创建一个200MB的空映像,第二次我做了140MB.
    su root
    losetup -f disk.img
    losetup -a   # 看到,挂在 loop0
     # EFI分区只放内核的Image。预计占用12-15MB,总空间大于20MB就足够了。
    fdisk /dev/loop0    # 创建两个分区。
      g       # gpt 分区
      n       # 创建分区1
        1
        回车  # 默认值2048
        +30M
      t       # 改分区1类型
        1     # 类型 EFI System
      n       # 创建分区2, 默认类型 Linux filesystem
        2
        回车  # 默认值
        回车  # 默认值
      w
    partx -a /dev/loop0      # 或者 partx -u /dev/loop0
    mkfs.vfat /dev/loop0p1   # 格式化为FAT32
    dd if=openwrt-22.03.2-armvirt-64-rootfs-ext4.img of=/dev/loop0p2 bs=1M
    resize2fs /dev/loop0p2
    lsblk -o PATH,UUID,PARTUUID /dev/loop0     # 查看 UUID 和 PARTUUID
     # 下面内容中 fs_uuid 替换为自己的loop0p1的UUID。
    cat << __END__ > grub-early.cfg
    search.fs_uuid E555-D276 root
    set prefix=(\$root)'/boot'
    configfile \$prefix/grub.cfg
    __END__
    mkdir part1
    mount /dev/loop0p1 part1
    mkdir -p part1/EFI/BOOT/
    cd part1/EFI/BOOT/
    grub-mkimage -c ../../../grub-early.cfg -p /boot -o BOOTAA64.EFI -O arm64-efi boot chain configfile fat linux ls part_gpt reboot serial efi_gop search_fs_uuid
    cd ../..
    mkdir boot
    cd boot/
     # 下面内容中的 PARTUUID 是 loop0p2 的(不是UUID)。需自己替换。
    cat << __END__ > grub.cfg
    serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 --rtscts=off
    terminal_input console serial; terminal_output console serial
    set default="0"
    set timeout="5"
    menuentry "OpenWrt" {
    	linux /boot/vmlinuz root=PARTUUID=98e93560-8d7d-7e46-8812-916f21d11821 rootwait console=tty0  console=ttyS0,115200n8 noinitrd
    }
    menuentry "OpenWrt (failsafe)" {
    	linux /boot/vmlinuz failsafe=true root=PARTUUID=98e93560-8d7d-7e46-8812-916f21d11821 rootwait  console=tty0 console=ttyS0,115200n8 noinitrd
    }
    __END__
    cp ../../openwrt-22.03.2-armvirt-64-Image  vmlinuz
    cd ../..
    umount part1
    partx -d /dev/loop0
    losetup -d /dev/loop0
    exit         # 退出 su root
    
  • img启动映像,能够成功启动,内核也成功启动,进入shell,网口也都能获取IP。
    分区1已用12MB/分区2已用12MB。不过,忘了选择luci,用浏览器访问配置页面,什么都没有,没法使用。
  • 使用官方的 openwrt-22.03.2-armvirt-64-rootfs-ext4.img.gz
    加上自己编译的 openwrt-22.03.2-armvirt-64-Image.gz,重新做一遍,做 140MB的映像。
    成功启动,系统干净,可以使用。WEB配置页面只有基本配置。
    做好的映像:【openwrt-22.03.2-armvirt-64-generic-ext4-combined-efi.img.gz 压缩包9MB】
    可以正常opkg update, 可以安装使用官方包(架构:aarch64_cortex-a53)。
    • opkg install kmod-fs-vfat, 就可以 mount /dev/vda1 /boot, 挂载boot分区。
    • 22.03.2 映像总大小140MB,空间占用(已用/可用/总大小): 分区1(12/18/30MB), 分区2(14/92/108MB)。
      22.03.3 映像总大小140MB,空间占用(已用/可用/总大小): 分区1(11.2/18.7/29.9MB), 分区2(13.4/91.7/107.3MB)。
  • 如果觉得空间不够大,那就自己扩容吧。参考【openwrt_21.02_img_空间扩容_改分区表大小】。
  • 或者自己制作一个img映像,自己设置空间大小。

虚拟机op接受kvm关机指令

  • 使用这个自己重新编译的内核。
    在 op内部,执行 halt可以关掉。
    在外部用virsh shutdown xxx关不掉
    在外部用virsh destroy xxx可以强制关掉。
  • 以前在Hyper-v中跑op,op能迅速响应"关机"指令。无需 acpid或 qemu-ga。
  • opkg install acpid (2个依赖包,约占100KB),op不理会shutdown命令
    再次编译内核,加入,
    CONFIG_ACPI_CONFIGFS=y
    CONFIG_ACPI_TINY_POWER_BUTTON=y
    
    编译后,替换内核。启动 acpid服务。op还是不理会 virsh 的关机命令。放弃
  • opkg install qemu-ga (op22-armvirt,有7个依赖包,约占3.9MB),重启 op后才生效
    可以接受 virsh shutdown 的命令了。(无需 acpid服务,可卸载acpid)。
    • virt-install 生成的虚拟机,默认已经生成管理 channel。
      virsh edit xxxx可以看到,在<devices>...</devices>中,有这几行。
      <channel type='unix'>
        <target type='virtio' name='org.qemu.guest_agent.0'/>
        <address type='virtio-serial' controller='0' bus='0' port='1'/>
      </channel>
      
      如果是用virt-manager图形界面创建的虚机,见【如果有图形桌面_virt-manager】。
      需要手动添加一个"信道/channel"设备,名称org.qemu.guest_agent.0
    • 在op中,没装qemu-ga前,有 /dev/vport2p1 这个字符设备。
      安装 qemu-ga并重启 op后,脚本会把这个设备链接到 /dev/virtio-ports/org.qemu.guest_agent.0
      qemu-ga 进程就可以启动成功,接受 virsh的命令。
    • qemu-ga 的配置文件/etc/qemu/qemu-ga.conf,op中没这个文件,需要时,自己创建。配置例子如下:
      [general]
        blacklist = guest-ssh-remove-authorized-keys,guest-ssh-add-authorized-keys,guest-ssh-get-authorized-keys,guest-get-devices,guest-get-osinfo,guest-get-users,guest-get-host-name,guest-exec,guest-exec-status,guest-set-user-password,guest-network-get-interfaces,guest-file-seek,guest-file-write,guest-file-read,guest-file-open
      
  • 当你关闭/重启实体机时,系统会先关闭所有服务,包括关闭 KVM 的 libvirtd 服务,
    libvirtd 会发出 shutdown 指定给所有的虚拟机。
    如果虚拟机不予理会。那就要等到超时时间,通常是300秒每个虚机,才强制杀掉虚拟机,才能停掉 libvirtd 服务。
    超时定义在/etc/init.d/libvirt-guests/usr/lib/systemd/system/libvirt-guests.service
    /etc/default/libvirt-guests(debian),/etc/sysconfig/libvirt-guests(centos)。
    所以,你会觉得很奇怪,实体机的表现,关机/重启操作之后,5-10分钟内机器没反应,不知道它在忙什么,也不知道要等多久。

映像文件转换格式

  • 请看:【映像文件转换格式
  • 可以把 img 的 raw格式转为 hyper-v(vhdx), vmware(vmdk), virtualbox(vdi), xen(img)... 使用的格式。

用ImageBuilder打包自定义img

  • ImageBuilder 就是个打包器。里头有现成的kernel,通过下载ipk包。然后把 kernel 和 ipk 打包成映像。
    如果 ipk下载顺利,打包执行的速度就很快。
  • 现成的内核在build_dir/target-xxxxx_musl/linux-xxxxx/目录中。
  • 下载 ImageBuilder, 解压。
  • make过程中,会去下载 ipk 包。使用的是 wget,不用 curl。
    • 如果需要,设置 ~/.wgetrc,为wget配置代理。只支持http,不支持socks5。
    • 也可以在前面套 tsocks 或 proxychains4。不过 tsocks 会显示不少错误,但不影响执行。proxychains4 正常。
    • 修改 ImageBuiler目录/repository.conf, 改国内源。
  • make help 查看帮助。
  • make image 制作缺省配置的固件。
    • 对于 armvirt,只能生成: 内核Image, rootfs。 没有 combined 启动映像。
    • 对于其他架构,会生成 combined 刷机映像。
  • 先做一个和官方一样的img吧。
     # 下载官方的img的包列表,
    wget https://downloads.openwrt.org/releases/22.03.2/targets/armvirt/64/openwrt-22.03.2-armvirt-64-default.manifest
     # 创建 make 命令的脚本,
    echo -n 'make image PACKAGES="' > cmd-mymake.sh
    cut -d' ' -f 1 openwrt-22.03.2-armvirt-64-default.manifest | xargs echo -n >> cmd-mymake.sh
    echo '"' >> cmd-mymake.sh
     #可以编辑一下 cmd-mymake.sh 文件,看看要加什么。不修改,做出来的就和官方的一样。
    sh cmd-mymake.sh
     # 去 ImageBuiler目录/bin/targets/armvirt/64/, 就能找到生成的结果了。
     # 对于armvirt,其实就是做了个 rootfs。还需要自己去制作启动映像。
    
  • 如果是为硬路由制作刷机包,获取官版原有的包列表。参考【用imagebuilder打包一个自定义bin文件】。
  • 可以加更多的ipk包,去除ipk包。添加额外的文件,删除无用文件。参考【官方文档 imagebuilder】。
  • 如果要修改 /etc/config/ 中的配置,见【openwrt_imagebuilder_修改缺省配置_network_firewall_root密码】。
  • 修改img映像的大小:
    • 对于 armvirt 或 x86 或 x86_64, 修改 .config 文件中,
      CONFIG_TARGET_ROOTFS_PARTSIZE=104, root分区104MB。rootfs的img是104MB。
      CONFIG_TARGET_KERNEL_PARTSIZE=16, boot分区16MB。
      最终"可启动"的img,比两个分区总和再大几MB(为了对齐)。
      armvirt 不生成"可启动"的img。
    • 对于其他架构,找找类似target/linux/ramips/image/mt7621.mktarget/linux/ramips/image/Makefile中有没有地方修改。
      比如 IMAGE_SIZE := 32448k

别人做好的 VMware 的虚机

linux中查看img的内容

  • losetup -f xxxxxxx.img #挂载到 loop 设备
    losetup -a #查看挂在哪个 loop 设备上了,我这是 loop0
    partx -a /dev/loop0 #读取分区信息,加载到系统
    fdisk -l /dev/loop0 #查看分区信息
    lsblk -f #查看各个块设备的文件系统类型
    mount /dev/loop0p1 /mypath #挂载文件系统
    umount /mypath #卸载文件系统
    partx -d /dev/loop0 #卸载系统中的分区信息
    losetup -d /dev/loop0 #卸载 loop 设备
  • 除了能查看,修改里头的内容也没有问题。通常是往文件系统中添加些文件。
  • 只要mount上去了,哪怕什么都没做,img映像文件的内容其实已经被修改了。img文件的sha256值就会变。
    只挂载到loop设备,查看分区信息,不修改分区信息,img文件不会被修改。

----end----


转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/16670954.html
来自 osnosn的博客 https://www.cnblogs.com/osnosn/ .


posted on 2022-09-08 22:23  osnosn  阅读(1309)  评论(0编辑  收藏  举报