Linux 用文件作为统一接口、用进程作为执行单位、用凭据和命名空间划分边界,再用 cgroup 约束资源。
VFS 把普通文件、目录、块设备、字符设备、管道、socket 和内核状态都抽象成可打开的对象。进程通过文件描述符对它们执行 open、read、write、close,所以同一套工具可以操作磁盘、终端、/proc 和网络连接。抽象统一了接口,但不同对象的语义仍不同:socket 不能随机读写,设备文件的行为由驱动决定。
每个进程都有 PID、PPID、地址空间、打开的文件描述符、凭据和命名空间。fork 复制父进程,exec 替换映像;PID 1 负责回收孤儿进程,退出但未被回收的子进程会变成僵尸。信号是异步控制手段,SIGKILL 不能被捕获,SIGTERM 给了程序清理机会。进程不是“一个程序文件”,而是内核管理的一组运行时状态。
权限由 uid/gid 和模式位共同决定:rwx 对文件表示读、写、执行,对目录表示列出、创建删除条目、进入目录。目录只有 r 没有 x 时,能看到名字却无法访问内容。除模式位外还有 ACL、setuid/setgid、sticky bit 和 capability;root 绕过普通 DAC 检查,但仍受 SELinux、AppArmor 等强制访问控制约束。
文件描述符是进程内的小整数,指向内核的打开文件描述,再指向 inode。0/1/2 分别是标准输入、输出和错误;管道和 socket 也是描述符。删除文件只是移除目录项,只要还有进程持有描述符,inode 和数据块就不会释放。描述符数量有软硬限制,泄漏会表现为 Too many open files,而不是内存上涨。
namespace 决定“你能看到什么”:PID、挂载、网络、UTS、IPC、用户、cgroup 和时间都可以隔离。cgroup 决定“你能用多少”:CPU、内存、IO 和进程数被计量与限制。容器不是轻量虚拟机,而是 namespace、cgroup、rootfs、capability 和挂载配置的组合;共享内核意味着隔离强度与虚拟机不同。
一次网络请求从 socket 进入 TCP/UDP,再经过 IP 路由、netfilter 规则和链路层。监听 socket 由协议、地址和端口唯一标识,ss 读的是内核维护的表。DNS 解析由 /etc/nsswitch.conf 和 /etc/resolv.conf 决定,容器内还有独立的网络 namespace 和 DNS 配置。排障时要先确认自己在哪个 namespace、哪张路由表和哪条规则链里。
| 层次 | 核心对象 | 观察入口 |
|---|---|---|
| 文件与设备 | inode、VFS、挂载点 | ls -li、findmnt、/proc/mounts |
| 进程与调度 | task_struct、PID、状态 | ps、top、/proc/<pid> |
| 权限与边界 | uid/gid、mode、capability | id、ls -l、getcap、getfacl |
| 隔离与资源 | namespace、cgroup | lsns、nsenter、/sys/fs/cgroup |
| 网络 | socket、路由、netfilter | ss、ip、nft、tcpdump |
一条请求的典型路径是:进程打开 socket(文件描述符),经过网络 namespace 的路由和 netfilter,到达对端;权限和 cgroup 在每一步限制它能做什么、能用多少。
chmod 777 能解决权限问题,绕过最小权限原则。free 很小就是内存不足,忽略可回收的 page cache。sysctl 或路由,却没意识到自己在独立的网络 namespace。合上页面,先回答,再展开对照。
df 显示的空间没有减少?x 权限和文件的 x 权限分别控制什么?lsof +L1 找到持有进程,关闭文件或重启进程后空间才释放。x 表示可以执行;目录上的 x 表示可以进入目录、访问已知路径和把目录作为路径组成部分。目录只有 r 时能列出名字,但没有 x 无法访问条目。