特别备注 由于Dora OS等的 崭新的"面向AI时代的新型机器人操作系统"的复杂性,我们这次没有用Dora OS作为案例;
我们只是演示cnb.cool与Qemu虚拟机的结合
演示的只是 Debian 12 bookworm 与 alpine 3.22.0 两个版本

特别说明
本模式只适合 广大计算机学院,软件学院,网络学院学生学习 操作系统试验课程 通过qemu虚拟机软件 做技术试验
通过qemu虚拟机 调试 自己的 linux内核源代码 这个 调试 环节是必须用到 qemu虚拟机的
在操作系统试验中, 有一个 准备根文件系统 步骤 必须使用 qemu虚拟机
类似编译 RISC-V 指令集上的 linux 内核源代码,在cnb.cool主工作空间进行,速度更快,编译 linux内核源代码,不要在qemu虚拟机内进行
编译 RISC-v指令集上的linux源代码 也可以通过直接使用 相应的 docker镜像与容器,更快的进行
本案例,仅用来自 debian 官方的 debian 12 qcow2镜像作为案例, "这个镜像 在cnb.cool的qemu虚拟机中 '调试操作系统内核' 与 '构建轻型的根文件系统' 速度还是不错的"

仿照优秀的cnb.cool团队提出的 git分支 就是不同的 deepseek 大语言模型的
下图2个标有"虚拟机"后缀的分支,选中该分支以后,点击"学习笔记"(橙色)按钮,就可立即启动CNB的工作空间,按照配置自动启动Qemu虚拟机
debian-12-qemu-vm-虚拟机 [用户名 root 用户密码是 123456]
alpine-3.2.20-docker容器中通过qemu-2层结构-虚拟机 [用户名 root 没有密码]

这个模式是,计算机学院学子们,做操作系统试验的 最佳选择

直接进入qemu虚拟机_快捷_便利

可以看到 debian 12 qemu 虚拟机使用的 独立的内核 启动的 这样就有条件做 操作系统内核的 调试试验了

这个方式网络比较复杂,不适合 计算机学院的学子们 做操作系统试验 我们放在这里,是演示一些这个模式也是存在的(过于复杂)

alpine-3.2.20-qemu-vm 虚拟机 用户名 root 没有密码 可以直接进入

**通过noVNC web页面方式(6080端口) 可以访问alpine-3.2.20-qemu-vm 虚拟机的命令行

其他分支都是方便,直接运行虚拟机 main分支,是进行 操作系统内核试验的 主要工作分支
main分支 由于灵活与强大的.cnb.yml配置能力,进入了 CNB_WELCOME_EXECUTE_COMMAND 执行后的界面 如下图 做计算机操作系统试验的 学子们 可以 根据屏幕显示的信息 输入 "make de60" 启动实验相关的qemu虚拟机 去进行操作

上图的核心配置如下
main:
vscode:
- docker:
image: docker.cnb.cool/8888/cnbcnb/imadesk/cnb_xfce_qemu/cnb_xfce_qemu/ce12_cnb_qemu_vm_for_os_study:latest
runner:
cpus: 16
# tags: cnb:arch:amd64:gpu
services:
- vscode
- docker
# 开发环境启动后会执行的任务
stages:
- name: 通过make展示帮助信息
script: "[ -f ${HOME}/Makefile ] && make -f ${HOME}/Makefile help"
env:
# NOTE 如下是选择分支后_展示_帮助信息
CNB_WELCOME_EXECUTE_COMMAND: |
[[ -f "${HOME}/Makefile" ]] && make -f ${HOME}/Makefile help && echo -e "\n位于_git分支_main"
在main分支中 "cd && make && make de60" 快速启动 de60-debian-12-qemu-vm 虚拟机


cd ${HOME} && make help && make de60
ps aux | grep qemu | grep 'name'
方法一 (安全关闭): 通过ssh登录到 上述虚拟机内部,通过shutdown -h now模式关闭
cd ${HOME} && make help && make de60_stop
方法二(虚拟机失去反应,暴力关闭) 在cnb.cool主工作空间中,通过killall 杀死qemu进程,暴力关闭
cd ${HOME} && make help && make de60_hard_stop
特别提示: 通过方法二暴力关闭失去反应的虚拟机,可能无法再次启动该虚拟机,需要重新关闭cnb.cool工作空间,再次进入,再次启动虚拟机(这样应该可以启动)

方法 01
ssh -p 2222 root@localhost
方法 02
cd ${HOME} && ls -alh *.sh && source 03_ssh_2222端口_用户_root_密码_123456_执行本脚本登录.sh
sshpass -p123456 ssh -p 2222 root@localhost
ssh -p 2222 root@localhost bash -c "ls -lah /root"
ssh -p 2222 root@localhost << 'EOF'
de30_exec_inside_vm() {
ls -alh /root
cd /etc
find . | wc -l
}
de30_exec_inside_vm
EOF
sshpass -p '123456' ssh -p 2222 root@localhost << 'EOF'
de60_exec_inside_vm() {
ls -alh /root
cd /etc
find . | wc -l
}
de60_exec_inside_vm
EOF
如果函数比较复杂,建议先将其写入一个脚本,然后远程执行该脚本.
#!/bin/bash
my_function() {
echo "Hello from remote VM!"
echo "Current user: $(whoami)"
echo "Date: $(date)"
}
my_function
ssh -p 2222 root@localhost 'bash -s' < remote_func.sh
bash -s 表示从标准输入读取并执行脚本.< remote_func.sh 将本地脚本内容传递给远程主机.如果你希望函数内容在运行时动态生成,可以这样写:
FUNCTION_NAME="my_remote_func"
FUNCTION_BODY="echo '这是一个可以通过拼串模式,动态创建的bash函数'; echo '虚拟内执行: \$(whoami)'; ls -lah /root"
sshpass -p '123456' ssh -p 2222 root@localhost << EOF
$FUNCTION_NAME() {
$FUNCTION_BODY
}
$FUNCTION_NAME
EOF
export source_dir=/root
export target_dir=/tmp/cm30_scp_de60_vm_target
mkdir -p ${target_dir}
cd ${target_dir}
scp \
-P 2222 \
-r \
root@localhost:/${source_dir} \
${target_dir}
ls -alh ${target_dir} && pwd
# rsync 从 cnb.cool 到 本地笔记本电脑环境(Linux或 windows 10 WSL环境) 是成功的
export source_dir=/root
export target_dir=/tmp/cm36_rsync_de60_vm_target
mkdir -p ${target_dir}
cd ${target_dir}
apt update && apt install -y rsync lsof tree psmisc && \
rsync \
-avzP \
-e "ssh -p 2222" \
root@localhost:${source_dir} .
ls -lah ${target_dir} && pwd

OpenCamp.cn Learning Qemu Camp 2025 训练营 正在火热报名中

报名链接

debian官网qcow2镜像修改root账号密码,开启ssh,修改源,语法高亮等
wget -c \
https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2
cp debian-12-generic-amd64.qcow2 \
dm30_debian-12-generic-amd64_这里是来自debian官方的原始镜像_需要用guestfish修改root密码为123456.qcow2
cp -f debian-12-generic-amd64.qcow2 \
../de60_debian_12_generic_amd64.qcow2
给cnb.cool制作qemu虚拟机_选择debian官方的_qcow2镜像_里面是安装好的虚拟机_qemu直接使用_最为方便

镜像文件信息
[debian-10.2-cloud] name=Debian 10.2.0 (Buster) Cloud osinfo=debian10 arch=x86_64 file=de60_debian_12_generic_amd64.qcow2 checksum[sha512]=296ad8345cb49e52464a0cb8bf4365eb0b9e4220c47ebdd73d134d51effc756d5554aee15027fffd038fef4ad5fa984c94208bce60572d58b2ab26f74bb2a5de format=qcow2 size=566434304 revision=20191116 notes=Debian 10.2.0 (Buster). This is a Debian installation, suited for running as OpenStack guest.
[root@support01 ~]# openssl passwd -1 123456 $1$0cFL6rLW$aKxksiunPZOskbplB5Uk90
apt update && apt install -y guestfish guestfish --rw -a de60_debian_12_generic_amd64.qcow2
Welcome to guestfish, the guest filesystem shell for editing virtual machine filesystems and disk images. Type: 'help' for help on commands 'man' to read the manual 'quit' to quit the shell > run > list-filesystems /dev/sda1: ext4 > mount /dev/sda1 / >
编辑/etc/shadow
> vi /etc/shadow
root:*:18216:0:99999:7::: daemon:*:18216:0:99999:7::: bin:*:18216:0:99999:7::: sys:*:18216:0:99999:7::: sync:*:18216:0:99999:7::: games:*:18216:0:99999:7::: man:*:18216:0:99999:7::: lp:*:18216:0:99999:7::: mail:*:18216:0:99999:7::: news:*:18216:0:99999:7::: uucp:*:18216:0:99999:7::: proxy:*:18216:0:99999:7::: www-data:*:18216:0:99999:7::: backup:*:18216:0:99999:7::: list:*:18216:0:99999:7::: irc:*:18216:0:99999:7::: gnats:*:18216:0:99999:7::: nobody:*:18216:0:99999:7::: _apt:*:18216:0:99999:7::: systemd-timesync:*:18216:0:99999:7::: systemd-network:*:18216:0:99999:7::: systemd-resolve:*:18216:0:99999:7::: messagebus:*:18216:0:99999:7::: unscd:*:18216:0:99999:7::: ntp:*:18216:0:99999:7::: sshd:*:18216:0:99999:7:::
将root:后面的第一个*替换为第二步加密之后的密码
替换后第一行为/etc/shadow第一行为
root:$1$0cFL6rLW$aKxksiunPZOskbplB5Uk90:18216:0:99999:7:::
编辑/etc/ssh/sshd_config ,在vi中:set number开启行号
> vi /etc/ssh/sshd_config
第32行 左右 许可root用户通过ssh登录
#PermitRootLogin prohibit-password
释放掉注释,并修改值为yes,调整完之后第32行为
PermitRootLogin yes
第38行左右 许可通过ssh证书 免密码登录
# PubkeyAuthentication yes
释放掉注释,调整完之后第56行为
PubkeyAuthentication yes
第56行左右 许可 通过 用户名与用户密码 进行登录
#PasswordAuthentication yes
释放掉注释,调整完之后第56行为
PasswordAuthentication yes
(qcow2注册到OpenStack之后启动虚拟机源还是默认的,目前原因未知,可待虚拟机启动后执行下列修改)
编辑/etc/apt/sources.list ,将替换为以下内容(腾讯源)
# See /etc/apt/sources.list.d/debian.sources deb https://mirrors.tencent.com/debian/ bookworm main non-free non-free-firmware contrib deb-src https://mirrors.tencent.com/debian/ bookworm main non-free non-free-firmware contrib deb https://mirrors.tencent.com/debian-security/ bookworm-security main deb-src https://mirrors.tencent.com/debian-security/ bookworm-security main deb https://mirrors.tencent.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb-src https://mirrors.tencent.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb https://mirrors.tencent.com/debian/ bookworm-backports main non-free non-free-firmware contrib deb-src https://mirrors.tencent.com/debian/ bookworm-backports main non-free non-free-firmware contrib
编辑/root/.bashrc ,1,3,4,8,15行为说明注释,除此之外释放所有注释
> vi /root/.bashrc
编辑之前内容为:
# ~/.bashrc: executed by bash(1) for non-login shells. # Note: PS1 and umask are already set in /etc/profile. You should not # need this unless you want different defaults for root. # PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ ' # umask 022 # You may uncomment the following lines if you want `ls' to be colorized: # export LS_OPTIONS='--color=auto' # eval "`dircolors`" # alias ls='ls $LS_OPTIONS' # alias ll='ls $LS_OPTIONS -l' # alias l='ls $LS_OPTIONS -lA' # # Some more alias to avoid making mistakes: # alias rm='rm -i' # alias cp='cp -i' # alias mv='mv -i'
编辑之后内容为:
# ~/.bashrc: executed by bash(1) for non-login shells.
# NOTE 必须保持这样判断,这样通过scp拷贝内容的时候,不会出现问题
case $- in
*i*) ;;
*) return;;
esac
# Note: PS1 and umask are already set in /etc/profile. You should not
# need this unless you want different defaults for root.
# PS1='${debian_chroot:+($debian_chroot)}\h_虚拟机内部:\w\$ '
# NOTE 用黄色字体显示PS1 提示符
PS1='\[\e[1;33m\]${debian_chroot:+($debian_chroot)}\h_虚拟机内部:\w\$ \[\e[0m\]'
umask 022
# You may uncomment the following lines if you want `ls' to be colorized:
export LS_OPTIONS='--color=auto'
eval "$(dircolors)"
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -l'
alias l='ls $LS_OPTIONS -lA'
#
# Some more alias to avoid making mistakes:
# alias rm='rm -i'
# alias cp='cp -i'
# alias mv='mv -i'
# dhclient ens3
ensure_dhclient_running() {
if ! pgrep -f "dhclient.*ens3" > /dev/null; then
echo "dhclient for ens3 is not running. Starting it now..."
/sbin/dhclient ens3
fi
}
# ensure_dhclient_running
de60_exec_inside_vm() {
local lock_file="${HOME}/lc20_de60_debian_12_vm_lock.sh"
# 检查锁文件是否存在
if [ -f "$lock_file" ]; then
# echo "锁文件已存在,跳过执行."
echo "#--> 最后一次执行: $(date)" >> "$lock_file"
return 0
fi
echo "锁文件不存在,开始执行命令..."
# 执行命令序列
echo "正在显示网络接口信息..."
ip a
echo "正在为 ens3 接口获取 IP 地址..."
dhclient ens3
echo "再次显示网络接口信息..."
ip a
echo "正在显示路由表..."
ip route
echo "正在测试网络连通性(ping 8.8.8.8)..."
ping 8.8.8.8 -c 3
echo "正在测试 HTTP 连接(访问 www.baidu.com)..."
curl www.baidu.com
echo -e "\n\n\n"
hostnamectl
# 创建锁文件
touch "$lock_file"
echo "###--> 创建了锁文件: $(date)" >> "$lock_file"
echo "已创建锁文件 :$lock_file"
echo -e "\e[1;32m\n本信息只在第1次登录的时候测试网络联通性,以后登录都不会再测试了\e[0m"
}
# 调用函数
de60_exec_inside_vm
> vi /usr/share/vim/vim81/defaults.vim
78,79,80三行内容为:
if has('mouse') set mouse=a endif
在"="前面添加一个"-",编辑后内容为:
if has('mouse') set mouse-=a endif
最后执行quit命令退出guestfish,将qcow2镜像文件注册到openstack,投递虚拟机实例即可

制作一个 单一qcow2镜像文件 完整的qemu 虚拟机 把所有的虚拟机内部环境整理工作都进行完毕(例如 ssh证书 免密码登录等)
# 必须是切换到 git仓库的 main分支
git switch main
env | grep VSCODE_REMOTE
# 获得类似如下的内容
CNB_VSCODE_REMOTE_SSH_SCHEMA=vscode://vscode-remote/ssh-remote+cnb-11g-1j6caqd5t-001.59900aed-2fcf-469e-8389-2e640dea4227-qmo@remote.cnb.space:2201/workspace/
试验一下是否可以在命令行中,通过ssh登录到cnb.cool的主工作空间中去
#!/bin/bash
# NOTE 如下的URL是拷贝自上面的 CNB_VSCODE_REMOTE_SSH_SCHEMA 环境变量
export URL="vscode://vscode-remote/ssh-remote+cnb-11g-1j6caqd5t-001.59900aed-2fcf-469e-8389-2e640dea4227-qmo@remote.cnb.space:2201/workspace/"
SSH_ADDRESS=$(echo "$URL" | awk -F'+' '{print $2}' | awk -F':' '{print $1}')
export MY_CNB_CURRENT_SSH_ADDRESS="$SSH_ADDRESS"
echo "MY_CNB_CURRENT_SSH_ADDRESS=$MY_CNB_CURRENT_SSH_ADDRESS"
ssh -p 2201 ${MY_CNB_CURRENT_SSH_ADDRESS}
#!/bin/bash
# NOTE 如下的URL是拷贝自上面的 CNB_VSCODE_REMOTE_SSH_SCHEMA 环境变量
export URL="vscode://vscode-remote/ssh-remote+cnb-11g-1j6caqd5t-001.59900aed-2fcf-469e-8389-2e640dea4227-qmo@remote.cnb.space:2201/workspace/"
SSH_ADDRESS=$(echo "$URL" | awk -F'+' '{print $2}' | awk -F':' '{print $1}')
export MY_CNB_CURRENT_SSH_ADDRESS="$SSH_ADDRESS"
echo "MY_CNB_CURRENT_SSH_ADDRESS=$MY_CNB_CURRENT_SSH_ADDRESS"
# NOTE 下面需要修改为你自己的qemu qcow2镜像的地址
export my_source_qemu_vm_filename="my_qemu_vm.qcow2"
export cnb_target_dir="/tmp/cm40_de60_qemu_vm_rsync_workdir"
# NOTE 如下参数是支持断点续传的
apt update && apt install -y rsync lsof tree psmisc && \
rsync \
-avzP \
-e "ssh -p 2201" \
${my_source_qemu_vm_filename} \
${cnb_target_dir}
# NOTE 尝试通过 ssh通道 查看一下 传递到 cnb.cool主工作空间中文件的情况
ssh -p 2201 ${MY_CNB_CURRENT_SSH_ADDRESS} ls -lah "${cnb_target_dir}/${my_source_qemu_vm_filename}"
重新回到cnb.cool主工作空间中,执行类似如下的代码
# NOTE 为了简化本README 我们假设您的qemu虚拟机 只有一个qcow2文件组成
if [[ -f "${cnb_target_dir}/${my_source_qemu_vm_filename}" ]]; then
if [[ -f "/workspace/ho38_qemu_images/de60_debian_12_generic_amd64.qcow2" ]]; then
if [[ ! -f "/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/de60_debian_12_generic_amd64.qcow2" ]]; then
# NOTE 通过移动原有的文件_实现备份的目的
mv \
"/workspace/ho38_qemu_images/de60_debian_12_generic_amd64.qcow2" \
"/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/de60_debian_12_generic_amd64.qcow2"
fi
# NOTE 更改原有的镜像的名字_方便以后的_操作
echo -e "/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/bk30_$(date '+%Y-%m-%d日_%H:%M:%S秒')_虚拟机镜像备份_de60_debian_12_generic_amd64.qcow2"
mv \
"/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/de60_debian_12_generic_amd64.qcow2" \
"/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/bk30_$(date '+%Y-%m-%d日_%H:%M:%S秒')_虚拟机镜像备份_de60_debian_12_generic_amd64.qcow2"
# NOTE 把上面从您自己的qemu虚拟机的qcow2镜像拷贝到特定的位置
# 并且修改为特定的名称
# 原因是,这里一个简化的README.md 这样可以服用 我们演示仓库中 现有的脚本,更加容易跑通
cp -f \
"${cnb_target_dir}/${my_source_qemu_vm_filename}" \
"/workspace/ho38_qemu_images/oe60_de60_debian_12_备份虚拟机/de60_debian_12_generic_amd64.qcow2"
# 紧接着检查退出状态码
if [ $? -eq 0 ]; then
echo "✅ 上一个命令执行成功!"
else
echo "❌ 20_上一个命令执行失败_原因未知"
fi
else
echo -e "30_情况不明,无法继续进行"
fi
else
echo -e "60_没有发现_需要更新的_qemu_虚拟机的镜像_无法在进行操作"
fi
cd /workspace && git switch main
备份原有的.ssh证书
cd /workspace
if [[ -d "/workspace/ho38_qemu_images/sh60_debian_12_虚拟机的_一些文件/rootfs/root/.ssh" ]]; then
cp -r -f \
"/workspace/ho38_qemu_images/sh60_debian_12_虚拟机的_一些文件/rootfs/root/.ssh" \
"/workspace/ho38_qemu_images/sh60_debian_12_虚拟机的_一些文件/rootfs/root/bk30_$(date '+%Y-%m-%d日_%H:%M:%S秒')_上一个虚拟机镜像_配合的_ssh证书备份_ssh"
else
echo -e "70_没有找到原有的_ssh证书的目录_无法继续"
fi
需要把如下目录中 .ssh证书 替换为你自己的 .ssh证书, 否则 后继 无法使用 ssh证书 免密码登录 因为 证书 不一致 无法登录
cd /workspace/ho38_qemu_images/sh60_debian_12_虚拟机的_一些文件/rootfs/root/.ssh
# 手动替换这些证书
➜ .ssh git:(main) ✗ pwd
/workspace/ho38_qemu_images/sh60_debian_12_虚拟机的_一些文件/rootfs/root/.ssh
➜ .ssh git:(main) ✗ ll
total 20K
-rw-r--r-- 1 root root 748 Sep 29 08:01 authorized_keys
-rw-r--r-- 1 root root 3.4K Sep 29 08:01 id_rsa
-rw-r--r-- 1 root root 748 Sep 29 08:01 id_rsa.pub
-rw-r--r-- 1 root root 1.1K Sep 29 08:01 known_hosts
-rw-r--r-- 1 root root 714 Sep 29 08:01 readme.md
在cnb.cool主工作空间_继续进行如下操作 需要修改多个文件
下一个版本中我们将提供一个bash函数 进一步代替这些手工改动
cd /workspace
git switch main
git status
# TODO 仔细看这行,这里有一个最为关键的,您必须手动修改的地方
# /workspace/DMakefile
# 大约第11行左右
# 您必须手工的修改为您的docker的地址
# 我没有办法用变量的模式,替您自动完成(经过多次尝试,我们使用变量模式都是失败的)
# 类似如下
# ce12_cnb_qemu_vm_for_os_study_IMAGE_NAME="docker.cnb.cool/8888/cnbcnb/imadesk/cnb_xfce_qemu/cnb_xfce_qemu/ce12_cnb_qemu_vm_for_os_study:latest"
cd /workspace && git add .
git commit -m "我把 de60-debian-12-qemu-vm 虚拟机的 qcow2 镜像文件 替换我自己的版本了"
apt update && apt install -y make lsof
# NOTE 下面将
# 依据main分支中的修改 对另外2个git 分支 进行git merge操作(从main分支到该分支 方向)
# git push --all
# docker build .
# docker push
[[ -f "/workspace/DMakefile" ]] && make -f DMakefile sync
退出 原有的cnb.cool的工作空间(就是那个webide)
# 可以使用如下命令,加速cnb.cool工作空间的关闭
# 不是所有的cnb.cool工作空间中,都安装好了 killall 命令
killall docker-init
等待cnb.cool工作空间完全关闭 重新点击'学习笔记'按钮,就如工作空间 就有可能是您自己的 qemu 虚拟机镜像的版本


https://docs.openstack.org/image-guide/modify-images.html#guestfish
https://blog.51cto.com/superzhangqiang/1705678
https://blog.csdn.net/weixin_42551369/article/details/88946622
http://www.chenshake.com/openstack-mirror-and-password/
