nsenter コマンドは、指定されたプロセスのコマンド空間で指定されたプログラムを実行できるコマンドです。これは util-linux パッケージにあります。
使用
最も一般的な使用法の 1 つは、コンテナーのネットワーク コマンド スペースにアクセスすることです。かなりの数のコンテナには、軽量化のために、ip address
、ping
、telnet
、ss
、tcpdump
およびその他のコマンドなどの基本的なコマンドが含まれていません。これにより、コンテナ ネットワークのデバッグに多大な問題が生じます。 docker inspect ContainerID
コンテナ IP はコマンドを通じてのみ取得できます。他のネットワークとの接続をテストします。現時点では、nsenter コマンドを使用してコンテナーのネットワーク名前空間に入力することのみが可能で、ホストのコマンドを使用してコンテナー ネットワークをデバッグできます。
さらに、nsenter はmnt
、uts
、 、ipc
、pid
、user
コマンド スペースを入力して、ルート ディレクトリと作業ディレクトリを指定することもできます。
使用
まず、nsenter コマンドの構文を確認してください。
nsenter [options] [program [arguments]]
options:
-t, --target pid:指定被进入命名空间的目标进程的pid
-m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
-u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
-i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
-n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
-p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
-U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
-G, --setgid gid:设置运行程序的gid
-S, --setuid uid:设置运行程序的uid
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录
如果没有给出program,则默认执行$SHELL。
例:
nginx コンテナを実行し、コンテナの pid を確認します。
[root@staight ~]# docker inspect -f { {.State.Pid}} nginx
5645
次に、nsenter コマンドを使用して、コンテナーのネットワーク名前空間を入力します。
[root@staight ~]# nsenter -n -t5645
[root@staight ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
正常に入力されました~
Kubernetes では、コンテナーの PID を取得する前に、コンテナーの ID を取得する必要があります。次のコマンドを使用して取得できます。
[root@node1 test]# kubectl get pod test -oyaml|grep containerID
- containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
または、containerID をより正確に取得します。
[root@node1 test]# kubectl get pod test -o template --template='{ {range .status.containerStatuses}}{ {.containerID}}{ {end}}'
docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
原理
名前空間
ネームスペースは、Linux の一部のプロセスの属性のスコープであり、ネームスペースを使用すると、さまざまなプロセスを分離できます。
Linux は継続的に名前空間を追加しており、現在は次のとおりです。
-
mount : Linux 2.4.19 以降、プロセスが独立したマウントされたファイル システムを持つように名前空間をマウントします。
-
ipc : ipc 名前空間。Linux 2.6.19 以降、プロセスはメッセージ キュー、共有メモリ、セマフォを含む独立した ipc を持ちます。
-
uts : uts 名前空間。Linux 2.6.19 以降、プロセスが独立したホスト名とドメイン名を持つようになります。
-
net : ネットワーク コマンド スペース。Linux 2.6.24 以降、プロセスが独立したネットワーク スタックを持つようになります。
-
pid : pid 名前空間。Linux 2.6.24 以降、プロセスが独立した pid 空間を持つようになります。
-
user : user 名前空間。これは、プロセスが Linux 2.6.23 から始まり Linux 3.8 で終わる独立したユーザー空間を持つことを意味します。
-
cgroup : cgroup 名前空間。Linux 4.6 以降、プロセスに独立した cgroup 制御グループが存在します。
Linux の各プロセスには名前空間があり、/proc/PID/ns ディレクトリで名前空間のファイル記述子を確認できます。
[root@staight ns]# pwd
/proc/1/ns
[root@staight ns]# ll
total 0
lrwxrwxrwx 1 root root 0 Sep 23 19:53 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 uts -> uts:[4026531838]
クローン
clone は、新しいプロセスを作成するために使用される Linux システム コール関数です。
クローンはフォークに似ていますが、より洗練されたもので、例えば、クローンで作成された子プロセスは、親プロセスの仮想アドレス空間、ファイル記述子テーブル、信号処理テーブルなどを共有できます。ただし、クローン関数は新しいプロセスの名前空間も指定できることをここで強調しておく必要があります。
クローンの構文:
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, void *newtls, pid_t *ctid */ );
その中で、フラグは次のような名前空間を指定できます。
-
CLONE_NEWCGROUP:cgroup
-
CLONE_NEWIPC:ipc
-
CLONE_NEWNET:ネット
-
CLONE_NEWNS:マウント
-
CLONE_NEWPID:pid
-
CLONE_NEWUSER:ユーザー
-
CLONE_NEWUTS:uts
使用例:
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
セット
clone は新しいコマンド空間を作成するために使用され、setns は現在のスレッド (単一スレッドまたはプロセス) が名前空間に参加できるようにするために使用されます。
文法:
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>
int setns(int fd, int nstype);
fd参数是一个指向一个命名空间的文件描述符,位于/proc/PID/ns/目录。
nstype指定了允许进入的命名空间,一般可设置为0,表示允许进入所有命名空间。
したがって、この関数の使用法は次のようになります。
-
setns 関数を呼び出します。スレッドの名前空間を指定します。
-
execvp 関数を呼び出します。指定されたパスのプログラムを実行し、子プロセスを作成し、親プロセスを置き換えます。
このようにして、新しいプログラムを実行するための名前空間を指定できます。
コード例:
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int
main(int argc, char *argv[])
{
int fd;
if (argc < 3) {
fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY); /* Get file descriptor for namespace */
if (fd == -1)
errExit("open");
if (setns(fd, 0) == -1) /* Join that namespace */
errExit("setns");
execvp(argv[2], &argv[2]); /* Execute a command in namespace */
errExit("execvp");
}
使用例:
./ns_exec /proc/3550/ns/uts /bin/bash
ンスター
次に、最後は nsenter です。nsenter は、setns サンプル プログラムの最上位のカプセル化層に相当します。そのため、名前空間のファイル記述子を指定する必要はなく、プロセス番号を指定するだけで済みます。
プロセス番号 PID と入力する必要がある名前空間を指定した後、nsenter は対応する名前空間ファイル記述子 /proc/PID/ns/FD を見つけ、その名前空間を使用して新しいプログラムを実行します。
参照文書
-
コンテナ内のパケットをキャプチャしてネットワークの問題を特定する: https://tencentcloudcontainerteam.github.io/tke-handbook/skill/capture-packets-in-container.html
-
man-page:nsenter:http://www.man7.org/linux/man-pages/man1/nsenter.1.html#top_of_page
-
man-page:クローン:http://www.man7.org/linux/man-pages/man2/clone.2.html
-
man-page:setns:http://www.man7.org/linux/man-pages/man2/setns.2.html