Post

Linux命名空间【UTS】

🔸 背景知识

Linux中,namespace是容器技术的基础。它隔离了系统资源,比如进程、网络、挂载点等。UTS namespace是最基础的命名空间之一,主要用于隔离hostnamedomainname

🔸 CLONE_NEWUTS作用

  • 允许进程在新的UTS命名空间中运行。
  • 改变主机名sethostname()只影响当前命名空间。
  • 常用于容器技术(如Docker)中,让容器显示不同的主机名。

🔸 系统调用关系图

1
2
clone(CLONE_NEWUTS, ...) ──► 创建新的 UTS 命名空间
                         └──► sethostname()仅影响该空间

🔸 代码示例

这个例子展示如何创建一个带有独立主机名的子进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#define STACK_SIZE (1024 * 1024)

static int child_func(void *arg) {
  printf("==> [child] 当前主机名:\n");
  char hostname[100];
  gethostname(hostname, sizeof(hostname));
  printf("    %s\n", hostname);

  // 设置新的主机名
  const char *new_hostname = "child-uts";
  sethostname(new_hostname, strlen(new_hostname));
  printf("==> [child] 修改后的主机名:\n");
  gethostname(hostname, sizeof(hostname));
  printf("    %s\n", hostname);

  // 保持一段时间便于观察
  sleep(10);
  return 0;
}

int main() {
  char *stack = malloc(STACK_SIZE);
  if (!stack) {
    perror("malloc");
    exit(1);
  }

  printf("==> [parent] 当前主机名:\n");
  char hostname[100];
  gethostname(hostname, sizeof(hostname));
  printf("    %s\n", hostname);

  pid_t pid = clone(child_func, stack + STACK_SIZE, CLONE_NEWUTS | SIGCHLD, NULL);
  
  if (pid == -1) {
    perror("clone");
    exit(1);
  }

  waitpid(pid, NULL, 0);
  printf("==> [parent] 子进程结束,主机名仍为:\n");
  gethostname(hostname, sizeof(hostname));
  printf("    %s\n", hostname);

  free(stack);
  return 0;
}

🔸 编译和运行方式(需root权限)

1
2
$ gcc -o uts_ns uts_ns.c
$ sudo ./uts_ns

🔸 运行结果

1
2
3
4
5
6
7
8
==> [parent] 当前主机名:
    gc
==> [child] 当前主机名:
    gc
==> [child] 修改后的主机名:
    child-uts
==> [parent] 子进程结束,主机名仍为:
    gc

说明: child 改变了自己的主机名,但不影响parent。这就是CLONE_NEWUTS的作用。

📌 总结

项目说明
名称空间UTS namespace
标志CLONE_NEWUTS
能力隔离主机名与域名
使用场景容器(如Docker)、sandbox
编程接口clone() + sethostname()
权限需要CAP_SYS_ADMIN权限

🔹 使用lsns命令查看所有UTS命名空间

1
$ lsns -t uts

输出会列出所有当前系统中的UTS命名空间,例如:

1
2
        NS TYPE NPROCS   PID USER COMMAND
4026531838 uts      76  1101 gc   /lib/systemd/systemd --user

其中:

  • NSnamespaceinode号;
  • NPROCS是使用该namespace的进程数量;
  • PID是最早进入该namespace的进程;
  • COMMAND是启动该进程的命令。

🔹 查看某个进程的UTS命名空间

1
$ ls -l /proc/<pid>/ns/uts

例如:

1
$ ls -l /proc/1234/ns/uts

输出:

1
$ lrwxrwxrwx 1 root root 0 Jul 30 09:00 /proc/1234/ns/uts -> 'uts:[4026532249]'

🔹 对比两个进程的UTS命名空间是否相同

1
2
$ readlink /proc/1234/ns/uts
$ readlink /proc/5678/ns/uts

如果两个输出结果一样,则它们在同一个UTS命名空间中;否则为不同命名空间。

🔹 查看hostname是否被隔离

在不同UTS命名空间中,可以设置独立的hostnamedomainname

1
2
$ hostname
$ domainname

如果你进入了某个容器或namespace后,这两个值不同于宿主机,那说明当前shell已处于不同的UTS命名空间中。

This post is licensed under CC BY 4.0 by the author.