登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux unshare 怎样只隔离 UTS 命名空间

来源:17golang原创

时间:2026-11-08 03:54:20 232浏览 收藏

想只让一个 Linux shell 使用不同的主机名,可以用 unshare -u 创建 UTS(UNIX Timesharing System)命名空间。它隔离的是 hostname 和 domainname 视图:新 shell 里修改主机名,不会直接改掉外部 shell 看到的主机名。需要注意,UTS 隔离不等于完整容器,文件系统、进程列表和网络仍然可能与外部环境共享。

参考手册:https://man7.org/linux/man-pages/man1/unshare.1.html

最小做法是用 unshare -u 启动一个子 shell,再在子 shell 内运行 hostname 修改名称;如果当前用户没有创建 UTS 命名空间所需的能力,就把 --user --map-root-user 一起使用,并把它当成一次隔离实验,而不是安全容器。

UTS 命名空间究竟隔离了什么

Linux 的 UTS 命名空间保存了进程看到的主机名和域名。unshare 会创建新命名空间,然后执行指定程序;如果不写程序,通常会启动当前 shell。新命名空间只要仍有成员进程就存在,shell 退出后,临时命名空间也随之结束。

下面的结构图把边界画成两个视图:外部 shell 继续看到原来的主机名,进入新 UTS 命名空间的 shell 看到另一个名称。图中没有表示文件、进程或网络隔离,因为 -u 不会自动创建这些 namespace。

宿主 shell 与独立 UTS 命名空间之间的主机名视图隔离结构图
图1:UTS 命名空间把 hostname 视图隔离在新进程组内;这是静态结构图,不是运行截图。

用 unshare -u 启动只改主机名的 shell

如果当前账号已经具备创建 UTS 命名空间的权限,可以先用一个最小命令启动子 shell。把主机名修改和检查放在同一个命令中,退出时更容易确认修改只存在于新环境。

# 创建临时 UTS 命名空间,并在其中运行一个子 shell
unshare --uts /bin/sh -c '
  # 只修改新 UTS 命名空间里的 hostname
  hostname lab-uts
  # 打印当前 namespace 看到的主机名
  printf "namespace hostname: %s\n" "$(hostname)"
'

这个命令成功时,输出应包含 namespace hostname: lab-uts。命令结束后,子 shell 和临时 UTS 命名空间一起退出;在外部 shell 再运行 hostname,仍然看到外部环境原来的名称。不要把两次输出拼成一个“全局修改”的结论,关键在于它们属于不同的进程上下文。

普通用户为什么常常要配合用户命名空间

单独创建 UTS 命名空间通常需要相应的管理能力。普通用户直接执行 unshare --uts 可能得到权限错误,这不是 hostname 参数写错,而是当前进程没有创建该 namespace 的能力。Linux 环境允许用户命名空间时,可以让 unshare 同时创建用户命名空间,并把当前用户映射成新 namespace 中的 root。

# 创建用户命名空间,把当前用户映射为其中的 root,再创建 UTS 命名空间
unshare --user --map-root-user --uts /bin/sh -c '
  # 新 namespace 内的 root 只用于本次隔离实验
  hostname lab-uts-user
  # 同时查看主机名和当前 UTS namespace 的 inode
  printf "hostname=%s\n" "$(hostname)"
  readlink /proc/self/ns/uts
'

--map-root-user 不会把当前用户变成宿主机 root,也不会扩大宿主机权限;它只建立用户命名空间内的 UID 映射。若系统禁用了 unprivileged user namespace,或者安全策略拒绝该操作,这条命令仍会失败,应按系统管理员的策略处理,不要用绕过方式强行开启。

用户命名空间与 UTS 命名空间组合使用的权限关系图
图2:普通用户实验时,用户命名空间提供映射后的能力,再由 UTS 命名空间承载独立主机名;这是权限关系图。

如何确认自己只隔离了 UTS

排查时可以把检查拆成三个问题:主机名是否只在子 shell 内改变、当前进程是否进入了新的 UTS namespace,以及是否误以为文件系统或进程也被隔离。

# 在父 shell 记录外部主机名,便于和子 shell 对照
outside_hostname=$(hostname)

# 创建 UTS namespace,子 shell 只负责打印对照信息
unshare --uts /bin/sh -c '
  # 显示新 UTS 视图中的主机名
  hostname lab-uts-check
  printf "inside=%s\n" "$(hostname)"
  # namespace inode 用于区分当前 UTS 视图,不代表其他 namespace 已隔离
  printf "uts=%s\n" "$(readlink /proc/self/ns/uts)"
'

# 子 shell 退出后,父 shell 的主机名应保持不变
printf "outside=%s\n" "$outside_hostname"

如果 inside 与 outside 不同,说明主机名视图隔离生效;如果父 shell 的名称也被改变,说明实际执行路径并不是上面的临时 UTS 方案,或者你是在同一个命名空间中检查。/proc/self/ns/uts 只能帮助确认 UTS 归属,不能证明 mount、PID、IPC 或 network namespace 已经隔离。

常见误区与使用边界

  • 把 -u 当成用户命名空间。在 unshare 中,-u 是 UTS namespace;用户命名空间要用 --user 或 -U。
  • 把主机名隔离当成容器。只创建 UTS namespace 不会隐藏宿主机文件,也不会改变进程、网络和挂载的可见性。
  • 忽略 shell 的退出时机。命令结束后临时 namespace 通常没有成员进程,主机名修改不会作为宿主机配置永久保存。
  • 直接绕过权限策略。用户命名空间被禁用时,应确认系统策略和运维要求;不要把权限错误改写成“需要换一个参数”的问题。

一张表记住命令选择

目标命令思路要记住的边界
已有权限,只隔离主机名视图unshare --uts ...只创建 UTS namespace
普通用户做一次隔离实验unshare --user --map-root-user --uts ...依赖用户命名空间策略
退出后仍需进入同一个 namespace需要额外的持久化与进入方案本文不展开持久化 namespace

相关问题

unshare -u 会隔离网络吗?

不会。-u 只针对 UTS 命名空间;网络隔离需要单独的 network namespace,并且还要配置可用的网络路径。

为什么 unshare --uts 报 Operation not permitted?

通常是当前进程缺少创建 UTS namespace 的能力,或者系统策略限制了该操作。可以在允许用户命名空间的环境中尝试组合 --user --map-root-user,但不能保证所有发行版和安全策略都允许。

修改 hostname 后宿主机为什么没有变化?

这是预期行为。修改发生在新 UTS namespace 的视图中,临时 namespace 随子 shell 退出而结束,宿主机的 UTS namespace 没有被修改。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>