VMDK转img并制作U盘启动安装到无系统的PC机上

起源

今天收到大佬给的一个VMDK的debian bookworm系统的虚拟机,在测试实时性时发现极其出色,故因此想把改VMDK转化成可以直接安装在实体机器上的Linux操作系统。

Step 1 VMDK转化成img

这里我们需要把VMDK转换成IMG,我的初步构想是将img文件制作成U盘启动,然后再烧录到电脑的硬盘中

qemu-img convert -O raw test.vmdk test.img

Step 2 制作UEFI的img镜像

第一步完成后,可以直接将test.img烧录到U盘并启动,但是我发现老款的机子可以启动,新款机子识别不到U盘,看了一下test.img的属性,好家伙是MBR,不支持UEFI启动,怪不得新的机子识别不到,因此我这里需要重新制作一个UEFI的镜像,不然启动的时候BIOS识别不到U盘

damn@damn-virtual-machine:~$ fdisk -l test.img 
Disk test.img: 25 GiB, 26843545600 bytes, 52428800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x338c503f

Device     Boot    Start      End  Sectors  Size Id Type
test.img1   *        2048 50427903 50425856   24G 83 Linux
test.img2        50429950 52426751  1996802  975M  5 Extended
test.img5        50429952 52426751  1996800  975M 82 Linux swap / Solaris



damn@damn-virtual-machine:~$ gdisk -l test.img 
GPT fdisk (gdisk) version 1.0.8

Partition table scan:
  MBR: MBR only
  BSD: not present
  APM: not present
  GPT: not present


***************************************************************
Found invalid GPT and valid MBR; converting MBR to GPT format
in memory. 
***************************************************************

Disk test.img: 52428800 sectors, 25.0 GiB
Sector size (logical): 512 bytes
Disk identifier (GUID): 6DD1C871-8298-4C6A-88DB-117B7926645D
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 52428766
Partitions will be aligned on 2048-sector boundaries
Total free space is 6077 sectors (3.0 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048        50427903   24.0 GiB    8300  Linux filesystem
   5        50429952        52426751   975.0 MiB   8200  Linux swap

由于之前的经验,我将Linux分区挂载在/mnt下,看了一下Linux系统的大小,文件不过4G左右,因此我新建一个8G的img,建立好以后,我们需要用loop的方式挂载这个img,并且进行分区以及格式化。UFEI的分区默认第一分区存放EFI,第二分区存放Linux filesystem

dd if=/dev/zero of=a.img bs=1G count=8
sudo parted a.img mklabel gpt
sudo parted a.img
mkpart ESP fat32 1MiB 500MiB
set 1 esp on
mkpart Linux ext4 500MiB 8GiB
sudo losetup -fP a.img
LOOP_DEV=$(losetup -j a.img | cut -d':' -f1)
sudo mkfs.vfat -F32 ${LOOP_DEV}p1
sudo mkfs.ext4 ${LOOP_DEV}p2

格式化完成后,我们需要将原来test.img里的filesystem拷贝到新的a.img的p2分区里

sudo losetup -fP test.img

sudo mkdir /mnt/{old,new}
sudo mount /dev/loop14p1 /mnt/old        # 假设原镜像已挂载为loop14
sudo mount ${LOOP_DEV}p2 /mnt/new        # 挂载新根分区
sudo rsync -aAXv /mnt/old/* /mnt/new
sudo umount /mnt/old

Step 3 制作UFEI引导

之前创建完EFI目录以后,其实该目录还是空的,我们需要制作引导。

sudo mount ${LOOP_DEV}p2 /mnt
mkdir /mnt/boot/efi
sudo mount ${LOOP_DEV}p1 /mnt/boot/efi

for dir in proc sys dev; do
  sudo mount --bind /$dir /mnt/$dir
done

sudo chroot /mnt
mount -t proc proc /proc
mount --rbind /sys /sys
mount --rbind /dev /dev

进入封闭的文件系统里以后,我们需要安装grub-efi的工具。

apt install grub-efi-amd64-bin grub-efi-amd64-signed parted acl iptables


grub-install \
--target=x86_64-efi \
--efi-directory=/boot/efi \
--bootloader-id=GRUB \
--removable \
--directory=/usr/lib/grub/x86_64-efi

运行完以后,可以看到boot的efi目录里多了BOOT和GRUB 

damn@damn-virtual-machine:/mnt/boot/efi/EFI$ ls
BOOT  GRUB 

我们还需要拷贝一个文件夹到和一个文件到BOOT和GRUB目录

cd /mnt/boot/grub

ls

fonts  grub.cfg  grubenv  i386-pc  locale  unicode.pf2  x86_64-efi


cp grub.cfg /mnt/boot/efi/EFI/BOOT
cp grub.cfg /mnt/boot/efi/EFI/GRUB

cp -r x86_64-efi /mnt/boot/efi/EFI/BOOT/
cp -r x86_64-efi /mnt/boot/efi/EFI/GRUB/

update-grub

退出

#在chroot里
umount /proc
umount /dev
umount /sys
exit

#在linux宿主机终端中
umount /mnt/proc
umount /mnt/dev
umount /mnt/sys

umount /mnt/boot/efi
umount /mnt

# 如果一直出现busy,那么可以重启linux系统解决。。。

sudo losetup -d $LOOP_DEV

将a.img写入U盘,用lsblk查看U盘块

lsblk

这里看到我的U盘的标记是/dev/sdb,所以我选择/dev/sdb

sudo dd if=a.img of=/dev/sdb bs=4M status=progress

sync

Step 4 安装到PC硬盘

将制作好的U盘插入PC机,BIOS里选择该U盘启动

启动后输入账号密码,进入U盘的Linux系统。这时候我们需要对PC的硬盘进行分区,换原我们的系统

lsblk

查看到我的PC机的硬盘符为/dev/nvme0n1

sudo parted /dev/nvme0n1

(parted) mklabel gpt

(parted) mkpart ESP fat32 1MiB 500MiB

(parted) set 1 esp on

(parted) mkpart Linux ext4 500MiB 100GiB

退出parted以后,我们用dd命令还原分区

# 我的U盘启动以后,U盘本身的分区是sda
# 拷贝 sda1(EFI 分区)到nvme0n1p1   
sudo dd if=/dev/sda1 of=/dev/nvme0n1p1 bs=4M status=progress 

# 拷贝 sda2(根分区)
sudo dd if=/dev/sda2 of=/dev/nvme0n1p2 bs=4M  status=progress

sync

这里我们还需要修改一部分信息,那就是fstab里的UUID信息,因为磁盘变了,需要修改nvme0n1p2 中的etc/fstab里的磁盘UUID

blkid

/dev/nvme0n1p2 : UUID="f1e07a95-a73e-4b0b-b5e4-b87431cb3366" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="f15e7724-e943-436b-b03b-2e22458ee136"

mount /dev/nvme0n1p2 /mnt


nano /mnt/etc/fstab

修改下面的数据

UUID= /               ext4    errors=remount-ro 0       1
# swap was on /dev/sda5 during installation
#UUID=0b5e482e-4657-4c57-ab62-740944d6fa24 none            swap    sw              0       0
#/dev/sr0        /media/cdrom0   udf,iso9660 user,noauto     0       0




修改完以后


UUID=f1e07a95-a73e-4b0b-b5e4-b87431cb3366 /               ext4    defaults 0       1
# swap was on /dev/sda5 during installation
#UUID=0b5e482e-4657-4c57-ab62-740944d6fa24 none            swap    sw              0       0
#/dev/sr0        /media/cdrom0   udf,iso9660 user,noauto     0       0

这里修改完,可以直接umount了

umount /mnt

Step 5 收尾

到这里,可以关机拔掉U盘,进行重启,进入BIOS里选择对应的启动项即可,或者如果进不去系统,可以进入UEFI SHELL

fs0:

cd EFI
cd BOOT
./BOOTX64.EFI

#!/bin/bash

echo "Available SSD/HDD"

lsblk -d -o NAME,SIZE,MODEL

read -p "Input the name of SSD/HDD:" target_disk

if [ -z "$target_disk" ]; then
    echo "Error: None SSD/HDD"
    exit 1
fi

if ! lsblk -d /dev/$target_disk &> /dev/null; then
    echo "Error: /dev/$target_disk is not exsited"
    exit 1
fi

echo "Creating Partition ..."
sudo parted /dev/$target_disk --script mklabel gpt
sudo parted /dev/$target_disk --script mkpart ESP fat32 1MiB 500MiB
sudo parted /dev/$target_disk --script set 1 esp on
sudo parted /dev/$target_disk --script mkpart Linux ext4 500MiB 95%
sudo parted /dev/$target_disk --script mkpart linux-swap ext4 95% 100% 
sudo parted /dev/$target_disk --script set 3 swap on

echo "format swap ..."

sudo mkswap /dev/${target_disk}p3

echo "Copy Data..."
sudo dd if=/dev/sda1 of=/dev/${target_disk}p1 bs=4M status=progress
sudo dd if=/dev/sda2 of=/dev/${target_disk}p2 bs=4M status=progress
sync

echo "Get SSD/HHD UUID..."
uuid=$(sudo blkid -s UUID -o value /dev/${target_disk}p2)
if [ -z "$uuid" ]; then
    echo "Error: Can not obtian the uuid of /dev/${target_disk}p2 "
    exit 1
fi

echo "Modifying /etc/fstab..."
sudo mount /dev/${target_disk}p2 /mnt
sudo sed -i "s/UUID=[^ ]*/UUID=$uuid/" /mnt/etc/fstab

swap_uuid=$(sudo blkid -s UUID -o value /dev/${target_disk}p3)
if [ -z "$swap_uuid" ]; then
    echo "Error: Couldn't get UUID of swap"
    exit 1
fi

echo "UUID=$swap_uuid none swap sw 0 0" | sudo tee -a /mnt/etc/fstab
echo "RESUME=UUID=$swap_uuid" | sudo tee /mnt/etc/initramfs-tools/conf.d/resume >/dev/null



sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys
sudo chroot /mnt update-initramfs -u -k all
sudo umount /mnt/dev
sudo umount /mnt/proc
sudo umount /mnt/sys

sudo umount /mnt
echo "Adjusting Capacity..."
sudo e2fsck -f /dev/${target_disk}p2  # 强制检查文件系统一致性[6,8](@ref)
sudo resize2fs /dev/${target_disk}p2   # 自动扩展到分区最大容量[1,7](@ref)

echo "Done"

read -p "Please press 'Enter' to reboot the system and remove USB devices: " dummy_input
sudo reboot

你可能感兴趣的:(linux)