diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-10-29 02:57:51 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-10-29 02:57:51 +0800 |
| commit | aeb1ab2c3e960c6eb38ee2c9b18519b9b3bd8fa4 (patch) | |
| tree | 4404733e7bce7e41058ee227c8ce1c8fbf9d57a3 | |
| parent | b25c21a3272416d52e805b5253cc46f59587d4c2 (diff) | |
| download | rutils-aeb1ab2c3e960c6eb38ee2c9b18519b9b3bd8fa4.tar.gz rutils-aeb1ab2c3e960c6eb38ee2c9b18519b9b3bd8fa4.tar.xz | |
Add NAT networking with bridge, veth, DNS, routing, and firewall configuration for containers.
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
| -rw-r--r-- | debian-container/README | 9 | ||||
| -rw-r--r-- | debian-container/lib/common.sh | 7 | ||||
| -rw-r--r-- | debian-container/lib/container.sh | 12 | ||||
| -rw-r--r-- | debian-container/lib/network.sh | 82 |
4 files changed, 107 insertions, 3 deletions
diff --git a/debian-container/README b/debian-container/README index c0ef344..0328def 100644 --- a/debian-container/README +++ b/debian-container/README @@ -46,6 +46,7 @@ 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 --network nat 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 @@ -53,6 +54,7 @@ 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 --network nat -- apt-get update sudo ./debian-container.sh exec test-1 --mount /home/richard/project:/workspace:rw -- make -C /workspace 列出和查看容器: @@ -95,7 +97,12 @@ DEBIAN_ARCH 目标架构 DEBIAN_MIRROR Debian 镜像地址 DEBIAN_INCLUDE 额外软件包,使用逗号分隔 DEBIAN_EXCLUDE 要排除的软件包,使用逗号分隔 -DEBIAN_NETWORK 默认网络模式,none 或 host +DEBIAN_NETWORK 默认网络模式,none、host 或 nat +DEBIAN_NAT_BRIDGE NAT 网桥名称,默认 rutils0 +DEBIAN_NAT_NETWORK NAT 子网,默认 10.88.0.0/24 +DEBIAN_NAT_GATEWAY NAT 网关地址,默认 10.88.0.1 +DEBIAN_NAT_ADDRESS NAT 容器地址,默认 10.88.0.2 +DEBIAN_NAT_DNS NAT 模式 DNS,默认 1.1.1.1 挂载参数格式: diff --git a/debian-container/lib/common.sh b/debian-container/lib/common.sh index 6177482..075cd15 100644 --- a/debian-container/lib/common.sh +++ b/debian-container/lib/common.sh @@ -77,7 +77,7 @@ base-create 选项: --exclude PACKAGES 要排除的软件包,使用逗号分隔 网络选项: - --network MODE 网络模式:none(默认)或 host + --network MODE 网络模式:none(默认)、host 或 nat 挂载选项: --mount SPEC 目录挂载:HOST:CONTAINER[:ro|rw] @@ -97,6 +97,11 @@ profile 配置项: DEBIAN_INCLUDE 额外软件包,使用逗号分隔 DEBIAN_EXCLUDE 要排除的软件包,使用逗号分隔 DEBIAN_NETWORK 默认网络模式(默认:none) + DEBIAN_NAT_BRIDGE NAT 网桥名称(默认:rutils0) + DEBIAN_NAT_NETWORK NAT 子网(默认:10.88.0.0/24) + DEBIAN_NAT_GATEWAY NAT 网关地址(默认:10.88.0.1) + DEBIAN_NAT_ADDRESS 容器地址(默认:10.88.0.2) + DEBIAN_NAT_DNS NAT 模式 DNS(默认:1.1.1.1) EOF } diff --git a/debian-container/lib/container.sh b/debian-container/lib/container.sh index b3d8c9b..62ab0b3 100644 --- a/debian-container/lib/container.sh +++ b/debian-container/lib/container.sh @@ -247,6 +247,11 @@ dc_enter() { bind_args+=(--mount "$spec") done + if [[ "$network_mode" == nat ]]; then + dc_network_nat_run _enter "${bind_args[@]}" + return + fi + unshare --mount --uts --ipc --pid --fork --propagation private \ "${DC_NETWORK_UNSHARE_ARGS[@]}" -- bash "$DC_SCRIPT" _enter "$DC_INSTANCE" "${bind_args[@]}" } @@ -255,6 +260,7 @@ dc_enter_rootfs() { dc_bind_load_options "$@" dc_mount_root trap dc_cleanup_mounts EXIT + dc_network_configure_rootfs dc_mount_virtual_filesystems dc_bind_mount_all hostname debian-container @@ -306,6 +312,11 @@ dc_exec() { bind_args+=(--mount "$spec") done + if [[ "$network_mode" == nat ]]; then + dc_network_nat_run _exec "${bind_args[@]}" -- "$@" + return + fi + unshare --mount --uts --ipc --pid --fork --propagation private \ "${DC_NETWORK_UNSHARE_ARGS[@]}" -- \ bash "$DC_SCRIPT" _exec "$DC_INSTANCE" "${bind_args[@]}" -- "$@" @@ -335,6 +346,7 @@ dc_exec_rootfs() { (($# > 0)) || dc_die 'exec 需要一个命令。' dc_mount_root trap dc_cleanup_mounts EXIT + dc_network_configure_rootfs dc_mount_virtual_filesystems dc_bind_mount_all hostname debian-container diff --git a/debian-container/lib/network.sh b/debian-container/lib/network.sh index 333869f..a5a31dd 100644 --- a/debian-container/lib/network.sh +++ b/debian-container/lib/network.sh @@ -4,6 +4,12 @@ DC_NETWORK_MODE=${DEBIAN_NETWORK:-none} DC_NETWORK_UNSHARE_ARGS=() +DC_NAT_BRIDGE=${DEBIAN_NAT_BRIDGE:-rutils0} +DC_NAT_NETWORK=${DEBIAN_NAT_NETWORK:-10.88.0.0/24} +DC_NAT_PREFIX=${DC_NAT_NETWORK#*/} +DC_NAT_GATEWAY=${DEBIAN_NAT_GATEWAY:-10.88.0.1} +DC_NAT_ADDRESS=${DEBIAN_NAT_ADDRESS:-10.88.0.2} +DC_NAT_DNS=${DEBIAN_NAT_DNS:-1.1.1.1} dc_network_prepare() { local mode=${1:-$DC_NETWORK_MODE} @@ -15,8 +21,82 @@ dc_network_prepare() { host) DC_NETWORK_UNSHARE_ARGS=() ;; + nat) + DC_NETWORK_UNSHARE_ARGS=(--net) + ;; *) - dc_die "网络模式无效:$mode(可选:none、host)" + dc_die "网络模式无效:$mode(可选:none、host、nat)" ;; esac } + +dc_network_configure_rootfs() { + [[ "$DC_NETWORK_MODE" == nat ]] || return 0 + rm -f "$DC_ROOT/etc/resolv.conf" + printf 'nameserver %s\n' "$DC_NAT_DNS" > "$DC_ROOT/etc/resolv.conf" +} + +dc_network_nat_setup_firewall() { + dc_require_commands grep nft sysctl + + sysctl -w net.ipv4.ip_forward=1 >/dev/null + if ! nft list table ip rutils_nat >/dev/null 2>&1; then + nft add table ip rutils_nat + fi + if ! nft list chain ip rutils_nat postrouting >/dev/null 2>&1; then + nft 'add chain ip rutils_nat postrouting { type nat hook postrouting priority 100; policy accept; }' + fi + if ! nft list chain ip rutils_nat postrouting | grep -Fq "ip saddr $DC_NAT_NETWORK"; then + nft add rule ip rutils_nat postrouting ip saddr "$DC_NAT_NETWORK" oifname != "$DC_NAT_BRIDGE" masquerade + fi +} + +dc_network_nat_setup() { + local netns=$1 + local host_interface=$2 + local guest_interface=$3 + + dc_require_commands grep ip + if ! ip link show "$DC_NAT_BRIDGE" >/dev/null 2>&1; then + ip link add "$DC_NAT_BRIDGE" type bridge + fi + ip link set "$DC_NAT_BRIDGE" up + if ! ip -4 addr show dev "$DC_NAT_BRIDGE" | grep -Fq "inet $DC_NAT_GATEWAY/"; then + ip addr add "$DC_NAT_GATEWAY/$DC_NAT_PREFIX" dev "$DC_NAT_BRIDGE" + fi + + ip netns add "$netns" + ip link add "$host_interface" type veth peer name "$guest_interface" + ip link set "$guest_interface" netns "$netns" + ip link set "$host_interface" master "$DC_NAT_BRIDGE" + ip link set "$host_interface" up + + ip netns exec "$netns" ip link set lo up + ip netns exec "$netns" ip link set "$guest_interface" name eth0 + ip netns exec "$netns" ip addr add "$DC_NAT_ADDRESS/$DC_NAT_PREFIX" dev eth0 + ip netns exec "$netns" ip link set eth0 up + ip netns exec "$netns" ip route add default via "$DC_NAT_GATEWAY" + dc_network_nat_setup_firewall +} + +dc_network_nat_cleanup() { + local netns=$1 + local host_interface=$2 + + ip link delete "$host_interface" 2>/dev/null || true + ip netns delete "$netns" 2>/dev/null || true +} + +dc_network_nat_run() { + local child_action=$1 + local netns="rutils-${DC_INSTANCE}-$$" + local host_interface="rvh$$" + local guest_interface="rvg$$" + + shift + trap "dc_network_nat_cleanup '$netns' '$host_interface'" EXIT + dc_network_nat_setup "$netns" "$host_interface" "$guest_interface" + env DEBIAN_NETWORK=nat ip netns exec "$netns" \ + unshare --mount --uts --ipc --pid --fork --propagation private -- \ + bash "$DC_SCRIPT" "$child_action" "$DC_INSTANCE" "$@" +} |
