一個辦法

一個辦法

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 execnsenter

步驟 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 execuse 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 使臨時名稱空間保持活動狀態,並且分叉nsentermount。下面的內容更接近一長命令的工作方式。

    # 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 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;'

相關內容