aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-29 02:23:17 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-29 02:23:17 +0800
commit808c626c612b238f6923c3ec2d6a05c5611d87db (patch)
tree049edc6114487c2cecc8034c778c50ec0758aaeb
parent298dd9150ec8bc92af1bc1685726e1cd98d16b49 (diff)
downloadrutils-808c626c612b238f6923c3ec2d6a05c5611d87db.tar.gz
rutils-808c626c612b238f6923c3ec2d6a05c5611d87db.tar.xz
Add container profiles for persistent network and bind mount configuration.
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
-rw-r--r--debian-container/README15
-rwxr-xr-xdebian-container/debian-container.sh1
-rw-r--r--debian-container/lib/common.sh5
-rw-r--r--debian-container/lib/container.sh39
-rw-r--r--debian-container/lib/profiles.sh50
5 files changed, 108 insertions, 2 deletions
diff --git a/debian-container/README b/debian-container/README
index b0e11fe..25734f0 100644
--- a/debian-container/README
+++ b/debian-container/README
@@ -19,6 +19,17 @@ 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
+使用 profile 创建容器:
+
+profile 文件内容:
+
+network=none
+mount=/home/richard/project:/workspace:rw
+mount=/home/richard/data:/data:ro
+
+sudo ./debian-container.sh init lab --profile ./lab.profile --tarball ./debian-stable.tar.gz
+sudo ./debian-container.sh enter lab
+
扩容容器:
sudo ./debian-container.sh resize test-3 --size 12G
@@ -53,6 +64,7 @@ sudo ./debian-container.sh init test-3
instances/test-1/rootfs.ext4
instances/test-1/root/
+instances/lab/config
默认基础 tarball:
@@ -83,4 +95,7 @@ HOST:CONTAINER[:ro|rw]
目前只支持目录挂载,默认模式为 rw。
+实例 profile 保存在 instances/NAME/config,支持 network 和 mount 配置项。
+enter 或 exec 的命令行选项会覆盖 profile 中的网络模式,并追加挂载项。
+
脚本实现按职责拆分在 lib/ 目录中,入口脚本只负责加载模块和分发命令。
diff --git a/debian-container/debian-container.sh b/debian-container/debian-container.sh
index d6bfbaf..44bd55a 100755
--- a/debian-container/debian-container.sh
+++ b/debian-container/debian-container.sh
@@ -14,6 +14,7 @@ source "$DC_DIR/lib/network.sh"
source "$DC_DIR/lib/storage.sh"
source "$DC_DIR/lib/mount.sh"
source "$DC_DIR/lib/binds.sh"
+source "$DC_DIR/lib/profiles.sh"
source "$DC_DIR/lib/container.sh"
DC_ACTION=${1:-}
diff --git a/debian-container/lib/common.sh b/debian-container/lib/common.sh
index 4102188..96ed00b 100644
--- a/debian-container/lib/common.sh
+++ b/debian-container/lib/common.sh
@@ -61,6 +61,7 @@ dc_usage() {
init 选项:
--tarball PATH 从本地 tarball 初始化,跳过软件包下载
--size SIZE 镜像大小(默认:3G)
+ --profile PATH 复制实例 profile
resize 选项:
--size SIZE 新的镜像大小,只能扩大
@@ -79,6 +80,10 @@ base-create 选项:
挂载选项:
--mount SPEC 目录挂载:HOST:CONTAINER[:ro|rw]
+profile 配置项:
+ network=MODE
+ mount=HOST:CONTAINER[:ro|rw]
+
环境变量:
DEBIAN_INSTANCES 实例目录(默认:当前目录/instances)
DEBIAN_SIZE 新实例镜像大小(默认:3G)
diff --git a/debian-container/lib/container.sh b/debian-container/lib/container.sh
index 5f040e3..2ae920e 100644
--- a/debian-container/lib/container.sh
+++ b/debian-container/lib/container.sh
@@ -5,6 +5,7 @@
dc_init() {
local tarball=
local size=$DC_SIZE
+ local profile=
while (($# > 0)); do
case "$1" in
@@ -18,6 +19,11 @@ dc_init() {
size=$2
shift 2
;;
+ --profile)
+ (($# >= 2)) || dc_die '--profile 需要一个文件路径。'
+ profile=$2
+ shift 2
+ ;;
--help|-h)
dc_usage
return 0
@@ -34,6 +40,10 @@ dc_init() {
tarball=$(readlink -f -- "$tarball")
[[ -f "$tarball" ]] || dc_die "找不到 tarball:$tarball"
fi
+ if [[ -n "$profile" ]]; then
+ profile=$(readlink -f -- "$profile")
+ [[ -f "$profile" ]] || dc_die "找不到 profile:$profile"
+ fi
if [[ -e "$DC_INSTANCE_DIR" ]]; then
dc_die "实例已存在:$DC_INSTANCE。请使用 enter 进入,避免覆盖容器数据。"
@@ -45,6 +55,12 @@ dc_init() {
else
unshare --mount --propagation private -- bash "$DC_SCRIPT" _init "$DC_INSTANCE"
fi
+ DC_PROFILE_FILE="$DC_INSTANCE_DIR/config"
+ if [[ -n "$profile" ]]; then
+ cp -- "$profile" "$DC_PROFILE_FILE"
+ else
+ dc_profile_write_default "$DC_NETWORK_MODE"
+ fi
echo "初始化完成。执行 sudo bash $DC_SCRIPT enter $DC_INSTANCE 进入容器。"
}
@@ -182,6 +198,10 @@ dc_base_create() {
dc_enter() {
local network_mode=$DC_NETWORK_MODE
local -a bind_args=()
+ local spec
+
+ dc_profile_load
+ network_mode=$DC_PROFILE_NETWORK
while (($# > 0)); do
case "$1" in
@@ -193,7 +213,6 @@ dc_enter() {
--mount)
(($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
dc_bind_add "$2"
- bind_args+=(--mount "${DC_BIND_SPECS[$((${#DC_BIND_SPECS[@]} - 1))]}")
shift 2
;;
--help|-h)
@@ -208,6 +227,9 @@ dc_enter() {
[[ -f "$DC_IMAGE" ]] || dc_die '没有找到镜像,请先运行 init。'
dc_network_prepare "$network_mode"
+ for spec in "${DC_BIND_SPECS[@]}"; do
+ bind_args+=(--mount "$spec")
+ done
unshare --mount --uts --ipc --pid --fork --propagation private \
"${DC_NETWORK_UNSHARE_ARGS[@]}" -- bash "$DC_SCRIPT" _enter "$DC_INSTANCE" "${bind_args[@]}"
@@ -230,6 +252,10 @@ dc_enter_rootfs() {
dc_exec() {
local network_mode=$DC_NETWORK_MODE
local -a bind_args=()
+ local spec
+
+ dc_profile_load
+ network_mode=$DC_PROFILE_NETWORK
while (($# > 0)); do
case "$1" in
@@ -241,7 +267,6 @@ dc_exec() {
--mount)
(($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
dc_bind_add "$2"
- bind_args+=(--mount "${DC_BIND_SPECS[$((${#DC_BIND_SPECS[@]} - 1))]}")
shift 2
;;
--)
@@ -261,6 +286,9 @@ dc_exec() {
(($# > 0)) || dc_die 'exec 需要一个命令。'
[[ -f "$DC_IMAGE" ]] || dc_die '没有找到镜像,请先运行 init。'
dc_network_prepare "$network_mode"
+ for spec in "${DC_BIND_SPECS[@]}"; do
+ bind_args+=(--mount "$spec")
+ done
unshare --mount --uts --ipc --pid --fork --propagation private \
"${DC_NETWORK_UNSHARE_ARGS[@]}" -- \
@@ -300,8 +328,15 @@ dc_exec_rootfs() {
}
dc_status() {
+ local spec
+
+ dc_profile_load
echo "实例:$DC_INSTANCE"
echo "目录:$DC_INSTANCE_DIR"
+ echo "网络:$DC_PROFILE_NETWORK"
+ for spec in "${DC_BIND_SPECS[@]}"; do
+ echo "挂载:$spec"
+ done
if [[ -f "$DC_IMAGE" ]]; then
echo '镜像:存在'
fi
diff --git a/debian-container/lib/profiles.sh b/debian-container/lib/profiles.sh
new file mode 100644
index 0000000..77deee7
--- /dev/null
+++ b/debian-container/lib/profiles.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2026 by Richard Qin
+
+DC_PROFILE_FILE=
+DC_PROFILE_NETWORK=
+
+dc_profile_parse() {
+ local file=$1
+ local line
+ local key
+ local value
+
+ while IFS= read -r line || [[ -n "$line" ]]; do
+ [[ -z "$line" || "$line" == \#* ]] && continue
+ [[ "$line" == *=* ]] || dc_die "profile 配置格式无效:$line"
+ key=${line%%=*}
+ value=${line#*=}
+ case "$key" in
+ network)
+ DC_PROFILE_NETWORK=$value
+ ;;
+ mount)
+ dc_bind_add "$value"
+ ;;
+ *)
+ dc_die "profile 配置项无效:$key"
+ ;;
+ esac
+ done < "$file"
+}
+
+dc_profile_load() {
+ DC_BIND_SPECS=()
+ DC_BIND_SOURCES=()
+ DC_BIND_TARGETS=()
+ DC_BIND_MODES=()
+ DC_PROFILE_FILE="$DC_INSTANCE_DIR/config"
+ DC_PROFILE_NETWORK=$DC_NETWORK_MODE
+
+ if [[ -f "$DC_PROFILE_FILE" ]]; then
+ dc_profile_parse "$DC_PROFILE_FILE"
+ fi
+}
+
+dc_profile_write_default() {
+ local network_mode=$1
+
+ printf 'network=%s\n' "$network_mode" > "$DC_PROFILE_FILE"
+}