
Der Strongswan-Daemon legt seine .pid- und .ctl-Dateien in /var/run ab, um festzustellen, ob er bereits ausgeführt wird.
Ich möchte mehrere dieser Daemons auf derselben Maschine in unterschiedlichen Netzwerk-Namespaces ausführen. Dies versuche ich zu erreichen, indem ich verschiedene Verzeichnisse binde (sagen wir /etc/namespace1 an /var/run von namespace1 und /etc/namespace2 an /var/run von namespace2). /var/run ist ein symbolischer Link zu /run, also binde ich es wie unten beschrieben an /run.
Ich kann das fast so erreichen:
""Im Standard-Namespace""
$:~ sudo echo "red" >> /etc/red/run/pidfile
$:~ sudo echo "blue" >> /etc/blue/run/pidfile
$:~ sudo ip netns exec red
„Im roten Namensraum“
$:~ mount --bind /etc/red/run/ /run/
$:~ cat /var/run/pidfile
Rot
„Im blauen Namensraum“
$:~ mount --bind /etc/blue/run/ /run/
$:~ cat /var/run/pidfile
Blau
Das funktioniert also einwandfrei. Auf diese Weise wird der Daemon, wenn er /var/run/charon.pid innerhalb von Rot erstellt, nicht mit /var/run/charon.pid im blauen Namespace verwechselt und es können zwei Instanzen gestartet werden.
Hier ist jedoch das Problem: Wenn ich den roten Namespace „verlasse“ und ihn dann über „ip netns exec red bash“ erneut betrete, ist die Einbindung nicht mehr vorhanden. Das heißt, es gibt überhaupt kein /var/run/redfile.
Die Frage ist also, wie ich das festhalten kann. Muss ich /etc/fstab ändern? Aber es funktioniert nicht. Auf Nachfrage kann ich Einzelheiten dazu angeben, warum „es nicht funktioniert“.
Ich bin ratlos. Wäre für jede Hilfe dankbar.
Danke!
Antwort1
Die einfache Lösung wäre, jede Instanz von strongswan anzuweisen, ein anderes Verzeichnis zum Speichern der PID-Datei zu verwenden, indem der korrekte Wert desIPSEC_PIDDIR
Umgebungsvariable in Ihrem Start- und Stoppskript.
Antwort2
ip netns exec
Bind-Mounts werden bereits /etc/netns/<netns name>/*
über die entsprechende Datei/das entsprechende Verzeichnis in bereitgestellt /etc
. Sie können strongSwan also beispielsweise mit kompilieren --with-piddir=/etc/ipsec.d/run
und dann die erforderlichen Verzeichnisse erstellen, sodass jede Instanz ihre PID-Dateien in separaten Verzeichnissen erstellt:
# 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
Weitere Einzelheiten finden Sie auf derstrongSwan-Wiki.
Antwort3
Problemursache Soweit ich weiß
ip netns add ${NSNAME}
erstellt einen persistenten Namespace, indem er an gemountet wird /run/netns/${NSNAME}
. Dies selbst hat noch keine Auswirkungen auf Mount-Namespaces.
Das erzeugt ip netns exec ${NSNAME} cmd
einvorübergehendDer Mount-Namespace, der bis existiert cmd
, wird beendet. Danach wird der Mount-Namespace bereinigt, nur der Netzwerk-Namespace bleibt übrig. Dies ist erforderlich, um das magische Mounten von zu erreichen /etc/netns/${NSNAME}/*
. Leider werden auch alle von durchgeführten Mounts cmd
bereinigt.
Aus man ip-netns
:
ip netns exec
automatisiert die Handhabung dieser Konfiguration, Dateikonvention für Anwendungen, die den Netzwerk-Namespace nicht kennen, durch die Erstellung eines Mount-Namespace und das Bind-Mounten aller Konfigurationsdateien pro Netzwerk-Namespace an ihrem traditionellen Speicherort in /etc.
Eine Lösung
Kurzfassung
# 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
Lange Version
Es ist möglich, sowohl Netzwerk- als auch Mount-Namespaces dauerhaft zu erstellen.
Dies ist größtenteils den Beispielen auf der unshare
Manpage entnommen:http://man7.org/linux/man-pages/man1/unshare.1.html
ip netns exec
Die wichtigste Folge ist, dass stattdessen nsenter
jetzt sowohl der Netzwerk- als auch der Mount-Namespace verwendet werden müssen, zumindest dort, wo Mounts ohnehin eine Rolle spielen.
Schritt 1. Vorbereiten. Verzeichnis für persistente Mount-Namespaces erstellen
Dies muss einmal durchgeführt werden, z. B. nach dem Booten, NICHT für jeden Namespace. Der Pfad hier ist beliebig. Ich versuche, eine ähnliche Benennung zu verwenden wie 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
Beachten Sie, dass sie mkdir ... && mount ...
nicht atomar sind und dass ein Race Condition auftreten kann, wenn mehrere Dienste gleichzeitig gestartet werden und diese Sequenz ausführen.
Schritt 2. Erstellen Sie persistente Netzwerk- und Mount-Namespaces
2a. Methode A, einfach, keine magischen Bindungshalterungen.
Dadurch werden persistente Mount+Netzwerk-Namespaces erstellt. Es ist einfach, erstellt aber keine magischen Bind-Mounts für /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. Methode B, Hebelwirkung ip netns exec
zum Erstellen von Mounts, aber dauerhaft.
Um diese Bind-Mounts durchzuführen, ip netns exec ...
sie aber dauerhaft zu machen, können Sie das Setup wie folgt durchführen. Beachten Sie, dass dies NUR einmal beim Erstellen des Namespaces durchgeführt werden muss, nicht jedes Mal.
$ 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}' && :"
Einen Erklärungsversuch finden Sie gegen Ende.
Schritte 3. Verwenden Sie es
Jetzt nsenter
muss verwendet werden, um Befehle in beiden Namespaces nach Bedarf zu starten, um dauerhafte Mount-Ergebnisse zu erzielen. Dies gilt unabhängig davon, ob das Setup mit unshare
oder durchgeführt wurde ip netns exec NAME sh ... nsneter ... mount ...
.
# Get a shell inside the namespaces
$ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
/bin/bash
zB mit den Befehlen des 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/'
Wichtig
Dieser Ansatz funktioniert, aber anstatt use ip netns exec
! nsenter --net=... --mount=...
zu ip netns exec ...
verwenden, wird (für die Dauer der Ausführung) der Mount-Namespace ersetzt, was für Befehle in Ordnung sein kann, die sich nicht um die Persistenz des Mounts kümmern, z. B.
# This does not touch any files, only operates on network device
ip netns exec ${NSNAME} ip link set up dev lo
Schritt Z. - Aufräumen
Unabhängig davon, welche der beiden oben genannten Methoden zum Erstellen der Namespaces verwendet wurde, kann die Bereinigung mit einer der beiden Methoden durchgeführt werden:
# 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}"
oder
# Unmount and delete both namespaces' holders
umount "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}" \
&& rm "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}"
Erläuterung
Entschuldigen Sie den langen Text. Er ist zum Teil zu meinem eigenen Nutzen.
Dieser Befehl aus Schritt2boben bedarf einer Erklärung.
Nochmal der Befehl.
$ 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}' && :"
Ausman unshare
Die Namespaces können optional persistent gemacht werden, indem /proc/pid/ns/type-Dateien an einen Dateisystempfad gebunden und mit nsenter(1) auch nach Beendigung des Programms betreten werden (außer PID-Namespaces, bei denen ein permanent laufender Init-Prozess erforderlich ist). Sobald ein persistenter Namespace nicht mehr benötigt wird, kann er mit umount(8) depersistent gemacht werden.
Erläuterungsbeginn
Hier ist, was es bewirkt, wenn es in einfache Schritte unterteilt wird. Beachten Sie, dass für diese Demo zwei Shells erforderlich sind.
# 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
Jetzt sind beide Netzwerk- und Mount-Namespaces persistent und können wie zuvor gezeigt erneut aufgerufen werden .
Der wichtige Teil ist das Einhängen ip netns exec
von /proc/pid/ns/net
in den Mount-Namespace der äußeren Shell.Vor ip netns exec..
Ausgänge.
Erläuterung (Fortsetzung)
Die Antwort lautet also: von innen heraus ip netns exec ...
do nsenter
, aber nicht als direkter Befehl , weil das ohnehin den temporären Namespace verlassen und zerstören würde ip netns exec ${NSNAME} nsenter ...
exec()
, fork()
sondern vielmehr ein fork() auslösen, indem eine Zwischenshell ausgeführt wird, die den temporären Namespace aktiv hält, und das geforkte nsenter
do mount
. Das Folgende kommt der Funktionsweise des einen langen Befehls näher.
# 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.
Es scheint, dass einige Versionen von „, bash
die mit -c command
für einen einzelnen Befehl aufgerufen werden“, dies optimieren fork()
und dass fork() hier wirklich benötigt wird. Erzwingen Sie daher „fork()“ mit && :
am Ende des Befehls (siehe Kurzversion am Anfang).
Manuelle Montage/etc/netns/${NSNAME}/*
Die ursprüngliche Antwort enthielt diesen Abschnitt, also ist er hier, obwohl er wahrscheinlich nicht sehr nützlich ist.
/mnt/netns/${NSNAME}/ wird neu erstelltHalterungen binden*
Der Nachteil bei der Verwendung unshare
besteht darin, dass Sie nicht die automatische Bind-Montage von erhalten , /etc/netns/NETNS_NAME/*
die von bereitgestellt wird ip netns exec ${NSNAME} cmd
und die manuell problemlos hinzugefügt werden kann.
# 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;'