aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-28 20:05:03 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-28 20:05:03 +0800
commit36cf23ae3ba7295ca4021258681996fbbba9b14d (patch)
treeba4105eb47e80e1e4f0732a2d80e8fbb5fbf2c17
parentd7f36a47b6d0b8129600bb476cb013146d36142f (diff)
downloadrutils-36cf23ae3ba7295ca4021258681996fbbba9b14d.tar.gz
rutils-36cf23ae3ba7295ca4021258681996fbbba9b14d.tar.xz
Add Container Management Script
-rw-r--r--debian-container.sh100
1 files changed, 100 insertions, 0 deletions
diff --git a/debian-container.sh b/debian-container.sh
new file mode 100644
index 0000000..be2b1f5
--- /dev/null
+++ b/debian-container.sh
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+# Debian 构建容器
+set -Eeuo pipefail
+
+SCRIPT=$(readlink -f -- "${BASH_SOURCE[0]}")
+IMAGE=$PWD/rootfs.ext4
+ROOT=$PWD/debian-root/
+ACTION=${1:-}
+
+if [[ ${EUID} -ne 0 ]]; then
+ echo '请使用 sudo 执行本脚本。' >&2
+ exit 1
+fi
+
+cleanup_mounts() {
+ umount "$ROOT/dev/pts" 2>/dev/null || true
+ umount "$ROOT/dev" 2>/dev/null || true
+ umount "$ROOT/proc" 2>/dev/null || true
+ umount "$ROOT" 2>/dev/null || true
+}
+
+mount_root() {
+ mkdir -p "$ROOT"
+ mount -o loop "$IMAGE" "$ROOT"
+ mkdir -p "$ROOT/proc" "$ROOT/dev"
+}
+
+mount_virtual_filesystems() {
+ mount -t proc -o ro,nosuid,nodev,noexec proc "$ROOT/proc"
+ mount -t tmpfs -o mode=0755,nosuid tmpfs "$ROOT/dev"
+ mknod -m 0666 "$ROOT/dev/null" c 1 3
+ mknod -m 0666 "$ROOT/dev/zero" c 1 5
+ mknod -m 0666 "$ROOT/dev/random" c 1 8
+ mknod -m 0666 "$ROOT/dev/urandom" c 1 9
+ mknod -m 0666 "$ROOT/dev/tty" c 5 0
+ mkdir -p "$ROOT/dev/pts"
+ mount -t devpts -o newinstance,ptmxmode=0666,mode=0620 devpts "$ROOT/dev/pts"
+ ln -s pts/ptmx "$ROOT/dev/ptmx"
+}
+
+# 防止多个会话同时读写同一 ext4 镜像。
+case "$ACTION" in
+ init|enter|delete)
+ mkdir -p /run/lock
+ exec 9>/run/lock/debian-container.lock
+ flock -n 9 || { echo 'Debian 容器已经在运行或正在初始化。' >&2; exit 1; }
+ ;;
+esac
+
+case "$ACTION" in
+ init)
+ for tool in debootstrap unshare mkfs.ext4 mount chroot setpriv flock; do
+ command -v "$tool" >/dev/null || { echo "缺少工具:$tool" >&2; exit 1; }
+ done
+ if [[ -e "$IMAGE" ]]; then
+ echo "镜像已存在:$IMAGE。请使用 enter 进入,避免覆盖容器数据。" >&2
+ exit 1
+ fi
+ mkdir -p "$(dirname "$IMAGE")" "$ROOT"
+ truncate -s 3G "$IMAGE"
+ mkfs.ext4 -F -q -L DEBIAN_CONTAINER "$IMAGE"
+ unshare --mount --propagation private -- bash "$SCRIPT" _init
+ echo '初始化完成。执行 sudo bash debian-container.sh enter 进入容器。'
+ ;;
+ _init)
+ mount_root
+ trap cleanup_mounts EXIT
+ debootstrap --variant=minbase stable "$ROOT" http://deb.debian.org/debian
+ rm -f "$ROOT/etc/resolv.conf"
+ cp -L /etc/resolv.conf "$ROOT/etc/resolv.conf"
+ mount_virtual_filesystems
+ chroot "$ROOT" /usr/bin/env DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get update
+ chroot "$ROOT" /usr/bin/env DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y passwd util-linux vim-tiny e2fsprogs
+ echo debian-container > "$ROOT/etc/hostname"
+ ;;
+ enter)
+ [[ -f "$IMAGE" ]] || { echo '没有找到镜像,请先运行 init。' >&2; exit 1; }
+ # 单独创建网络命名空间,暂时没有联网功能。
+ unshare --mount --uts --ipc --pid --net --fork --propagation private -- bash "$SCRIPT" _enter
+ ;;
+ _enter)
+ mount_root
+ trap cleanup_mounts EXIT
+ mount_virtual_filesystems
+ hostname debian-container
+ echo '已进入独立的 Debian 实验环境;输入 exit 可退出。'
+ # 完成挂载后撤销一些宿主级危险权限,保留 CAP_LINUX_IMMUTABLE。
+ setpriv --bounding-set=-sys_admin,-net_admin,-net_raw,-sys_module,-sys_boot,-sys_time,-sys_rawio,-sys_ptrace,-syslog -- \
+ chroot "$ROOT" /bin/bash -l
+ ;;
+ delete)
+ [[ -f "$IMAGE" ]] || { echo 'Debian 镜像已不存在。'; exit 0; }
+ rm -- "$IMAGE"
+ echo 'Debian 镜像已删除。'
+ ;;
+ *)
+ echo "用法:sudo bash $0 init|enter|delete" >&2
+ exit 2
+ ;;
+esac