Linux目录结构深度解析:从FHS到磁盘排障实战

发布时间:2026/10/14 5:20:10
Linux目录结构深度解析:从FHS到磁盘排障实战
半夜两点被值班电话叫醒某台服务器磁盘告警登录上去看df -h根分区已经 100%du扫了一圈发现/var/log和/tmp各占了一大半一时半会儿还不知道哪些文件能清。这种场景干运维的多少都经历过而每次被这种问题困住根子都在同一个地方对 Linux 文件系统的目录结构理解停留在“大概知道”的层面真到了关键时刻没法靠目录树的逻辑快速定位问题。很多人觉得目录结构就是考试题记住/etc放配置、/var放日志就够了。但实际工作中你会发现这套目录结构里面藏着 Unix 四十多年的设计思路谁在什么场景下该往哪个目录放东西、为什么有些目录被拆出来单独挂载、为什么删了文件磁盘空间却不见少全都能从目录结构中找到答案。这篇我就把自己这些年跟 Linux 目录结构打交道的理解、踩过的坑、以及排障时怎么用目录树的思维解题一次讲透。1. 目录结构从来不是随便画的FHS 与 Unix 设计逻辑的来龙去脉Linux 的目录结构不是某个团队拍脑袋定的而是沿袭了一套名为 FHSFilesystem Hierarchy Standard的标准。FHS 本身又是从 Unix 早期目录布局演化过来的理解这段历史你就能明白“这个目录为什么存在”而不是死记硬背。1.1 从一块硬盘到一棵树的演进为什么根目录下要有这些固定目录Unix 诞生于上世纪 70 年代的贝尔实验室当时的计算机存储资源极其紧张系统设计者把目录当成了一种隐形的“接口约定”。/bin放系统启动和执行基础命令所需的二进制/etc放配置文件/dev放设备文件这套约定解决了什么问题它让人和程序在没有任何数据库的情况下也能大致猜到某个文件应该在哪比如配置文件丢了就去/etc找可执行文件不在PATH里就去/bin或/usr/bin翻。Linux 沿用了这套约定并在此基础上发展出 FHS核心目标有两个一个是让软件开发者知道“该把文件装到哪里”才能让不同发行版兼容另一个是让系统管理员知道“该去哪里找文件、备份哪些目录、清理哪些目录”。所以你别小看根目录下那一排目录名每一个都对应着一类文件的“职责归属”。比如/srv是给服务提供数据文件的早期很多新手会把网站代码放到/home/www或/root/www严格来说都不符合 FHS 的推荐放到/srv/www才是规范的。1.2 四个维度的分类可共享、不可共享、可变、静态FHS 背后真正的分类逻辑其实是两个交叉的维度文件和目录是否可共享across hosts以及是否可变variable vs. static。把目录往这四个象限里一放就能看懂整个布局的深意。可共享且静态比如/usr它里面是安装的软件和库文件基本不变而且可以导出给同网络的其他机器用也就是只读共享。可共享且可变比如/var/mail、/var/spool这些数据在机器之间同步有意义但是内容会一直变。不可共享且静态比如/etc每台机器的配置都不一样不能跨机器共享但文件本身不经常变。不可共享且可变比如/var/log、/var/run这是本机运行时产生的内容既不能共享又一直变化。这个分类法解决了一个实际问题做备份、做镜像、做集群扩容时你不需要把整个根分区打包只要按照这些维度去挑目录就行。比如要给一台新机器复刻环境把/etc导出、把/usr镜像一份、再初始化/var里的业务数据基本就完成了。我在实际迁移环境时就是这么干的而不是拿着dd去整盘克隆省下的时间不是一点半点。强调一下FHS 规定的其实是“目录应该装什么”而不是“目录非长这样不可”。不同的发行版可以微调但那棵大树的枝干是一致的这也是为什么你在任何主流发行版上都能快速上手的原因。2. 二级目录逐层拆解每个目录真正在扛什么活儿根目录下的二级目录是使用频率最高的我打算把一个一个拆开讲但不按教科书顺序而是按它们在真实系统中的“数据生命周期”来讲系统启动期、运行期、动态数据期、虚拟数据期、用户数据期。这样你脑子里会形成一条线而不是零散的点。2.1 /bin 与 /sbin早期启动的最小可用环境/bin在老的 Unix 系统里存放的是最基本的用户命令/sbin存放的是系统管理命令两者的边界主要体现在“谁在什么状态下需要它”。/bin里的ls、cp、cat是单用户模式、救援模式下也要能用的/sbin里的fdisk、fsck、mkfs是系统维护和修复时才需要的。现在大多数发行版里/bin和/sbin其实是指向/usr/bin和/usr/sbin的符号链接这就是所谓的 usr mergeusr 合并把根目录下的二进制都归拢到/usr下根分区只需要承担启动那一小部分。这个改动让根分区变得更小、更稳定也更容易做只读挂载。判断你的系统是不是这种布局直接ls -ld /bin看有没有箭头就行。实际排障中我经常提醒自己当系统进入救援模式时PATH往往很短很多命令都在/sbin下但不在默认PATH里。这时候你直接输入ifconfig如果还在用的话会提示找不到但/sbin/ifconfig是能跑的。记住这一点关键时刻能救命。2.2 /usr你以为是用户目录实际是系统软件的大本营/usr是个极其容易误解的目录名字看起来像 user所有人都以为它和“用户数据”有关。实际上/usr是 Unix System Resources 的缩写里面装的是系统软件资源而不是用户文件。用户文件在哪在/home这是两个完全不同的概念。/usr/bin放的是发行版自带和通过包管理软件装进来的绝大部分可执行文件/usr/lib放的是配套的库文件/usr/share放的是架构无关的共享数据比如帮助文档、字体、图标。一个典型的系统里/usr 的体积可能占整个操作系统的七八成以上。理解了这一点你就明白为什么有些人会把/usr单独挂到一个比较大的分区上根分区只给系统启动留出必要空间。这设计在目前大多数系统上实践下来很稳即使系统日志把/var撑满了也不会拖垮正在运行的二进制程序登录还能进得来排查就有抓手。2.3 /var所有“会长大”的数据都在这里/var里全是动态变化的文件这也是磁盘告警最先应该排查的目录。/var/log存各类日志、/var/tmp是比/tmp更“长寿”的临时文件重启后可能依然存在、/var/lib存软件包的运行状态数据比如数据库文件、Docker 的 overlay 目录。可以说整个系统运行起来之后绝大部分“新增落盘的数据”都在/var下。最重要的排障思路磁盘满了先别rm扔着等而是按照“先查/var/log、再查/var/tmp、再查/var/lib”的顺序层层逼近。很多日志默认不轮转或者轮转配置不合理单个日志文件能涨到几十 GB 甚至上百 GB。我在某次处理一个广告服务集群的日志时发现某个access.log已经 40GB 且还在跑最后就是调整/etc/logrotate.d/下的配置把它“治住”的。2.4 /etc系统唯一的中心化配置目录/etc大概是所有人最早记住的目录但它的边界比很多人以为的更清晰。该目录只存放静态的配置文件不允许存放可执行文件更不允许保存动态生成的文件。系统的网络配置、用户账户信息/etc/passwd、软件服务的配置比如 Nginx 的/etc/nginx/都在这里。这里有一个特别容易犯的错误有些部署脚本喜欢把临时状态文件、PID 文件往/etc里塞。从 FHS 的角度这属于污染配置目录PID 文件应该放到/run状态文件应该放到/var/lib。我在项目规范里会明确指出这种边界因为一旦把/etc当垃圾桶备份和迁移配置时就会多出一堆不该有的内容。2.5 /proc 与 /sys不占磁盘的“虚拟文件系统”/proc和/sys是新手最容易懵的两个目录ls进去看到一大堆数字和文件其实它们并不是磁盘上真实存在的文件而是内核提供给用户态的一个“视图”。/proc主要通过进程号目录暴露每个进程的运行状态比如/proc/loadavg看负载、/proc/meminfo看内存细节/sys则用来暴露设备驱动、内核参数、电源管理等更底层的对象。对系统管理来说这两个虚拟目录的意义在于很多原本需要写程序或调用系统调用的信息直接用cat、echo就能读写。例如临时开启 IP 转发echo 1 /proc/sys/net/ipv4/ip_forward就能生效而且不用重启。当然这种直接改法重启后失效生产环境还是建议通过/etc/sysctl.conf或sysctl.d配置文件持久化。2.6 /home、/root 与 /tmp用户空间和“临时停车场”/home是普通用户的家目录集合/root是管理员root 用户的家目录。这两个目录里的数据属于“用户产生数据”需要和系统目录分开备份。有些公司会把整个/home单独挂一块盘这样系统重装时用户数据不受影响这是标准的实践。/tmp是所有用户都能读写的共享临时代它的特点是任何用户都能往里写这既是便利也是风险。攻击者常常在/tmp里放临时提权工具普通用户如果磁盘配额不限制也可能把共享的临时空间写满影响其他人。生产环境里我通常建议把/tmp独立挂载并加上noexec选项禁止在这个目录里执行任何二进制这是成本极低但收益很高的安全加固手段。3. 磁盘爆满却找不到大文件用目录树思维设计排障链路理解了目录的职责排障就不再是无头苍蝇。我这里把一个典型的“磁盘满但找不到大文件”案例拆出来完整走一遍排查链路你会发现每一步其实都对应着目录设计逻辑。3.1 第一层排查从 / 开始逐层 du而不是靠 ls 猜接到磁盘告警第一件事当然是df -h看是哪个分区满了。假如告警的是/那么接下来要用du -xhd1 /按一层目录统计根目录下的占用大小。这里的关键参数是-x即--one-file-system它告诉du不要跨文件系统否则会把挂载在/下的其他独立分区比如/home也算进来造成误判。我看到有些人习惯直接du -sh /这样扫全盘又慢又容易触发权限告警扫出来的数值还因为跨文件系统而失真。正确姿势是一层层往下收窄先看du -xhd1 /找到/var或某个目录占大头再进到下一层接着du -xhd1 /var把范围逐步缩小到具体文件或子目录上。这个过程快的话几十秒慢的话几分钟比写成脚本全盘扫要高效得多。3.2 第二层排查inode 用尽与“进程占用已删除文件”有时候df -h显示空间还剩不少但系统就是报告磁盘满比如No space left on device这时候要考虑df -i检查 inode。inode 是文件系统记录文件和目录元数据的结构任何文件即使大小为 0 也要消耗一个 inode。如果某个目录下生成了海量小文件比如/tmp里大量随机会话文件或/var/spool里堆积的队列条目就会先把 inode 耗尽表现就是明明还有空间却写不进去任何文件。这里还要提一个经典坑用rm删除了文件但df显示空间没变化。原因是有进程仍然持有这个文件的文件描述符fd文件没真正释放。排查方法是用lsof | grep deleted找出还在占用已删除文件的进程确认后重启对应进程或让它重新打开日志文件。这个坑跟目录结构的关系在于/var/log 下的日志文件如果被进程保持打开运维轮转或删除日志时必须通知进程重新打开文件否则磁盘空间会一直“错觉占满”。3.3 第三层排查合理的清理由本应避免的脏数据堆积查出来大文件在哪之后怎么清理也是门学问。以日志为例你应该优先处理/etc/logrotate.d/下的轮转配置而不是手动rm。手动删除日志文件容易导致正在写日志的进程找不到原来的文件句柄行为变得难以预料。正确做法是让 logrotate 定时轮转保留若干历史再动态给进程发信号让它重新打开新日志文件。还有/tmp里面的大文件很多是程序运行时不规范把临时文件写到/tmp又没清理。除了定期用tmpwatch或systemd-tmpfiles清理有些值班脚本也会顺手清更重要的是根治程序行为让临时数据写到规范的位置比如应用自己目录下的tmp或/var/tmp。把这一层线理顺之后你会发现磁盘排障从“每次都被动救火”变成“按目录树定期体检”。4. 挂载、权限与安全加固目录结构的运维进阶玩法目录结构不仅决定文件放哪里还决定你怎么挂盘、怎么控权、怎么防攻击者。这一节我会讲几个很具体的实操配置都是生产环境里验证过很多年依然稳当的方案。4.1 哪些目录值得独立挂载/home、/tmp、/var 的取舍把重要目录单独挂载到独立分区或磁盘是 Linux 运维里非常重要的设计决策。好处主要有三个一是隔离故障某个分区写满不会连带拖垮根分区二是方便备份直接对挂载点做快照即可三是能做不同的挂载选项按目录的数据特征施加差异化安全策略。/home用户数据独立挂载操作系统重装或崩溃时数据不受损这是最标准的备份边界。/tmp独立挂载并启用noexec,nosuid禁止执行临时文件、禁止提权这是最推荐的安全做法。/var日志和数据增长大户独立挂载避免日志涨满根分区。/usr软件主体如果能接受只读挂载可以加ro提高安全性和稳定性。但前提是你足够清楚系统在正常运行时不会往/usr里写数据否则会出现莫名奇妙的写入失败。4.2 fstab 实战配置用一行挂载选项体现安全策略下面是一段典型的/etc/fstab配置示例你可以看到目录与挂载逻辑是如何结合的# 设备 挂载点 类型 选项 dump pass /dev/sda3 / ext4 defaults 1 1 /dev/sda5 /home ext4 defaults,nodev,nosuid 1 2 /dev/sda6 /tmp ext4 defaults,nodev,nosuid,noexec 1 2 /dev/sda7 /var ext4 defaults,noatime 1 2这几行配置分别对/home加了禁止设备文件与禁止 SUID、对/tmp额外加禁止执行noatime表示不记录文件访问时间戳减少磁盘写放大。dump和pass列中/为 1 表示最先做文件系统检查其他分区为 2 表示随后检查。使用findmnt或mount -a可以验证配置是否生效。强调一句修改/etc/fstab前建议先用mount -o remount方式验证挂载选项不存在语法错误否则重启时因为 fstab 写错导致系统卡在维护模式处理起来比较费劲。如果真把 fstab 写坏了用单用户模式或引导盘把 fstab 改回来即可但这个过程在无带外管理的远程服务器上会非常痛苦。4.3 目录权限与默认掩码把入口封到刚刚好Linux 的目录结构是骨架权限则是挂在骨架上的锁。一个常见的安全实践是对/home下的用户目录设置为 700 或 750阻止其他用户随意查看家目录对/tmp这种共享目录利用 sticky bit粘贴位用一个t表示限制只有文件所有者才能删除自己创建的文件。Linux 的/tmp默认已经带上了这个位ls -ld /tmp能看到权限末尾的t。默认文件权限由umask决定比如把umask 022改成umask 027新创建文件/目录对“组内其他用户”就不再开放写权限。很多安全基线要求就是这个原因尽量最小化新文件的默认开放面然后按需追加。目录结构配合权限做下来系统暴露面能少一大截。5. 发行版差异与容器时代这套结构还够用吗很多人在学目录结构时有个疑惑CentOS 和 Ubuntu 的目录为什么看起来不完全一样Docker 容器里的目录结构是不是也按 FHS 来这里我展开讲一下这两个问题因为它们直接关系到你对目录结构知识的“可迁移性”。5.1 CentOS/RHEL 系与 Ubuntu/Debian 系的主要目录差异不同发行版对 FHS 的执行力度有差异最典型的就是前面提到的 usr merge。RHEL/CentOS 7 之后、Ubuntu 较新的发行版基本都把/bin、/sbin、/lib做成了指向/usr对应目录的符号链接。老的 Ubuntu 14.04 时代还不是这样如果你在/bin找不到某个命令先在/usr/bin搜一下这个经验放到新旧系统上都适用。另一个差异在软件包管理产生的目录比如 Ubuntu 的/var/lib/dpkgRHEL 系对应的是/var/lib/rpm本质上都落在/var/lib这个“包管理状态数据库”的范畴里。遇到新系统时只要你能识别出“这是/var/lib下的某种状态目录”就不会因为具体子目录不同而迷路。还有/opt的用法FHS 推荐第三方闭源软件装到/opt下的独立子目录比如/opt/oracle避免污染系统目录但开源软件习惯装进/usr体系。理解了这层约定你在部署一些“解压即用”的软件包时就知道该放到哪个位置最规范。5.2 容器镜像里的目录结构FHS 的“降级”与根文件系统设计容器镜像通常也是基于标准的发行版目录骨架构建的但有一个显著区别容器里的根文件系统默认是只读层 可写层的叠加。镜像层里/usr、/etc这些目录来自基础镜像而/var或/tmp在容器运行期产生的写入可能只存在于该容器的可写层容器删除后这些数据就没了。正因为容器是“短生命周期”的运维习惯跟传统机器完全不同状态数据要么挂卷volume映射到宿主机要么放到外部存储。你看到某个容器里的/var/lib/mysql如果不挂卷容器一删数据就蒸发这本质上是在 FHS 的目录语义之上叠加了容器存储的生命周期语义。这也解释了为什么容器时代目录结构知识依然重要你排障时仍然需要顺着/var/log、/etc/nginx、/proc这些路径去判断问题只是对“哪些数据要持久化到宿主机”多了层判断。理解了传统目录结构的“归属逻辑”理解容器存储设计就是水到渠成的事。5.3 从一个目录结构出发建立你自己的系统地图最后我想说一个观点目录结构本质上是最好的系统地图。当你面对一台陌生的 Linux 机器时先花五分钟大致浏览根目录下的二级目录你就能快速推断出这台机器装了哪些软件、采用什么样的数据布局、日志和配置放在哪里。这种“地图感”是新老运维差距最直观的体现之一。我在接手某台历史悠久的服务器时习惯先跑一下ls /、ls /opt、ls /data如果存在的话配合mount看挂载点脑子里立马就能浮现出这台机器的画像根分区多大、哪些目录独立挂载、有没有人往根目录塞过自定义文件夹。这种画像能力只能靠对目录设计和默认约定的熟悉程度获得任何监控工具都替代不了。6. 目录结构实用自查清单与个人实践经验技术内容讲得差不多了这一节聊点更贴近日常操作的干货。我把这些年在目录结构应用上总结的自查清单和使用经验直接列出来你可以存下来当工作手册用。6.1 日常目录使用自查三问法防止路径混乱在写部署文档、写存储方案、写清理脚本时建议每次都问自己三个问题这个文件是静态的还是动态的静态的放/usr、/opt体系动态的放/var。这是目录选择的第一个分流依据。这个文件是系统自己生成的还是用户产生的系统运行状态放/run、/var/lib用户真实数据放/home、/srv。这个文件重启后是否还需要临时到极端的数据放/tmp重启后还要留一段时间的放/var/tmp需要长期保留的绝不能只丢在/tmp。这三问看着简单但我在 code review 和脚本评审里抓出过不少把持久数据写到/tmp、把日志和代码混在一个目录下的案例。目录结构是系统设计的子结构它混乱的根源通常是当初没人用这三问做过校验。6.2 针对不同分区场景的挂载实践根据我自己的实践不同“角色”的机器分区方案应有差异化倾向不能一套配置通吃机器角色核心考虑推荐挂载策略Web 前端日志增长快、代码更新频繁/var独立且空间给足/usr跟随根分区/tmp加 noexec数据库数据文件持久性要求高/var/lib具体看数据库独立挂载到高性能盘/home可以很小大数据/对象存储海量小文件与应用数据独立数据盘挂在应用路径下例如/data同时注意 inode 用量容器宿主机镜像与容器层占用大/var/lib/docker或容器存储目录独立挂载日志轮转要提前配好这个表格只提供一个思路具体还是要结合你所在团队的规范。但方向是确定的每个分区都要有明确的“用途归属”而不是稀里糊涂把所有东西塞进根分区。6.3 看完目录结构对工作流的直接影响备份与迁移策略最后一点经验是关于备份迁移策略的。一旦你掌握了目录结构其实就掌握了备份的第一性原理——你不需要备份整个系统只需要备份“不可再生但必须保留的数据”。照这个思路系统配置文件备份整个/etc这几乎是重建一台机器的“基因”。用户数据备份/home或远端挂载点对应的用户主目录。服务数据按服务备份/var/lib下对应子目录或/srv下的数据目录。数据库数据如果数据库装在默认路径备份它对应的/var/lib子目录或直接使用数据库自带的 dump 工具强烈不建议只靠文件拷贝备份正在运行的数据库文件。我见过不少团队备份方案就是“把整块云盘做快照”这当然是可行且有效的但在追求精细恢复、按目录恢复、跨机器迁移时目录级的备份策略有着不可替代的灵活度。目录结构给管理员带来的最大优势就是让你能把系统拆成一个个逻辑上独立、边界清晰的“积木块”备份、迁移、恢复都变得像拼图一样可控。这套知识平时看起来不像框架、不像中间件那么有“技术感”但它是所有排障、部署、安全加固的底层地基。我自己每次被某个目录问题折腾一遍后再回头看都会发现所有坑几乎都能绕回同一个结论我当初要是对这个目录的“定位”再多想一步这个事故大概率可以避免。希望这篇内容能帮你在心里也建立起这样一张 Linux 目录地图。