diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-10-29 01:41:01 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-10-29 01:41:01 +0800 |
| commit | d8bfc59e2f5dc0728326ae7a143f8fdc113932e2 (patch) | |
| tree | c3b02a8d4d91d730cc21befe2b8dbf6d9b6bee0f | |
| parent | d9932da9c00fd92aaa0cafa5d6d63a6f8e724ad1 (diff) | |
| download | rutils-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/README | 6 | ||||
| -rwxr-xr-x | debian-container/debian-container.sh | 6 | ||||
| -rw-r--r-- | debian-container/lib/common.sh | 6 | ||||
| -rw-r--r-- | debian-container/lib/config.sh | 1 | ||||
| -rw-r--r-- | debian-container/lib/container.sh | 39 | ||||
| -rw-r--r-- | debian-container/lib/storage.sh | 50 |
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 +} |
