aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-29 02:12:35 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-29 02:12:35 +0800
commit298dd9150ec8bc92af1bc1685726e1cd98d16b49 (patch)
treedac8b52571821433123fb56ecc32b98fa229d996
parentd8bfc59e2f5dc0728326ae7a143f8fdc113932e2 (diff)
downloadrutils-298dd9150ec8bc92af1bc1685726e1cd98d16b49.tar.gz
rutils-298dd9150ec8bc92af1bc1685726e1cd98d16b49.tar.xz
Add configurable host directory bind mounts for container entry and command execution.
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
-rw-r--r--debian-container/README9
-rwxr-xr-xdebian-container/debian-container.sh3
-rw-r--r--debian-container/lib/binds.sh64
-rw-r--r--debian-container/lib/common.sh3
-rw-r--r--debian-container/lib/container.sh44
-rw-r--r--debian-container/lib/mount.sh1
6 files changed, 120 insertions, 4 deletions
diff --git a/debian-container/README b/debian-container/README
index 15fd95b..b0e11fe 100644
--- a/debian-container/README
+++ b/debian-container/README
@@ -27,11 +27,14 @@ sudo ./debian-container.sh resize test-3 --size 12G
sudo ./debian-container.sh enter test-1
sudo ./debian-container.sh enter test-1 --network host
+sudo ./debian-container.sh enter test-1 --mount /home/richard/project:/workspace:rw
+sudo ./debian-container.sh enter test-1 --mount /home/richard/data:/data:ro
在容器中执行命令:
sudo ./debian-container.sh exec test-1 -- uname -a
sudo ./debian-container.sh exec test-1 --network host -- apt-get update
+sudo ./debian-container.sh exec test-1 --mount /home/richard/project:/workspace:rw -- make -C /workspace
列出和查看容器:
@@ -74,4 +77,10 @@ DEBIAN_INCLUDE 额外软件包,使用逗号分隔
DEBIAN_EXCLUDE 要排除的软件包,使用逗号分隔
DEBIAN_NETWORK 默认网络模式,none 或 host
+挂载参数格式:
+
+HOST:CONTAINER[:ro|rw]
+
+目前只支持目录挂载,默认模式为 rw。
+
脚本实现按职责拆分在 lib/ 目录中,入口脚本只负责加载模块和分发命令。
diff --git a/debian-container/debian-container.sh b/debian-container/debian-container.sh
index 78b0009..d6bfbaf 100755
--- a/debian-container/debian-container.sh
+++ b/debian-container/debian-container.sh
@@ -13,6 +13,7 @@ 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/binds.sh"
source "$DC_DIR/lib/container.sh"
DC_ACTION=${1:-}
@@ -52,7 +53,7 @@ case "$DC_ACTION" in
init) dc_init "$@" ;;
_init) dc_init_rootfs "$@" ;;
enter) dc_enter "$@" ;;
- _enter) dc_enter_rootfs ;;
+ _enter) dc_enter_rootfs "$@" ;;
exec) dc_exec "$@" ;;
_exec) dc_exec_rootfs "$@" ;;
resize) dc_resize "$@" ;;
diff --git a/debian-container/lib/binds.sh b/debian-container/lib/binds.sh
new file mode 100644
index 0000000..7725bd8
--- /dev/null
+++ b/debian-container/lib/binds.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2026 by Richard Qin
+
+DC_BIND_SPECS=()
+DC_BIND_SOURCES=()
+DC_BIND_TARGETS=()
+DC_BIND_MODES=()
+
+dc_bind_add() {
+ local spec=$1
+ local source
+ local target
+ local mode
+ local extra
+
+ IFS=: read -r source target mode extra <<< "$spec"
+ [[ -n "$source" && -n "$target" && -z "$extra" ]] || dc_die "挂载参数格式无效:$spec"
+ [[ "$source" = /* && "$target" = /* ]] || dc_die "挂载源和目标必须使用绝对路径:$spec"
+ [[ "$target" != "/" ]] || dc_die '不能把目录挂载到容器根目录。'
+
+ mode=${mode:-rw}
+ [[ "$mode" == rw || "$mode" == ro ]] || dc_die "挂载模式无效:$mode"
+ source=$(readlink -f -- "$source")
+ [[ -d "$source" ]] || dc_die "挂载源不是目录:$source"
+ target=$(readlink -m -- "$target")
+ [[ "$target" != "/" ]] || dc_die '不能把目录挂载到容器根目录。'
+
+ DC_BIND_SPECS+=("$source:$target:$mode")
+ DC_BIND_SOURCES+=("$source")
+ DC_BIND_TARGETS+=("$target")
+ DC_BIND_MODES+=("$mode")
+}
+
+dc_bind_load_options() {
+ while (($# > 0)); do
+ [[ "$1" == --mount ]] || dc_die '挂载参数格式无效。'
+ (($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
+ dc_bind_add "$2"
+ shift 2
+ done
+}
+
+dc_bind_mount_all() {
+ local index
+ local target
+
+ for index in "${!DC_BIND_SPECS[@]}"; do
+ target="$DC_ROOT${DC_BIND_TARGETS[index]}"
+ mkdir -p "$target"
+ mount --bind "${DC_BIND_SOURCES[index]}" "$target"
+ if [[ "${DC_BIND_MODES[index]}" == ro ]]; then
+ mount -o remount,bind,ro "$target"
+ fi
+ done
+}
+
+dc_bind_cleanup() {
+ local index
+
+ for ((index = ${#DC_BIND_TARGETS[@]} - 1; index >= 0; index--)); do
+ umount "$DC_ROOT${DC_BIND_TARGETS[index]}" 2>/dev/null || true
+ done
+}
diff --git a/debian-container/lib/common.sh b/debian-container/lib/common.sh
index 9fd03b4..4102188 100644
--- a/debian-container/lib/common.sh
+++ b/debian-container/lib/common.sh
@@ -76,6 +76,9 @@ base-create 选项:
网络选项:
--network MODE 网络模式:none(默认)或 host
+挂载选项:
+ --mount SPEC 目录挂载: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 eee6d76..5f040e3 100644
--- a/debian-container/lib/container.sh
+++ b/debian-container/lib/container.sh
@@ -181,6 +181,7 @@ dc_base_create() {
dc_enter() {
local network_mode=$DC_NETWORK_MODE
+ local -a bind_args=()
while (($# > 0)); do
case "$1" in
@@ -189,6 +190,12 @@ dc_enter() {
network_mode=$2
shift 2
;;
+ --mount)
+ (($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
+ dc_bind_add "$2"
+ bind_args+=(--mount "${DC_BIND_SPECS[$((${#DC_BIND_SPECS[@]} - 1))]}")
+ shift 2
+ ;;
--help|-h)
dc_usage
return 0
@@ -203,13 +210,15 @@ dc_enter() {
dc_network_prepare "$network_mode"
unshare --mount --uts --ipc --pid --fork --propagation private \
- "${DC_NETWORK_UNSHARE_ARGS[@]}" -- bash "$DC_SCRIPT" _enter "$DC_INSTANCE"
+ "${DC_NETWORK_UNSHARE_ARGS[@]}" -- bash "$DC_SCRIPT" _enter "$DC_INSTANCE" "${bind_args[@]}"
}
dc_enter_rootfs() {
+ dc_bind_load_options "$@"
dc_mount_root
trap dc_cleanup_mounts EXIT
dc_mount_virtual_filesystems
+ dc_bind_mount_all
hostname debian-container
echo '已进入独立的 Debian 实验环境;输入 exit 可退出容器。'
@@ -220,6 +229,7 @@ dc_enter_rootfs() {
dc_exec() {
local network_mode=$DC_NETWORK_MODE
+ local -a bind_args=()
while (($# > 0)); do
case "$1" in
@@ -228,6 +238,12 @@ dc_exec() {
network_mode=$2
shift 2
;;
+ --mount)
+ (($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
+ dc_bind_add "$2"
+ bind_args+=(--mount "${DC_BIND_SPECS[$((${#DC_BIND_SPECS[@]} - 1))]}")
+ shift 2
+ ;;
--)
shift
break
@@ -248,17 +264,39 @@ dc_exec() {
unshare --mount --uts --ipc --pid --fork --propagation private \
"${DC_NETWORK_UNSHARE_ARGS[@]}" -- \
- bash "$DC_SCRIPT" _exec "$DC_INSTANCE" "$@"
+ bash "$DC_SCRIPT" _exec "$DC_INSTANCE" "${bind_args[@]}" -- "$@"
}
dc_exec_rootfs() {
+ local -a command_args=()
+
+ while (($# > 0)); do
+ case "$1" in
+ --mount)
+ (($# >= 2)) || dc_die '--mount 需要一个挂载参数。'
+ dc_bind_add "$2"
+ shift 2
+ ;;
+ --)
+ shift
+ command_args=("$@")
+ break
+ ;;
+ *)
+ dc_die 'exec 子进程参数格式无效。'
+ ;;
+ esac
+ done
+
+ (($# > 0)) || dc_die 'exec 需要一个命令。'
dc_mount_root
trap dc_cleanup_mounts EXIT
dc_mount_virtual_filesystems
+ dc_bind_mount_all
hostname debian-container
setpriv --bounding-set=-sys_admin,-net_admin,-net_raw,-sys_module,-sys_boot,-sys_time,-sys_rawio,-sys_ptrace,-syslog -- \
- chroot "$DC_ROOT" "$@"
+ chroot "$DC_ROOT" "${command_args[@]}"
}
dc_status() {
diff --git a/debian-container/lib/mount.sh b/debian-container/lib/mount.sh
index 0b623c8..26403c7 100644
--- a/debian-container/lib/mount.sh
+++ b/debian-container/lib/mount.sh
@@ -3,6 +3,7 @@
# Copyright (C) 2026 by Richard Qin
dc_cleanup_mounts() {
+ dc_bind_cleanup
umount "$DC_ROOT/dev/pts" 2>/dev/null || true
umount "$DC_ROOT/dev" 2>/dev/null || true
umount "$DC_ROOT/proc" 2>/dev/null || true