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である必要はありません。ほとんどの場合、名前空間のすべてのプロセスがなくなるとすぐに、すべてが消えるようにします。完了したときにファイルシステムをクリーンアップするためにたくさんの状態を持つことは、理想的とは言えません。コンテナが最初に割り当てられたときに一時的に作成し、すぐに削除する方が、コンテナの終了時にクリーンアップするよりもはるかに優れています。
いいえ、docker、lxc、rkt、または他のものに依存しているような他の既存のソリューションは使用できませんbog標準のシステムユーティリティ(ipなど)、glibcなどのシステムライブラリ、およびLinuxシステムコール。
ip link
には名前空間オプションがあり、ネットワーク名前空間名に加えて、[〜#〜] pid [〜#〜]を使用してプロセスの名前空間を参照できます。 PID名前空間がプロセス間で共有されている場合は、どちらの方法でもデバイスを移動できます。 PID 1が"外部"であると考えると、内部からおそらく最も簡単です。個別のPID名前空間を使用して、外側の(PID)名前空間から内側の名前空間に移動する必要があります。
たとえば、ネットワーク名前空間の内部から、vethデバイスのペアからPID 1の名前空間を作成できます。
ip link add veth0 type veth peer name veth0 netns 1
すべてのプロセスには、/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 setns
、 man 2 unshare
および man 7 namespaces
。
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に新しいネットワーク名前空間が必要であり、それ以外のものは必要ないと仮定します。