解決策

解決策

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

したがって、これは正常に動作します。この方法では、デーモンが red 内で /var/run/charon.pid を作成するときに、blue 名前空間の /var/run/charon.pid と混同せず、2 つのインスタンスが起動する可能性があります。

しかし、ここに問題があります。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 をコンパイルして--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. 準備。永続マウント名前空間のディレクトリを作成する

これは、名前空間ごとにではなく、たとえば起動後に 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 ...、次のように設定します。これは毎回ではなく、名前空間を作成するときに 1 回だけ実行する必要があることに注意してください。

    $ 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永続的なマウント結果を得るために、必要に応じて両方の名前空間内でコマンドを起動するために を使用する必要があります。これは、セットアップが または で行われたかどうかには関係ありませunshareip 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を使用する代わりに、を使用すると、マウント名前空間が置き換えられます (実行中)。これは、マウントの永続性を気にしないコマンドでは問題ありません。例: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 - クリーンアップ

上記の 2 つの方法のどちらを使用して名前空間を作成したかに関係なく、クリーンアップは次の 2 つの方法のいずれかで実行できます。

    # 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) で永続化を解除できます。

説明開始

簡単な手順に分解すると、次のようになります。このデモには 2 つのシェルが必要であることに注意してください。

    # 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() を引き起こし、フォークされた が を行うからですnsentermount次の例は、1 つの長いコマンドの動作に近いです。

    # 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で を呼び出して を使用するバージョンの中には を最適化して を削除してしまうものもあるようですが、ここでは fork() が本当に必要なので、コマンドの最後に を使用するように強制します (冒頭の短縮版を参照)。-c commandfork()&& :

手動でマウントする/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;'

関連情報