
Демон Strongswan помещает свои файлы .pid и .ctl в /var/run, чтобы определить, запущен ли он уже.
Я хочу запустить несколько таких демонов на одной машине в разных сетевых пространствах имен. Я пытаюсь добиться этого, привязав монтирование разных каталогов (например, /etc/namespace1 к /var/run пространства имен1 и /etc/namespace2 к /var/run пространства имен2). /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
Простым решением было бы указать каждому экземпляру strongswan использовать другой каталог для хранения PID-файла, установив правильное значениеIPSEC_PIDDIR
переменная окружения в вашем скрипте запуска и остановки.
решение2
ip netns exec
уже связывает монтирования /etc/netns/<netns name>/*
по соответствующему файлу/каталогу в /etc
. Таким образом, вы можете скомпилировать strongSwan с помощью eg --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
Более подробную информацию можно найти наstrongSwan вики.
решение3
Насколько мне известно, причина проблемы
ip netns add ${NSNAME}
создает постоянное пространство имен, монтируя его в /run/netns/${NSNAME}
. Это само по себе пока не подразумевает монтирование пространств имен.
Делание ip netns exec ${NSNAME} cmd
порождаетвременныйmount namespace, который существует до cmd
выхода, после этого mount namespace очищается, остается только network namespace. Это необходимо для достижения магического монтирования /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. Создание сетевых и монтируемых постоянных пространств имен
2а. Метод А, простой, без магических привязок.
Это создает постоянные пространства имен mount+network. Это просто, но не создает магических связываемых монтирований для /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
2б. Метод 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
например с помощью команд ОП:
# 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=...
! If 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}"
Объяснение
Извините за длинный текст. Это отчасти для моей же пользы.
Эта команда из шага2бвышеизложенное заслуживает некоторого пояснения.
Снова команда.
$ 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) даже после завершения программы (за исключением пространств имен PID, где требуется постоянно работающий процесс init). Когда постоянное пространство имен больше не нужно, его можно отменить с помощью umount(8).
Начало объяснения
Вот что это делает, если разбить на простые шаги. Обратите внимание, для этой демонстрации требуются две оболочки.
# 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()
покинет и не уничтожит временное пространство имен, а скорее вызовет fork() , запустив промежуточную оболочку, которая сохраняет временное пространство имен активным, а разветвленная does 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
invoked with -c command
для одной команды оптимизируют fork()
и этот fork() здесь действительно необходим, поэтому принудительно вызовите fork() with && :
в конце команды (см. краткую версию в начале).
Монтаж вручную/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;'