web-dev-qa-db-ja.com

ネストされたネットワーク名前空間を作成できません

ネットワーク名前空間からネットワーク名前空間を作成できないようです。 「エラー:ピアnetns参照が無効です。」という結果になります。

これはバグですか、それとも私が気付いていないような制限がありますか?

以下は、エラーのcmdトレースです。

# ip netns add foo1
# ip netns exec foo1 ip netns add foo2
# ip netns
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
foo2
foo1
# ip netns exec foo2 /bin/bash
setting the network namespace "foo2" failed: Invalid argument

2
user98651

TL; DR:奇妙なことに、これは実際にはnetwork名前空間の問題ではなく、mount名前空間の問題であり、予期されていることです。

すべての新しい「ip netns名前空間」を作成する必要があります(意味については後で参照)。つまり、すべてのip netns add ...コマンドを、ip netns exec ...で入力した「ip netns名前空間」内からではなく、最初の(ホスト)「ip netns名前空間」から実行します。 createしない限り、自由にswitchを自由に入れ替えて、ip netns exec ...を使用してコマンドを入れ子にすることができます。

次のステップバイステップの例を使用した詳細な説明...


ip netnsはネットワーク名前空間に特化していますが、すべての機能を処理するために、(少なくとも、私が知っている)2つの理由でマウント名前空間と混ざる必要があります。

  • 代替サービス/デーモン構成を管理するために/etc/netns/FOO/SOMESERVICE/etc/SOMESERVICEにバインドをバインド

    他のネットワーク名前空間でいくつかの(ネットワーク関連の)デーモンを簡単に実行するのに便利な機能ですが、これ以外にもまだ「ホスト」の一部です。 ULでの質問に対する私の回答をチェックできます: ip netns(iproute2)によるネームスペース管理 。以下の機能と同じ扱いが必要なため、これ以上は触れません。

  • 階層内の新しいネットワーク名前空間のネットワークデバイスを公開するための/sysの再マウント

    これは必須の機能です。問題を明らかにする例:

    「初期ホスト」から:

    # ip link add dev dummy9 type dummy
    # ip -br link show dummy9 
    dummy9           DOWN           f6:f6:48:9c:12:b9 <BROADCAST,NOARP> 
    # ls -l /sys/class/net/dummy9
    lrwxrwxrwx. 1 root root 0 Apr  4 22:09 /sys/class/net/dummy9 -> ../../devices/virtual/net/dummy9
    

    下位ツール を使用して、他の(一時的な)ネットワーク名前空間に変更します。

    # unshare --net ip -br link show dummy9 
    Device "dummy9" does not exist.
    # unshare --net ls -l /sys/class/net/dummy9
    lrwxrwxrwx. 1 root root 0 Apr  4 22:13 /sys/class/net/dummy9 -> ../../devices/virtual/net/dummy9
    

    それが問題です。/sysは、新しいネットワーク名前空間のインターフェイスではなく、初期のホストのインターフェイスを公開します。これは、ネットワーク名前空間と/sysのマウントとの相互作用がある場所です。/sysが新しいネットワーク名前空間からマウントされている場合、選択したディレクトリ階層(/sys/class/netおよび/sys/devices/virtual/netなど)で新しいネットワークインターフェイスを公開するように切り替わります。これは動的ではなく、マウント時にのみ行われます。一部の高度なネットワーク設定は、そこに読み取りまたは書き込みを行うだけで簡単に利用できるため、提供する必要があり、その逆も当てはまります。新しいネットワーク環境で実行されている分離されたプロセスは、初期ホストのインターフェースを表示または変更できません。

したがって、ip netns exec FOO ...ip netns add FOOは除く)は nsharing -mount名前空間によってこれを解決し、その内部に/sys/を再マウントして、初期ホストのネットワーク名前空間を中断しないようにします。ただし、重要なのは、このマウント名前空間自体が一時的なものであることです。2つのip netns exec FOO ...コマンドを個別に実行すると、同じマウント名前空間にはなりません。それらはそれぞれ独自のものを持っており、/sysが同じネットワーク名前空間を指すように再マウントされています。

今までは問題ありません。これが発生したときは、2つのタイプの名前空間が関係しているため、これを「ip netns名前空間」と呼びます。これまでのところ:

用語1:

# ip netns add FOO
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:28 /proc/1712/ns/mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Apr  4 22:28 /proc/1712/ns/net -> net:[4026531992]
# ip netns exec FOO bash
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1864/ns/mnt -> mnt:[4026532618]
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1864/ns/net -> net:[4026532520]

用語2:

# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:32 /proc/1761/ns/mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Apr  4 22:32 /proc/1761/ns/net -> net:[4026531992]
# ip netns exec FOO bash
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1866/ns/mnt -> mnt:[4026532821]
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1866/ns/net -> net:[4026532520]

Ip netns名前空間を変更した後、新しいネットワーク名前空間はterm1term2で同じであるが、新しいマウント名前空間は互いに(および初期ホストと)異なることに注意してください。 。

term1で新しいip netns名前空間を作成するとどうなりますか?どれどれ:

用語1:

# ip netns add BAR
# ip netns ls
BAR
FOO

用語2:

# ip netns ls
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
BAR
FOO

これは、プロセスなしで既存の名前空間BARが他の場合と同様にmounted(新しく作成された空のファイル)/var/run/netns/BARであるからです(もう一度、 前のリンク)を参照してください たとえば)。マウント名前空間は異なりますが、ルートディレクトリは同じです。つまり、初期ホストのルートです。したがって、もちろん、この新しく作成された空のファイル/var/run/netns/BARは、作成時にどこでも確認できます(初期、term1のマウントns、term2のマウントns)。

残念ながら、マウントはterm1のFOOのマウント名前空間で行われ、term1でのみ表示され、term2では表示されません。それ以外の場合は、マウントネームスペースが異なるためです。したがって、term1(のFOO ip netns名前空間)では、/var/run/netns/BARnsfs疑似ファイルシステムに属する疑似ファイルです。

用語1:

# stat -f -c %T /var/run/netns/BAR
nsfs

tmpfs(実際の/runマウントから)上の空のファイルです。

用語2:

# stat -f -c %T /var/run/netns/BAR
tmpfs

その他の端末:

$ stat -f -c %T /var/run/netns/BAR
tmpfs

現在の「ip netns名前空間」を終了しない限り、term1で引き続き表示されます。 term1からまだip netns名前空間を切り替える場合でも、新しい非共有の一時的なマウント名前空間は、すべてのマウントを含む以前のマウントのコピーであるため、問題ありません。

終了すると、そのマウントポイントは失われます(つまり、そのマウントポイントを使用しているプロセスまたはファイル記述子がない場合、BARの対応するネットワーク名前空間は、このマウントポイントによってのみ保持されていたため、表示されなくなります)。この後、ip netns lsコマンドはどこにでも文句を言うでしょう。古くて役に立たないファイル/run/netns/BARを削除するだけで修正できます。

この段階的な説明の後、覚えておくべきことは、現在ip netns addで入力されているネームスペース内にip netns execを持つcreate新しいネームスペースを使用してはならないということです。すべてを初期(ホスト)名前空間から作成する必要があります。その後、任意のip netns名前空間から自由に切り替えることができます。

もちろん、/var/run/netns/(つまり、マウントポイント/run)が(あいまいなままの)名前空間間で異なる場合、相互作用はなく、各ip netnsの呼び出しは他から隔離され、他の操作や相互作用は行われません。これは通常どこで起こりますか?フルコンテナでは、マウントとネットワークの両方の名前空間が分離され、最初から個別のリソースをポイントします。


[〜#〜] update [〜#〜]:コメントで質問されたように、この問題を「修復」する方法を確認しましたが、見つかりませんでした簡単な解決策。

最初に前提条件があります。上記のように、新しい "ip netns"名前空間BARがFOO内に作成され、FOOが残されると、BARへの唯一の参照が消えるため、BARも消えます。さらに何かが必要です。

実際には、 名前空間への参照 を保持する方法は3つあります。

  • プロセス:これがメインの方法であり、ほとんどの場合、名前空間はこのように使用されます
  • マウントポイント(これはip netnsで使用されるメソッドです):プロセスなしで名前空間を保持できます。内部にネットワーク設定(インターフェース、ブリッジ、tcルール、ファイアウォールルールなど)のみを持つ名前空間を作成できます。
  • オープンファイル記述子:まれに、名前空間を作成するときに使用されますが、ほとんど保持されません。ただし、アプリケーションが同時に複数の名前空間を扱い、簡単に参照できるようにファイル記述子を使用してスレッドの一部を切り替える場合を除きます。

1番目または3番目の方法を使用できます。動作するものを見つける前に失敗したさまざまな試みを次に示します...

前に言ったように、動作しません:

# ip netns add FOO
# ip netns exec FOO ip netns add BAR

first "ip netns"名前空間で一時的に実行しているプロセスをその一時的なmount名前空間部分に残すだけで、-newへの必要な参照を維持できます。 = "ip netns"名前空間のnetwork名前空間を作成し、後で(初期名前空間から)外部から再利用します。

どちらも機能しません:

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; sleep 999 < /var/run/netns/BAR & echo $!'
28344
# strace -e trace=readlink,mount mount --bind /proc/6295/fd/0 /var/run/netns/BAR
readlink("/proc/6295/fd/0", "/run/netns/BAR", 4095) = 14
readlink("/var/run", "/run", 4095)      = 4
mount("/run/netns/BAR", "/run/netns/BAR", 0x55c88c9cccb0, MS_BIND, NULL) = 0
+++ exited with 0 +++
# stat -f -c %T /run/netns/BAR
tmpfs

straceで見られるように、mountコマンドは、この使用例では必要ないときにシンボリックリンクをたどりました(注:マウントはまだスリーププロセスにリンクされているため、アンマウントするために強制終了する必要があります)それ)。

これ(sleepの入力mount名前空間にアクセスして、BARのマウントされたnetwork隠された名前空間にアクセスする)は機能しますが、sleepの継続的な存在に依存していますまたは継続使用のためのプロセス:

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; ip -n BAR link add dummy8 type dummy; sleep 999 & echo $!'
12916
# nsenter --target=12916 --mount ip -n -brief BAR link show
lo               DOWN           00:00:00:00:00:00 <LOOPBACK> 
dummy8           DOWN           8e:ce:b3:d1:9c:bb <BROADCAST,NOARP> 

奇妙なことに、これは(名前空間のマウントショートカット /proc/pid/root/ を使用)が機能しない(理由がわからない):

# stat -f -c %T /proc/12916/root/var/run/netns/BAR 
tmpfs

最後に何がうまくいくでしょう:

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; ip -n BAR link add dummy8 type dummy; ip netns exec BAR sh -c '\''sleep 999 & echo $!'\'
14124
# mount --bind /proc/14124/ns/net /var/run/netns/BAR
# ip -n BAR -brief link show
lo               DOWN           00:00:00:00:00:00 <LOOPBACK> 
dummy8           DOWN           3a:48:65:20:68:c1 <BROADCAST,NOARP> 

したがって、このようなものを最後に使用できます。 sleepコマンドが終了する前の直後に削除しようとすると、競合状態が発生する可能性があります。

# ip netns add FOO
# mount --bind /proc/$(ip netns exec FOO sh -c 'ip netns add BAR; ip netns exec BAR bash -c '\''sleep 5 </dev/null >/dev/null 2>&1 & echo $!; disown'\')/ns/net /var/run/netns/BAR

このような構成をどのように使用できますか?ネストされた「ip netns」の問題が発生する前の元の問題が示されていないため、私にはわかりません。 「ネストされたネットワーク名前空間」を作成することなく、より簡単なソリューションを利用できる場合があります。

3
A.B