🔸 背景知识
在Linux中,namespace是容器技术的基础。它隔离了系统资源,比如进程、网络、挂载点等。UTS namespace是最基础的命名空间之一,主要用于隔离hostname和domainname。
🔸 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命名空间
输出会列出所有当前系统中的UTS命名空间,例如:
1
2
| NS TYPE NPROCS PID USER COMMAND
4026531838 uts 76 1101 gc /lib/systemd/systemd --user
|
其中:
NS是namespace的inode号;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命名空间中,可以设置独立的hostname和domainname:
1
2
| $ hostname
$ domainname
|
如果你进入了某个容器或namespace后,这两个值不同于宿主机,那说明当前shell已处于不同的UTS命名空间中。