web-dev-qa-db-ja.com

「匿名」ネットワーク名前空間内のvethデバイスを外部のvethデバイスに接続するにはどうすればよいですか?

unshareを呼び出して、それ自体が内部にある新しいネットワーク名前空間を作成するプロセスがあります。 execveを呼び出してbashを起動すると、ipコマンドはloデバイスしか持っていないことを示します。ユーザー名前空間も作成し、プロセスが名前空間内のルートになるように調整した場合、ipコマンドを使用してそのデバイスを起動し、機能します。

ipコマンドを使用して、この名前空間にvethデバイスを作成することもできます。しかし、それはip netns listには表示されず、新しいvethデバイスはルートレベルの名前空間に表示されません(予想通り)。ルートレベルの名前空間のvethデバイスをプロセス名前空間内の新しいvethデバイスに接続するにはどうすればよいですか? ipコマンドでは、名前空間にipコマンドで割り当てた名前を付ける必要があるようですが、ip netns addを使用して作成しなかったため、名前空間では必要ありません。

たぶん、netlinkデバイスを使用してセットアップを行う独自のプログラムを作成することで、それを行うことができたでしょう。しかし、私は本当にそうしたくないです。コマンドラインからこれを行う方法はありますか?

Dockerコンテナにも独自のネットワーク名前空間があり、その名前空間にも名前がないため、これを行う方法が必要です。それでも、内部にvethデバイスがあり、外部のvethデバイスに接続されています。

私の目標は、理想的にはコンテナーの外部でrootになる必要なしに、プロセス分離コンテキストを動的に作成することです。このために、PID名前空間、UID名前空間、ネットワーク名前空間、IPC名前空間、およびマウント名前空間を作成します。cgroup名前空間を作成することもできますが、これらは新しくて、現在サポートされているバージョンのSLES、RHEL、Ubuntu LTSで実行できる必要があります。

私は一度にこの名前空間を1つずつ処理してきましたが、現在、ユーザー、PID、マウントの名前空間は問題なく動作しています。

必要に応じて/proc/pid/ns/netをマウントできますが、ユーザーネームスペース内からマウントしたいので、(再度)ネームスペース外のrootである必要はありません。ほとんどの場合、名前空間のすべてのプロセスがなくなるとすぐに、すべてが消えるようにします。完了したときにファイルシステムをクリーンアップするためにたくさんの状態を持つことは、理想的とは言えません。コンテナが最初に割り当てられたときに一時的に作成し、すぐに削除する方が、コンテナの終了時にクリーンアップするよりもはるかに優れています。

いいえ、dockerlxcrkt、または他のものに依存しているような他の既存のソリューションは使用できませんbog標準のシステムユーティリティ(ipなど)、glibcなどのシステムライブラリ、およびLinuxシステムコール。

4
Omnifarious

ip link には名前空間オプションがあり、ネットワーク名前空間名に加えて、[〜#〜] pid [〜#〜]を使用してプロセスの名前空間を参照できます。 PID名前空間がプロセス間で共有されている場合は、どちらの方法でもデバイスを移動できます。 PID 1"外部"であると考えると、内部からおそらく最も簡単です。個別のPID名前空間を使用して、外側の(PID)名前空間から内側の名前空間に移動する必要があります。

たとえば、ネットワーク名前空間の内部から、vethデバイスのペアからPID 1の名前空間を作成できます。

ip link add veth0 type veth peer name veth0 netns 1

Linuxでの名前空間の仕組み

すべてのプロセスには、/proc/<pid>/ns/にそれらの名前空間の参照ファイルがあります。さらに、ip netns/run/netns/に永続的な参照ファイルを作成します。これらのファイルは setns システムコールで使用され、実行中のスレッドの名前空間をそのようなファイルが指す名前空間に変更します。

シェルから nsenter プログラムを使用して別の名前空間に入ることができ、引数に名前空間ファイル(パス)を提供します。

Linuxの名前空間の概要については、LWN.netの記事シリーズ Namespaces in operation の記事シリーズを参照してください。

名前空間の設定

複数の名前空間(mount、pid、user、など)を設定する場合は、mountおよびpid名前空間を変更する前に、できるだけ早くネットワーク名前空間を設定してください。 mountまたはpidの名前空間を共有していない場合、外部のネットワーク名前空間を参照しているファイルを見ることができないため、外部のネットワーク名前空間を指す方法はありません。

コマンドラインユーティリティが提供する以上の柔軟性が必要な場合は、システムコールを使用してプログラムから直接名前空間を管理する必要があります。ドキュメントについては、関連するmanページを参照してください: man 2 setnsman 2 unshare および man 7 namespaces

5
sebasth

vethは1組のデバイスで構成され、それぞれを通信するネットワーク名前空間(またはルート名前空間)に配置します。

これは、ルート名前空間からルートとして呼び出して新しいネットワーク名前空間を作成し、ルート名前空間とネットワーク名前空間の間にvethペアを設定するスクリプトです。最後の行は、その名前空間でxtermを開始します。必要に応じて調整します。

_#!/bin/bash
# Setup network namespace with veth pair, start xterm in it

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi

NS=${1:-ns0}
DEV=${2:-veth0}
DEV_A=${DEV}a
DEV_B=${DEV}b
ADDR=${3-:10.0.0}
ADDR_A=${ADDR}.254
ADDR_B=${ADDR}.1
MASK=${5:-24}
COL=${4:-yellow}

# echo ns=$NS dev=$DEV col=$COL mask=$MASK

ip netns add $NS
ip link add $DEV_A type veth peer name $DEV_B netns $NS
ip addr add $ADDR_A/$MASK dev $DEV_A
ip link set ${DEV}a up
ip netns exec $NS ip addr add $ADDR_B/$MASK dev $DEV_B
ip netns exec $NS ip link set ${DEV}b up
ip netns exec $NS ip route add default via $ADDR_A dev $DEV_B
ip netns exec $NS su -c "xterm -bg $COL &" your_user_id
_

あなたも使うことができます

_ip link set name_of_if netns name_of_ns
_

ネットワーク名前空間間でネットワークインターフェイス(物理デバイスへのインターフェイスを含む)を移動する。

編集

私はそれをテストしました。新しい名前空間withinからペアを作成し、1つのエンドポイントをルート名前空間に配置することもできます。トリックは、ルート名前空間には明らかに名前がないが、ID _1_としてアクセスできることです。

_Sudo ip link add veth1b type veth peer name veth1a netns 1
_

unshareでどのように機能するかはよくわかりませんが、新しく作成されたネットワーク名前空間を_/proc/<pid>/ns/<type>_でまだ見つけることができると思います。名前がない場合は、少なくとも数値IDが必要です。 _ip netns list_も役立ちます。そして、これらすべては、ipを使用する代わりに、システムコールでも実行できると思います。 straceまたはltraceは、どれかを判別するのに役立ちます。

編集

_man namespaces 7_をざっと見てみました。 _/proc_から名前空間を理解することは十分に関与しているように思われ(ファイル記述子しかない)、おそらく_ip netns add_で名前空間を作成し、その代わりに_ip netns exec_でプログラムを開始する方が良いでしょう。 unshare。あなたがonlyに新しいネットワーク名前空間が必要であり、それ以外のものは必要ないと仮定します。

1
dirkt