Strongswan 守护进程将其 .pid 和 .ctl 文件放入 /var/run 中以检测它是否已在运行。
我想在不同网络命名空间中的同一台计算机上运行多个守护进程。我试图通过绑定安装不同的目录来实现此目的(例如将 /etc/namespace1 绑定到namespace1 的 /var/run 并将 /etc/namespace2 绑定到namespace2 的 /var/run )。 /var/run 是 /run 的符号链接,因此我将挂载绑定到 /run ,如下所示。
我几乎可以这样实现:
""在默认命名空间中""
$:~ sudo echo "red" >> /etc/red/run/pidfile
$:~ sudo echo "blue" >> /etc/blue/run/pidfile
$:~ sudo ip netns exec red
""在红色命名空间中""
$:~ mount --bind /etc/red/run/ /run/
$:~ cat /var/run/pidfile
红色的
""在蓝色命名空间中""
$:~ mount --bind /etc/blue/run/ /run/
$:~ cat /var/run/pidfile
蓝色的
所以这很好用。这样,守护进程在红色内部创建 /var/run/charon.pid 时不会与蓝色名称空间的 /var/run/charon.pid 混淆,并且可以启动两个实例。
但是,问题在于:如果我从 red 命名空间“退出”,然后通过“ip netns exec red bash”重新进入,则挂载不再存在。也就是说根本没有 /var/run/redfile 。
那么,问题是我怎样才能让这个粘性呢?我需要更改 /etc/fstab 吗?但这不起作用。如果有人问起,我可以提供“它不起作用”的详细信息。
我搞不清楚了。将不胜感激一些帮助。
谢谢!
答案1
简单的解决方案是通过设置正确的 PID 值来指示 Strongswan 的每个实例使用不同的目录来存储 PID 文件。IPSEC_PIDDIR
启动和停止脚本中的环境变量。
答案2
ip netns exec
已经绑定挂载/etc/netns/<netns name>/*
到/etc
.因此,您可以使用eg编译strongSwan --with-piddir=/etc/ipsec.d/run
,然后创建所需的目录,以便每个实例在单独的目录中创建其PID文件:
# mkdir -p /etc/ipsec.d/run
# mkdir -p /etc/netns/<netns name 1>/ipsec.d/run
# mkdir -p /etc/netns/<netns name 2>/ipsec.d/run
更多详细信息可以在强天鹅维基。
答案3
问题原因据我所知
ip netns add ${NSNAME}
通过将其挂载到/run/netns/${NSNAME}
.这本身并不涉及挂载命名空间。
做ip netns exec ${NSNAME} cmd
会产生一个暂时的挂载命名空间一直存在直到cmd
退出,之后挂载命名空间被清理,只剩下网络命名空间。这是实现 的魔法安装所必需的/etc/netns/${NSNAME}/*
。不幸的是,由他们完成的任何安装cmd
也被清理掉了。
从man ip-netns
:
ip netns exec
通过创建安装命名空间并将所有每个网络命名空间配置文件绑定安装到 /etc 中的传统位置,自动处理此配置、网络命名空间不感知应用程序的文件约定。
一个办法
简洁版本
# Init for persistent mount namespaces
$ mkdir /run/mntns \
&& mount --bind --make-private /run/mntns /run/mntns
$ NSNAME=red
# Create persistent network+mount namespaces
$ ip netns add ${NSNAME} \
&& touch "/run/mntns/${NSNAME}" \
&& ip netns exec "${NSNAME}" \
sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"
# Do NOT use `ip netns exec`
# (Re)enter the namespaces with `nsenter`, mounts are persistent
$ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
program arg1 arg2
长版
可以创建持久的网络和挂载命名空间。
这很大程度上改编自unshare
手册页中的示例:http://man7.org/linux/man-pages/man1/unshare.1.html
主要含义是,现在必须ip netns exec
同时nsenter
使用网络+挂载命名空间,至少在挂载很重要的地方。
步骤 1. 准备。为持久挂载命名空间创建目录
这需要完成一次,例如在启动后,而不是针对每个命名空间。这里的路径是任意的。我正在尝试使用与ip netns
.
# Try to create a dir for persistent mount namespaces
# and if it got created (e.g. first attempt since boot),
# then bind mount it with --make-private as required by `unshare --mount=/path`
$ mkdir /run/mntns \
&& mount --bind --make-private /run/mntns /run/mntns
请注意,它们mkdir ... && mount ...
不是原子的,并且如果有多个同时启动的服务执行此序列,则可能会发生竞争条件。
步骤2.创建网络+挂载持久命名空间
2a.方法A,简单,无需魔法绑定坐骑。
这将创建持久挂载+网络命名空间。它很简单,但不会为/etc/netns/${NSNAME}/*
.
$ NSNAME=red # give it a name
# For network namespace use same paths as used by `ip netns` for interoperability
# touch can fail to update timestamp if file is already mounted
# Try to create files for persistent mounts.
# and if touch is successful
# then create persistent mount and network namespaces
# Instead of `true` can run a command right away e.g. /bin/bash
# As it is this is approximate equivalent of `ip netns add ${NANAME}`
$ touch /run/netns/${NSNAME} /run/mntns/${NSNAME} \
&& unshare --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} true
2b.方法B,杠杆ip netns exec
使坐骑但使持久。
要完成这些绑定安装ip netns exec ...
但使它们持久化,可以按如下方式进行设置。请注意,此操作只能在创建命名空间时执行一次,而不是每次都执行。
$ ip netns add ${NSNAME} \
&& touch "/run/mntns/${NSNAME}" \
&& ip netns exec "${NSNAME}" \
sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"
有关尝试的解释,请参阅最后。
步骤 3. 使用它
现在,nsenter
必须根据需要使用 来在两个命名空间内启动命令,以实现持久安装结果。这与是否使用unshare
或完成设置无关ip netns exec NAME sh ... nsneter ... mount ...
。
# Get a shell inside the namespaces
$ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
/bin/bash
例如使用OP的命令:
# Do your additional mounts (can also be done above as command to `unshare`)
# This is approximate equivalent of
# `ip netns exec ${NANAME} mount --bind /etc/red/run/ /run/`
$ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
mount --bind /etc/${NSNAME}/run/ /run/
# Re-enter the namespaces, check that the mounts are still there
$ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
sh -c 'ls /run/'
重要的
这种方法有效,但不是使用ip netns exec
use nsenter --net=... --mount=...
!如果ip netns exec ...
使用,它将替换(在其运行期间)挂载名称空间,这对于不关心挂载持久性的命令来说是可以的,例如
# This does not touch any files, only operates on network device
ip netns exec ${NSNAME} ip link set up dev lo
步骤 Z. - 清理
无论使用上述两种方法中的哪一种来创建命名空间,都可以通过这两种方法中的任意一种来完成清理:
# This deletes the /mnt/netns/${NSNAME} for us
ip netns del ${NSNAME}
# Unmount and delete mount namespace holder
umount "/mnt/mntns/${NSNAME}" \
&& rm "/mnt/mntns/${NSNAME}"
或者
# Unmount and delete both namespaces' holders
umount "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}" \
&& rm "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}"
解释
对于长文本表示歉意。这部分是为了我自己的利益。
此命令来自步骤2b以上值得一些解释。
又下令。
$ ip netns add ${NSNAME} \
&& touch "/run/mntns/${NSNAME}" \
&& ip netns exec "${NSNAME}" \
sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"
从man unshare
即使在程序终止后,也可以通过将 /proc/pid/ns/type 文件绑定到文件系统路径并使用 nsenter(1) 输入来使命名空间持久化(需要永久运行 init 进程的 PID 命名空间除外)。一旦不再需要持久命名空间,就可以使用 umount(8) 将其取消持久化。
解说开始
如果将其分解为简单的步骤,这就是它的作用。请注意,此演示需要两个 shell。
# SHELL-1
# Init
$ mkdir /run/mntns \
&& mount --bind --make-private /run/mntns /run/mntns
# Prep
$ NSNAME=red
# Create namespace
$ ip netns add ${NSNAME}
# Start a shell inside the namespace
$ ip netns exec "${NSNAME}" /bin/bash
# Now inside a shell inside a namespace.
# Now need to make a bind mount it this shell's mount namespace
$ echo $$ # Use this in SHELL2 AS SHELL1_PID
# Go to SHELL-2 before exiting this one
# SHELL-2
# Set this to PID from SHELL-1
$ SHELL1_PID=????
$ NSNAME=red
$ touch "/run/mntns/${NSNAME}"
$ mount --bind /proc/${SHELL1_PID}/ns/mnt "/run/mntns/${NSNAME}"
nsenter
现在,网络+挂载命名空间都是持久的,并且可以按照前面所示的方式重新输入。
重要的部分是将ip netns exec
'挂载/proc/pid/ns/net
到外壳的挂载命名空间中前 ip netns exec..
退出。
解释(续)
所以答案是:从ip netns exec ...
do内部nsenter
,但不是作为直接命令,因为这不会ip netns exec ${NSNAME} nsenter ...
exec()
因此fork()
留下并破坏临时名称空间,而是通过运行一个中间 shell 来导致 fork() ,该中间 shell 使临时名称空间保持活动状态,并且分叉nsenter
做mount
。下面的内容更接近于一长命令的工作方式。
# Init
$ mkdir /run/mntns \
&& mount --bind --make-private /run/mntns /run/mntns
# Prep
$ export NSNAME=red
$ touch "/run/mntns/${NSNAME}"
$ export MOUNT_PARENT_PID=$$ # for simplicity
# Create namespace
$ ip netns add ${NSNAME}
# Start a shell inside the namespace, the intermediate shell is important
$ ip netns exec "${NSNAME}" /bin/bash
# Now inside a forked namespaced shell
# Need to mount `ip netns exec` temporary mount namespace to a file
# within MOUNT_PARENT_PID's namespace to make it persistent
# nsenter will reference it later
$$ nsenter -t ${MOUNT_PARENT_PID} --mount \
mount --bind /proc/$$/ns/mnt "/run/mntns/${NSNAME}"
# Yes, here $MOUNT_PARENT_PID can be replaced by $PPID
# But if any intermediate sub-shells and forks get introduced
# then $PPID can point to a different process.
似乎某些版本的单个命令bash
调用 with优化了,并且这里确实需要 fork() ,因此强制它在命令末尾使用 fork() (请参阅开头的简短版本)。-c command
fork()
&& :
手动安装/etc/netns/${NSNAME}/*
最初的答案有这一部分,所以就在这里,尽管可能不是很有用。
重新创建 /mnt/netns/${NSNAME}/绑定安装*
使用的缺点unshare
是您无法获得/etc/netns/NETNS_NAME/*
提供的自动绑定安装ip netns exec ${NSNAME} cmd
,而手动添加并不难。
# either during unshare or later as nsenter.
# The important difference is here it is done once and result persists
# unlike with `ip netns exec` which does this every time
NSNAME="${NSNAME}" \
nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
/bin/sh -e -x -c \
'cd "/etc/netns/${NSNAME}"; for f in *; do mount --bind "/etc/netns/${NSNAME}/${f}" "/etc/${f}"; done;'