方法1

方法1

/proc/net/stat他の名前空間からアプリケーションにアクセスできるようにする方法はありますか?

明らかなのは、アプリケーション(つまりプロセス)を対応するnetnsに配置することです。しかし、私が念頭に置いているのは、アプリケーションが統計を監視し、/proc/net/statそれをネットワーク経由でデータベースに渡す必要があるということです。しかし、データベースは単なるパスです。デフォルトの名前空間で可能です。

似たような道があると期待していましたが、そうでは/proc/namespace-root/foo/net/statありませんでした。

また、他の名前空間の任意のPIDに依存します/proc/$somePID/ns/net

ベストアンサー1

プロセスに異なるネットワーク名前空間を提供します。

$ ps aux | grep '[s]leep'
root      716080  0.4  0.0   2292   748 ?        Ss   19:09   0:00 sleep 24h

$ sudo ls -l /proc/$$/ns/net /proc/716080/ns/net
lrwxrwxrwx 1 user    group   0 Jul 14 19:11 /proc/715845/ns/net -> 'net:[4026531992]'
lrwxrwxrwx 1 root    root    0 Jul 14 19:09 /proc/716080/ns/net -> 'net:[4026532200]'

方法1

私はそれが何であるかわかりません/proc/net/stats。私はそれを持っていません。だから/proc/net/stat/nf_conntrack代わりにこの例を使いましょう。デフォルトの名前空間のファイルを見ると、次のようになります。

$ cat /proc/net/stat/nf_conntrack
entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart
00000001  00000000 00000000 00000000 00000000 000000b8 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
00000001  00000000 00000000 00000000 00000002 00000087 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000

このnsenterコマンドを使用して、さまざまな名前空間でコマンドを実行できます。ここでは、catターゲットプロセスのネットワークネームスペースで実行できます。

$ sudo nsenter --net=/proc/716080/ns/net cat /proc/net/stat/nf_conntrack
entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart
00000000  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
00000000  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000

詳しく見ると、値が異なることがわかります。nsenter使用される結果は、ターゲットプロセスのネットワーク名前空間にあるprocファイルの内容です。

方法2

OPは、指標収集アプリケーションの文脈で機能するソリューションを探しています。目的の結果が得られる次のサンプルアプリケーションを設定しました。

#define _GNU_SOURCE
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
        return 1;
    }

    int pipe_fds[2] = {};

    if (pipe(pipe_fds) < 0) {
        perror("pipe");
        return 2;
    }

    const pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 3;
    }

    if (pid == 0) { // child
        char file_path[PATH_MAX];

        if (dup2(pipe_fds[1], STDOUT_FILENO) < 0) {
            perror("dup2");
            return 4;
        }
        close(pipe_fds[0]);
        close(pipe_fds[1]);

        snprintf(file_path, sizeof(file_path) - 1, "/proc/%s/ns/net", argv[1]);

        const int fd = open(file_path, O_RDONLY);
        if (fd < 0) {
            perror("open");
            return 5;
        }

        if (setns(fd, CLONE_NEWNET) < 0) {
            perror("setns");
            return 6;
        }


        FILE* const proc_file = fopen("/proc/net/stat/nf_conntrack", "r");
        if (proc_file == NULL) {
            fprintf(stderr, "fopen failed\n");
            return 7;
        }


        char* line = NULL;
        size_t line_len = 0;
        while (getline(&line, &line_len, proc_file) != -1) {
            printf("%s", line);
        }

        free(line);
        fclose(proc_file);

        return 0; // Child process is done
    }

    // parent
    if (dup2(pipe_fds[0], STDIN_FILENO) < 0) {
        perror("dup2");
        return 8;
    }
    close(pipe_fds[0]);
    close(pipe_fds[1]);

    char* line = NULL;
    size_t line_len = 0;

    while (getline(&line, &line_len, stdin) != -1) {
        printf("%s", line);
    }

    free(line);

    // Clean up our dead child
    wait(NULL);

    return 0;
}

アプリケーションはデフォルトのネットワーク名前空間から起動されます。これには、1つのコマンドライン引数(ターゲットネットワークネームスペース内のプロセスのPID)が必要です。

プログラムはパイプを作成して分岐します。サブプロセスは標準出力をパイプの書き込み端に接続します。親は標準入力をパイプの読み取り端に接続します。

子プロセスはprocファイルを使用してターゲットプロセスのネットワークネームスペースを開き、システムコールを使用してsetns()そのネットワークネームスペースをターゲットプロセスのネットワークネームスペースに切り替えます。その後、子プロセスは/procファイルを開き、1行ずつ読み込み、結果を標準出力(ここではパイプ)に書き込みます。

親は標準入力(パイプ)から行を読み取り、この行を標準出力に書き込みます。

ここで、親プロセスはメトリック収集アプリケーションの役割を果たすことができます。デフォルトのネットワーク名前空間に残り、読み取り値を渡すために、デフォルトのネットワーク名前空間のコンテキストで一部のリモートネットワークホストに接続できます。

- ベースのアプローチはfork()唯一のオプションではなく、単に私が使用する方法です。

プログラムの実行:

$ sudo ./a.out 716080
entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart
00000000  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
00000000  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
$

おすすめ記事