Docker底层-User Namespace

复制代码
root@LAPTOP-LU4HDAFV:~# id
uid=0(root) gid=0(root) groups=0(root),987(docker)
root@LAPTOP-LU4HDAFV:~# echo $$
285399
root@LAPTOP-LU4HDAFV:~# cat /proc/$$/uid_map
         0          0 4294967295
root@LAPTOP-LU4HDAFV:~# 

UID/GID 详解

基本概念

  • UID (User ID):用户标识符,Linux 用数字标识用户
  • GID (Group ID):组标识符,Linux 用数字标识用户组

    ┌─────────────────────────────────────────────────────────┐
    │ Linux 用户系统结构 │
    │ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ 用户名 (Username) │ │
    │ │ │ │
    │ │ 例如:alice, bob, root │ │
    │ │ (人类可读的名称) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ │ 映射关系 │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ UID (User ID) │ │
    │ │ │ │
    │ │ 例如:1000, 1001, 0 │ │
    │ │ (系统内部使用的数字) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ │ 属于某个组 │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ GID (Group ID) │ │
    │ │ │ │
    │ │ 例如:1000, 1001, 0 │ │
    │ │ (用户所属组的数字) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │
    │ 系统实际使用 UID/GID,而不是用户名! │
    └─────────────────────────────────────────────────────────┘

为什么需要 UID/GID?

  1. 性能:数字比较更快
  1. 唯一性:每个用户有唯一 UID
  1. 系统内部:内核使用数字,用户名只是映射

    ┌─────────────────────────────────────────────────────────┐
    │ 用户名 vs UID │
    │ │
    │ 人类视角: │
    whoami │ │ alice │ │ │ │ 系统视角: │ │ id │
    │ uid=1000(alice) gid=1000(alice) │
    │ │
    │ 内核实际使用: │
    │ UID: 1000 ← 内核只认识这个数字 │
    │ GID: 1000 ← 内核只认识这个数字 │
    │ │
    │ 用户名 "alice" 只是方便人类记忆的别名! │
    └─────────────────────────────────────────────────────────┘

User Namespace 工作原理详解

核心概念:UID/GID 映射

User Namespace 通过映射表将 Namespace 内的 UID/GID 映射到主机上的真实 UID/GID。

复制代码
┌─────────────────────────────────────────────────────────┐
│  User Namespace 的 UID/GID 映射机制                     │
│                                                          │
│  ┌──────────────────────────────────────────────────┐  │
│  │ 主机上的真实用户                                  │  │
│  │                                                  │  │
│  │  用户:alice                                     │  │
│  │  UID: 1000  (主机上的真实 UID)                  │  │
│  │  GID: 1000  (主机上的真实 GID)                  │  │
│  │                                                  │  │
│  │  执行命令:                                       │  │
│  │  unshare --user --map-root-user /bin/bash        │  │
│  │         │                                        │  │
│  │         └─────────┐                              │  │
│  └───────────────────┼──────────────────────────────┘  │
│                      │                                  │
│                      │ 创建新的 User Namespace           │
│                      ↓                                  │
│  ┌──────────────────────────────────────────────────┐  │
│  │ User Namespace 内部                               │  │
│  │                                                  │  │
│  │  ┌──────────────────────────────────────────┐   │  │
│  │  │ UID/GID 映射表                          │   │  │
│  │  │                                        │   │  │
│  │  │ Namespace UID  →  主机 UID             │   │  │
│  │  │ ──────────────    ─────────            │   │  │
│  │  │      0        →     1000               │   │  │
│  │  │      1        →     1001               │   │  │
│  │  │      2        →     1002               │   │  │
│  │  │    ...        →     ...                │   │  │
│  │  │   65534       →    106534              │   │  │
│  │  └──────────────────────────────────────────┘   │  │
│  │                                                  │  │
│  │  进程在 Namespace 内看到:                       │  │
│  │  $ id                                            │  │
│  │  uid=0(root) gid=0(root) groups=0(root)         │  │
│  │                                                  │  │
│  │  但实际上映射到主机的 UID 1000!                 │  │
│  └──────────────────────────────────────────────────┘  │
│                                                          │
│  关键:Namespace 内的 root (uid=0) 映射到主机的 UID 1000 │
└─────────────────────────────────────────────────────────┘

为什么不需要 root 权限?

Linux 内核允许普通用户创建 User Namespace(自 Linux 3.8 起),原因:

  1. 安全性:Namespace 内的 root 权限被限制在 Namespace 内
  1. 隔离性:无法影响主机上的其他进程
  1. 映射机制:通过 UID/GID 映射表控制权限

    ┌─────────────────────────────────────────────────────────┐
    │ 权限检查流程 │
    │ │
    │ 进程在 User Namespace 内执行操作: │
    │ │
    │ 1. 访问 Namespace 内的文件 │
    │ ↓ │
    │ 检查:Namespace 内的 UID (0) │
    │ ✓ 允许(在 Namespace 内是 root) │
    │ │
    │ 2. 访问主机上的文件 │
    │ ↓ │
    │ 检查:映射后的主机 UID (1000) │
    │ ✗ 拒绝(主机上不是 root) │
    │ │
    │ 3. 影响主机上的其他进程 │
    │ ↓ │
    │ 检查:映射后的主机 UID (1000) │
    │ ✗ 拒绝(主机上不是 root) │
    │ │
    │ 结论:Namespace 内的 root 权限被限制在 Namespace 内! │
    └─────────────────────────────────────────────────────────┘

    ┌─────────────────────────────────────────────────────────┐
    │ 1. 普通用户执行命令 │
    │ │
    unshare --user --map-root-user /bin/bash │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 2. 内核创建新的 User Namespace │ │ │ │ │ │ │ │ • 分配新的 Namespace ID │ │ │ │ • 创建新的进程(bash) │ │ │ │ • 设置初始 UID/GID 映射 │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 3. --map-root-user 自动设置映射表 │ │ │ │ │ │ │ │ /proc/self/uid_map: │ │ │ │ 0 <当前用户UID> 1 │ │ │ │ │ │ │ │ /proc/self/gid_map: │ │ │ │ 0 <当前用户GID> 1 │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 4. 进程在 Namespace 内运行 │ │ │ │ │ │ │ │ id │ │
    │ │ uid=0(root) gid=0(root) │ │
    │ │ │ │
    │ │ 但实际权限检查时: │ │
    │ │ • Namespace 内操作 → 使用 UID 0 │ │
    │ │ • 主机操作 → 使用映射后的 UID 1000 │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ 5. 权限检查机制 │ │
    │ │ │ │
    │ │ 访问 Namespace 内资源: │ │
    │ │ ✓ 使用 Namespace UID (0) → 有 root 权限 │ │
    │ │ │ │
    │ │ 访问主机资源: │ │
    │ │ ✗ 使用主机 UID (1000) → 只有普通用户权限 │ │
    │ └──────────────────────────────────────────────────┘ │
    └─────────────────────────────────────────────────────────┘

相关推荐
悠悠121386 分钟前
微服务通信别只看性能:REST 与 gRPC 的 6 个选型判断和一次 502 故障复盘
运维·服务器
zx_741484812 小时前
【Linux入门】Shell 函数、正则表达式与文本处理:cut 与 awk
linux·运维·正则表达式
Zenova EdgeOS2 小时前
Linux dmesg 工业边缘实战:内核日志过滤、持久化与故障定位
linux·运维·边缘计算·工业边缘·dmesg·内核日志
九皇叔叔2 小时前
K8S 资源菜单
docker·容器·kubernetes·k8s
wdfk_prog3 小时前
ROS教程08:从 TransportTCP::connect() 追到 TCPROS Connection Header、序列化与 Socket 数据传输
运维·缓存·docker·容器·ros
Zhu7583 小时前
docker环境快速部署postgresql数据库18及以上版本
postgresql·容器
做运维的阿瑞3 小时前
Python 标准库汇总:分类速览与常用模块清单
linux·运维·python
zoutao984 小时前
Gitea Actions 自定义 Runner 镜像与自动化部署实战
ci/cd·docker·gitea
日常筹谋记4 小时前
自动化仓储安全防护工况评估:明治传感器AS-33C技术适配性分析
大数据·运维·创业创新·业界资讯
Shadow(⊙o⊙)5 小时前
Linux进阶知识1.0
linux·运维·服务器