aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-29 01:41:01 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-29 01:41:01 +0800
commitd8bfc59e2f5dc0728326ae7a143f8fdc113932e2 (patch)
treec3b02a8d4d91d730cc21befe2b8dbf6d9b6bee0f
parentd9932da9c00fd92aaa0cafa5d6d63a6f8e724ad1 (diff)
downloadrutils-d8bfc59e2f5dc0728326ae7a143f8fdc113932e2.tar.gz
rutils-d8bfc59e2f5dc0728326ae7a143f8fdc113932e2.tar.xz
Add configurable container image sizing with support for creating and resizing ext4 images.
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
-rw-r--r--debian-container/README6
-rwxr-xr-xdebian-container/debian-container.sh6
-rw-r--r--debian-container/lib/common.sh6
-rw-r--r--debian-container/lib/config.sh1
-rw-r--r--debian-container/lib/container.sh39
-rw-r--r--debian-container/lib/storage.sh50
6 files changed, 101 insertions, 7 deletions
diff --git a/debian-container/README b/debian-container/README
index ef3bb97..15fd95b 100644
--- a/debian-container/README
+++ b/debian-container/README
@@ -17,6 +17,11 @@ sudo ./debian-container.sh base-create \
sudo ./debian-container.sh init test-1 --tarball ./debian-stable.tar.gz
sudo ./debian-container.sh init test-2 --tarball ./debian-stable.tar.gz
+sudo ./debian-container.sh init test-3 --size 8G --tarball ./debian-stable.tar.gz
+
+扩容容器:
+
+sudo ./debian-container.sh resize test-3 --size 12G
进入容器:
@@ -59,6 +64,7 @@ sudo env \
可配置的环境变量:
DEBIAN_INSTANCES 实例目录
+DEBIAN_SIZE 新实例镜像大小,默认 3G
DEBIAN_LOCK_FILE 锁文件路径
DEBIAN_TARBALL 默认基础 tarball 路径
DEBIAN_SUITE Debian 版本,默认 stable
diff --git a/debian-container/debian-container.sh b/debian-container/debian-container.sh
index 6ef4133..78b0009 100755
--- a/debian-container/debian-container.sh
+++ b/debian-container/debian-container.sh
@@ -11,6 +11,7 @@ DC_DIR=$(dirname -- "$DC_SCRIPT")
source "$DC_DIR/lib/config.sh"
source "$DC_DIR/lib/common.sh"
source "$DC_DIR/lib/network.sh"
+source "$DC_DIR/lib/storage.sh"
source "$DC_DIR/lib/mount.sh"
source "$DC_DIR/lib/container.sh"
@@ -27,14 +28,14 @@ esac
dc_require_root
case "$DC_ACTION" in
- base-create|init|enter|exec|delete)
+ base-create|init|enter|exec|resize|delete)
# 防止多个会话同时读写同一 ext4 镜像。
dc_acquire_lock
;;
esac
case "$DC_ACTION" in
- init|enter|exec|status|delete)
+ init|enter|exec|resize|status|delete)
(($# > 0)) || dc_die "$DC_ACTION 需要实例名称。"
dc_select_instance "$1"
shift
@@ -54,6 +55,7 @@ case "$DC_ACTION" in
_enter) dc_enter_rootfs ;;
exec) dc_exec "$@" ;;
_exec) dc_exec_rootfs "$@" ;;
+ resize) dc_resize "$@" ;;
status) dc_status ;;
list) dc_list ;;
delete) dc_delete ;;
diff --git a/debian-container/lib/common.sh b/debian-container/lib/common.sh
index d28948a..9fd03b4 100644
--- a/debian-container/lib/common.sh
+++ b/debian-container/lib/common.sh
@@ -53,12 +53,17 @@ dc_usage() {
init NAME [选项] 创建指定名称的容器镜像
enter NAME [选项] 进入指定容器
exec NAME [选项] 在指定容器中执行命令
+ resize NAME [选项] 扩大指定容器的镜像
status NAME 查看指定容器状态
list 列出所有容器
delete NAME 删除指定容器
init 选项:
--tarball PATH 从本地 tarball 初始化,跳过软件包下载
+ --size SIZE 镜像大小(默认:3G)
+
+resize 选项:
+ --size SIZE 新的镜像大小,只能扩大
base-create 选项:
--output PATH 输出 tarball 路径
@@ -73,6 +78,7 @@ base-create 选项:
环境变量:
DEBIAN_INSTANCES 实例目录(默认:当前目录/instances)
+ DEBIAN_SIZE 新实例镜像大小(默认:3G)
DEBIAN_LOCK_FILE 锁文件路径(默认:/run/lock/debian-container.lock)
DEBIAN_TARBALL 基础 tarball(默认:当前目录/debian-base.tar.gz)
DEBIAN_SUITE Debian 版本(默认:stable)
diff --git a/debian-container/lib/config.sh b/debian-container/lib/config.sh
index 0d91aad..3b59963 100644
--- a/debian-container/lib/config.sh
+++ b/debian-container/lib/config.sh
@@ -4,6 +4,7 @@
# Keep instance data in the directory from which the tool is invoked for now.
DC_INSTANCES=${DEBIAN_INSTANCES:-"$PWD/instances"}
+DC_SIZE=${DEBIAN_SIZE:-3G}
DC_LOCK_FILE=${DEBIAN_LOCK_FILE:-/run/lock/debian-container.lock}
DC_TARBALL=${DEBIAN_TARBALL:-"$PWD/debian-base.tar.gz"}
DC_SUITE=${DEBIAN_SUITE:-stable}
diff --git a/debian-container/lib/container.sh b/debian-container/lib/container.sh
index 2c0aaad..eee6d76 100644
--- a/debian-container/lib/container.sh
+++ b/debian-container/lib/container.sh
@@ -4,6 +4,7 @@
dc_init() {
local tarball=
+ local size=$DC_SIZE
while (($# > 0)); do
case "$1" in
@@ -12,6 +13,11 @@ dc_init() {
tarball=$2
shift 2
;;
+ --size)
+ (($# >= 2)) || dc_die '--size 需要一个大小。'
+ size=$2
+ shift 2
+ ;;
--help|-h)
dc_usage
return 0
@@ -33,9 +39,7 @@ dc_init() {
dc_die "实例已存在:$DC_INSTANCE。请使用 enter 进入,避免覆盖容器数据。"
fi
- mkdir -p "$DC_INSTANCE_DIR" "$DC_ROOT"
- truncate -s 3G "$DC_IMAGE"
- mkfs.ext4 -F -q -L DEBIAN_CONTAINER "$DC_IMAGE"
+ dc_create_image "$size"
if [[ -n "$tarball" ]]; then
unshare --mount --propagation private -- bash "$DC_SCRIPT" _init "$DC_INSTANCE" "$tarball"
else
@@ -44,6 +48,32 @@ dc_init() {
echo "初始化完成。执行 sudo bash $DC_SCRIPT enter $DC_INSTANCE 进入容器。"
}
+dc_resize() {
+ local size=
+
+ while (($# > 0)); do
+ case "$1" in
+ --size)
+ (($# >= 2)) || dc_die '--size 需要一个大小。'
+ size=$2
+ shift 2
+ ;;
+ --help|-h)
+ dc_usage
+ return 0
+ ;;
+ *)
+ dc_die "未知的 resize 选项:$1"
+ ;;
+ esac
+ done
+
+ [[ -n "$size" ]] || dc_die 'resize 必须指定 --size。'
+ [[ -f "$DC_IMAGE" ]] || dc_die '没有找到镜像,请先运行 init。'
+ dc_resize_image "$size"
+ echo "实例已扩容:$DC_INSTANCE,新的大小为 $size"
+}
+
dc_init_rootfs() {
local tarball=${1:-}
local -a include_packages=()
@@ -236,9 +266,8 @@ dc_status() {
echo "目录:$DC_INSTANCE_DIR"
if [[ -f "$DC_IMAGE" ]]; then
echo '镜像:存在'
- else
- echo '镜像:不存在'
fi
+ dc_status_image
}
dc_delete() {
diff --git a/debian-container/lib/storage.sh b/debian-container/lib/storage.sh
new file mode 100644
index 0000000..e72c0b9
--- /dev/null
+++ b/debian-container/lib/storage.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2026 by Richard Qin
+
+dc_create_image() {
+ local size=$1
+
+ mkdir -p "$DC_INSTANCE_DIR" "$DC_ROOT"
+ truncate -s "$size" "$DC_IMAGE"
+ mkfs.ext4 -F -q -L DEBIAN_CONTAINER "$DC_IMAGE"
+}
+
+dc_resize_image() {
+ local size=$1
+ local current_size
+ local target_size
+ local allocated_blocks
+ local block_size
+
+ dc_require_commands e2fsck findmnt numfmt resize2fs stat truncate
+ if findmnt --mountpoint "$DC_ROOT" >/dev/null 2>&1; then
+ dc_die "实例仍处于挂载状态:$DC_INSTANCE"
+ fi
+
+ current_size=$(stat -c '%s' "$DC_IMAGE")
+ target_size=$(numfmt --from=iec "$size")
+ ((target_size > current_size)) || dc_die "扩容大小必须大于当前镜像大小:$current_size bytes"
+
+ truncate -s "$size" "$DC_IMAGE"
+ if e2fsck -f -y "$DC_IMAGE"; then
+ :
+ else
+ [[ $? -eq 1 ]] || dc_die "文件系统检查失败:$DC_IMAGE"
+ fi
+ resize2fs "$DC_IMAGE"
+}
+
+dc_status_image() {
+ local allocated_blocks
+ local block_size
+
+ if [[ -f "$DC_IMAGE" ]]; then
+ allocated_blocks=$(stat -c '%b' "$DC_IMAGE")
+ block_size=$(stat -c '%B' "$DC_IMAGE")
+ echo "逻辑大小:$(stat -c '%s' "$DC_IMAGE") bytes"
+ echo "实际占用:$((allocated_blocks * block_size)) bytes"
+ else
+ echo '镜像:不存在'
+ fi
+}