Skip to content

Commit 82418e0

Browse files
committed
Add debian
1 parent f240807 commit 82418e0

5 files changed

Lines changed: 374 additions & 11 deletions

File tree

.github/workflows/build-debian.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build Debian QCOW2
2+
3+
on:
4+
push:
5+
paths:
6+
- 'Debian.json' # 只有当 Debian.json 文件被修改时触发
7+
workflow_dispatch: # 手动触发
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
# Step 1: 检出代码
15+
- name: Checkout repository
16+
uses: actions/checkout@v3
17+
18+
# Step 2: 解析 Debian.json 文件
19+
- name: Parse Debian.json
20+
id: parse-debian-json
21+
run: |
22+
# 使用 jq 解析 JSON 文件
23+
NAME=$(jq -r '.name' Debian.json)
24+
VERSION=$(jq -r '.version' Debian.json)
25+
URL=$(jq -r '.url' Debian.json)
26+
27+
# 设置环境变量
28+
echo "NAME=$NAME" >> $GITHUB_ENV
29+
echo "VERSION=$VERSION" >> $GITHUB_ENV
30+
echo "DOWNLOAD_URL=$URL" >> $GITHUB_ENV
31+
32+
# Step 3: 下载 .tar.xz 文件
33+
- name: Download Debian tar.xz file
34+
run: |
35+
mkdir -p input
36+
wget -O input/source.tar.xz "${{ env.DOWNLOAD_URL }}"
37+
38+
# Step 4: 安装依赖工具
39+
- name: Install dependencies
40+
run: |
41+
sudo apt-get update -qq
42+
sudo apt-get install -y qemu-utils e2fsprogs util-linux xz-utils rsync parted jq
43+
44+
# Step 5: 转换为 qcow2 文件
45+
- name: Convert to qcow2
46+
run: |
47+
mkdir -p output
48+
TARGET_FILE="output/HiSH-image-${{ env.NAME }}-${{ env.VERSION }}.qcow2"
49+
sudo ./convert.debian.sh input/source.tar.xz "$TARGET_FILE"
50+
51+
# Step 6: 上传生成的 qcow2 文件到 Release
52+
- name: Create Release and upload artifact
53+
uses: softprops/action-gh-release@v1
54+
with:
55+
tag_name: "HiSH-image-${{ env.NAME }}-${{ env.VERSION }}"
56+
name: "HiSH-image-${{ env.NAME }}-${{ env.VERSION }}"
57+
files: output/HiSH-image-${{ env.NAME }}-${{ env.VERSION }}.qcow2
58+
env:
59+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Debian.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Debian",
3+
"version": "13",
4+
"url": "https://cloud.debian.org/images/cloud/trixie/latest/debian-13-nocloud-arm64.tar.xz"
5+
}

README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,32 @@
3636
- 禁用内核更新(HiSH 自带内核)
3737
5. 压缩输出最终的 qcow2 镜像
3838

39+
**Debian(.tar.xz 磁盘镜像):**
40+
41+
1. 下载官方 `.tar.xz` 格式的镜像
42+
2. 解压获取 `disk.raw`,挂载其中的根分区
43+
3. 创建 120G 的 qcow2 镜像并格式化为 ext4
44+
4. 将根文件系统内容复制到新镜像
45+
5. 对新镜像做 HiSH 所需的修改
46+
- 配置 `/etc/fstab` 添加共享目录挂载
47+
- 配置 `/etc/network/interfaces` 网络(DHCP)
48+
- 创建 `/init``/sbin/init` 的符号链接
49+
- 禁用内核更新(HiSH 自带内核)
50+
6. 压缩输出最终的 qcow2 镜像
51+
3952
## 支持的发行版
4053

4154
| 发行版 | 配置文件 | 说明 |
4255
|--------|----------|------|
4356
| Fedora | `Fedora.json` | Fedora 最小化安装(.raw.xz) |
4457
| Ubuntu | `Ubuntu.json` | Ubuntu WSL 根文件系统(.tar.gz) |
58+
| Debian | `Debian.json` | Debian QEMU 云磁盘镜像(.tar.xz) |
4559

4660
## 使用方法
4761

4862
> **Ubuntu 默认登录信息:** 用户 `root`,密码 `hish`
4963
>
50-
> **Fedora 首次启动时会运行初始设置向导**,需要根据提示创建用户和设置密码。
64+
> **Fedora / Debian 首次启动时会运行初始设置向导**,需要根据提示创建用户和设置密码。
5165
5266
### 下载镜像
5367

@@ -83,9 +97,12 @@ sudo ./convert.fedora.sh <source.raw.xz> <output.qcow2>
8397

8498
# Ubuntu
8599
sudo ./convert.ubuntu.sh <source.tar.gz> <output.qcow2>
100+
101+
# Debian
102+
sudo ./convert.debian.sh <source.tar.xz> <output.qcow2>
86103
```
87104

88-
**依赖:** `qemu-utils``e2fsprogs``mount``util-linux``rsync`(Fedora 额外需要 `xz-utils`
105+
**依赖:** `qemu-utils``e2fsprogs``mount``util-linux``rsync`(Fedora/Debian 额外需要 `xz-utils`,Debian 额外需要 `parted`
89106

90107
> **注意:** 脚本必须以 root 权限运行。
91108

convert.debian.sh

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
#!/bin/bash
2+
3+
# 检查参数数量
4+
if [ "$#" -ne 2 ]; then
5+
echo "Usage: $0 <source.tar.xz> <target.qcow2>"
6+
exit 1
7+
fi
8+
9+
SOURCE=$1
10+
TARGET=$2
11+
RAW_FILE="disk.raw"
12+
QCOW2_FILE="temp.qcow2"
13+
MOUNT_DIR="mnt"
14+
SOURCE_MOUNT_DIR="mnt_source"
15+
NBD_DEVICE="/dev/nbd0"
16+
LOOP_DEVICE=""
17+
ROOT_PARTITION_DEVICE=""
18+
19+
# 检查是否以 root 用户运行
20+
if [ "$(id -u)" -ne 0 ]; then
21+
echo "Error: This script must be run as root."
22+
exit 1
23+
fi
24+
25+
# 定义依赖包列表
26+
DEPENDENCIES=("qemu-utils" "e2fsprogs" "mount" "util-linux" "xz-utils" "rsync" "parted")
27+
28+
# 安装所有依赖项
29+
echo "Installing required dependencies..."
30+
apt-get update -qq
31+
apt-get install -y "${DEPENDENCIES[@]}"
32+
if [ $? -ne 0 ]; then
33+
echo "Failed to install required dependencies. Exiting..."
34+
exit 1
35+
fi
36+
37+
# 检查 source 文件是否存在
38+
if [ ! -f "$SOURCE" ]; then
39+
echo "Error: Source file $SOURCE does not exist."
40+
exit 1
41+
fi
42+
43+
# 创建临时目录
44+
mkdir -p "$MOUNT_DIR"
45+
mkdir -p "$SOURCE_MOUNT_DIR"
46+
47+
# Step 1: 解压 .tar.xz 文件获取 disk.raw
48+
echo "Extracting disk.raw from tar.xz..."
49+
tar -xJf "$SOURCE" disk.raw
50+
if [ $? -ne 0 ]; then
51+
echo "Failed to extract disk.raw from tar.xz."
52+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
53+
exit 1
54+
fi
55+
56+
# Step 2: 使用 losetup 挂载 disk.raw 为块设备
57+
echo "Attaching disk.raw to loop device..."
58+
LOOP_DEVICE=$(losetup -f)
59+
losetup "$LOOP_DEVICE" "$RAW_FILE"
60+
if [ $? -ne 0 ]; then
61+
echo "Failed to attach disk.raw to loop device."
62+
rm -f "$RAW_FILE"
63+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
64+
exit 1
65+
fi
66+
67+
# Step 3: 扫描分区表并找到根分区
68+
echo "Scanning partition table..."
69+
partprobe "$LOOP_DEVICE" 2>/dev/null
70+
sleep 2
71+
72+
# 使用 blkid 查找 ext4 分区(根分区)
73+
ROOT_PARTITION_DEVICE=""
74+
for part_dev in "${LOOP_DEVICE}p"*; do
75+
if [ -e "$part_dev" ]; then
76+
FSTYPE=$(blkid -o value -s TYPE "$part_dev" 2>/dev/null)
77+
if [ "$FSTYPE" = "ext4" ]; then
78+
ROOT_PARTITION_DEVICE="$part_dev"
79+
echo " Found root partition: $ROOT_PARTITION_DEVICE (ext4)"
80+
break
81+
fi
82+
fi
83+
done
84+
85+
# 如果没有找到分区设备,尝试用 fdisk 解析并使用 losetup 偏移挂载
86+
if [ -z "$ROOT_PARTITION_DEVICE" ]; then
87+
echo " Partition devices not found, trying offset mount..."
88+
PART_INFO=$(fdisk -l "$LOOP_DEVICE" | grep "^${LOOP_DEVICE}p")
89+
PART_COUNT=$(echo "$PART_INFO" | wc -l)
90+
91+
# 从最后一个分区开始查找 ext4
92+
for i in $(seq "$PART_COUNT" -1 1); do
93+
PART_START=$(echo "$PART_INFO" | awk -v nr="$i" 'NR==nr {print $2}')
94+
PART_SIZE=$(echo "$PART_INFO" | awk -v nr="$i" 'NR==nr {print $4}')
95+
if [ -n "$PART_START" ] && [ -n "$PART_SIZE" ]; then
96+
ROOT_PARTITION_DEVICE=$(losetup -f)
97+
losetup -o $((PART_START * 512)) --sizelimit $((PART_SIZE * 512)) "$ROOT_PARTITION_DEVICE" "$LOOP_DEVICE"
98+
FSTYPE=$(blkid -o value -s TYPE "$ROOT_PARTITION_DEVICE" 2>/dev/null)
99+
if [ "$FSTYPE" = "ext4" ] || [ "$FSTYPE" = "ext2" ] || [ "$FSTYPE" = "ext3" ]; then
100+
echo " Found root partition at offset $((PART_START * 512)): $ROOT_PARTITION_DEVICE ($FSTYPE)"
101+
break
102+
else
103+
losetup -d "$ROOT_PARTITION_DEVICE"
104+
ROOT_PARTITION_DEVICE=""
105+
fi
106+
fi
107+
done
108+
fi
109+
110+
if [ -z "$ROOT_PARTITION_DEVICE" ]; then
111+
echo "Failed to find root partition."
112+
losetup -d "$LOOP_DEVICE"
113+
rm -f "$RAW_FILE"
114+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
115+
exit 1
116+
fi
117+
118+
# Step 4: 创建一个 120G 的 qcow2 文件
119+
echo "Creating a 120G qcow2 file..."
120+
qemu-img create -f qcow2 "$QCOW2_FILE" 120G
121+
if [ $? -ne 0 ]; then
122+
echo "Failed to create qcow2 file."
123+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
124+
losetup -d "$LOOP_DEVICE"
125+
rm -f "$RAW_FILE"
126+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
127+
exit 1
128+
fi
129+
130+
# Step 5: 使用 nbd 挂载 qcow2 文件
131+
echo "Attaching qcow2 file to NBD device..."
132+
modprobe nbd max_part=8
133+
qemu-nbd -c "$NBD_DEVICE" "$QCOW2_FILE"
134+
if [ $? -ne 0 ]; then
135+
echo "Failed to attach qcow2 file to NBD device."
136+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
137+
losetup -d "$LOOP_DEVICE"
138+
rm -f "$RAW_FILE" "$QCOW2_FILE"
139+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
140+
exit 1
141+
fi
142+
143+
# 等待设备就绪
144+
sleep 5
145+
146+
# Step 6: 格式化 nbd 分区为 ext4
147+
echo "Formatting NBD partition with ext4..."
148+
mkfs.ext4 "$NBD_DEVICE"
149+
if [ $? -ne 0 ]; then
150+
echo "Failed to format NBD partition."
151+
qemu-nbd -d "$NBD_DEVICE"
152+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
153+
losetup -d "$LOOP_DEVICE"
154+
rm -f "$RAW_FILE" "$QCOW2_FILE"
155+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
156+
exit 1
157+
fi
158+
159+
# Step 7: 挂载 qcow2 分区
160+
echo "Mounting NBD partition..."
161+
mount "$NBD_DEVICE" "$MOUNT_DIR"
162+
if [ $? -ne 0 ]; then
163+
echo "Failed to mount NBD partition."
164+
qemu-nbd -d "$NBD_DEVICE"
165+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
166+
losetup -d "$LOOP_DEVICE"
167+
rm -f "$RAW_FILE" "$QCOW2_FILE"
168+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
169+
exit 1
170+
fi
171+
172+
# Step 8: 挂载根分区
173+
echo "Mounting root partition..."
174+
mount "$ROOT_PARTITION_DEVICE" "$SOURCE_MOUNT_DIR"
175+
if [ $? -ne 0 ]; then
176+
echo "Failed to mount root partition."
177+
umount "$MOUNT_DIR"
178+
qemu-nbd -d "$NBD_DEVICE"
179+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
180+
losetup -d "$LOOP_DEVICE"
181+
rm -f "$RAW_FILE" "$QCOW2_FILE"
182+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
183+
exit 1
184+
fi
185+
186+
# Step 9: 复制根分区内容到目标分区
187+
echo "Copying data from root partition to mounted directory..."
188+
rsync -a --info=progress2 "$SOURCE_MOUNT_DIR/" "$MOUNT_DIR/"
189+
if [ $? -ne 0 ]; then
190+
echo "Failed to copy data from root partition."
191+
umount "$SOURCE_MOUNT_DIR"
192+
umount "$MOUNT_DIR"
193+
qemu-nbd -d "$NBD_DEVICE"
194+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
195+
losetup -d "$LOOP_DEVICE"
196+
rm -f "$RAW_FILE" "$QCOW2_FILE"
197+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
198+
exit 1
199+
fi
200+
201+
umount "$SOURCE_MOUNT_DIR"
202+
203+
# Step 10: 配置 /etc/fstab 挂载
204+
echo "Configuring /etc/fstab..."
205+
mkdir -p "$MOUNT_DIR/mnt/share"
206+
cat > "$MOUNT_DIR/etc/fstab" << 'EOF'
207+
hostshare /mnt/share 9p trans=virtio,version=9p2000.L 0 0
208+
EOF
209+
echo " Configured /etc/fstab with share mount"
210+
211+
# Step 11: 配置网络
212+
echo "Configuring network..."
213+
NETWORK_INTERFACES="$MOUNT_DIR/etc/network/interfaces"
214+
mkdir -p "$(dirname "$NETWORK_INTERFACES")"
215+
cat > "$NETWORK_INTERFACES" << 'EOF'
216+
auto lo
217+
iface lo inet loopback
218+
219+
auto eth0
220+
iface eth0 inet dhcp
221+
EOF
222+
echo " Configured /etc/network/interfaces with DHCP for eth0"
223+
224+
# Step 12: 创建 /sbin/init 到 /init 的相对路径软链接
225+
echo "Creating relative symbolic link sbin/init -> init..."
226+
cd "$MOUNT_DIR" || { echo "Failed to change directory to $MOUNT_DIR"; exit 1; }
227+
ln -srf "sbin/init" "init"
228+
if [ $? -ne 0 ]; then
229+
echo "Failed to create relative symbolic link sbin/init -> init."
230+
cd -
231+
umount "$MOUNT_DIR"
232+
qemu-nbd -d "$NBD_DEVICE"
233+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
234+
losetup -d "$LOOP_DEVICE"
235+
rm -f "$RAW_FILE" "$QCOW2_FILE"
236+
rm -rf "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
237+
exit 1
238+
fi
239+
cd -
240+
241+
# Step 13: 禁用内核更新
242+
echo "Disabling kernel updates in APT configuration..."
243+
APT_CONF="$MOUNT_DIR/etc/apt/apt.conf.d/99no-kernel-update"
244+
mkdir -p "$(dirname "$APT_CONF")"
245+
cat > "$APT_CONF" << 'EOF'
246+
APT::Get::Upgrade-Allow-New "false";
247+
EOF
248+
249+
# 使用 APT preferences 阻止内核包更新
250+
PREF_DIR="$MOUNT_DIR/etc/apt/preferences.d"
251+
mkdir -p "$PREF_DIR"
252+
cat > "$PREF_DIR/99no-kernel-update" << 'EOF'
253+
Package: linux-image-* linux-headers-* linux-modules-*
254+
Pin: release *
255+
Pin-Priority: -1
256+
EOF
257+
echo " Disabled kernel updates"
258+
259+
# Step 14: 卸载分区并断开连接
260+
echo "Unmounting and detaching devices..."
261+
umount "$MOUNT_DIR"
262+
qemu-nbd -d "$NBD_DEVICE"
263+
losetup -d "$ROOT_PARTITION_DEVICE" 2>/dev/null
264+
losetup -d "$LOOP_DEVICE"
265+
if [ $? -ne 0 ]; then
266+
echo "Failed to detach devices."
267+
exit 1
268+
fi
269+
270+
# Step 15: 使用 qemu-img convert 压缩 qcow2 文件为目标文件
271+
echo "Compressing qcow2 file using qemu-img convert..."
272+
qemu-img convert -O qcow2 -c "$QCOW2_FILE" "$TARGET"
273+
if [ $? -ne 0 ]; then
274+
echo "Failed to compress qcow2 file."
275+
exit 1
276+
fi
277+
278+
# 清理临时文件
279+
echo "Cleaning up temporary files..."
280+
rm -rf "$RAW_FILE" "$QCOW2_FILE" "$MOUNT_DIR" "$SOURCE_MOUNT_DIR"
281+
282+
echo "Conversion completed successfully. Target file: $TARGET"

0 commit comments

Comments
 (0)