在RHCSA备考圈里流传着一句话选择题可以靠短时间记答案结课项目只能靠实打实练。我当初不以为意等自己站到结课项目面前才发现平时上课拆开练的单个命令一点问题没有但一旦要求从一台裸机起步把用户、存储、服务、安全全部串起来脑子里那根线就开始乱。RHCSA结课项目本质上是一次全链路交付给你一台刚完成最小化安装的服务器要求你在规定时间内把它改造成一台符合验收条件的业务主机。这篇文章把我做结课项目时的完整流程、关键命令、验收清单和踩坑记录整理出来给正在准备RHCSA考试或者想系统建立Linux运维实操能力的同学一份可以直接照着做的参考。1. 结课项目的考核范围与实验环境规划1.1 一张表看懂RHCSA结课项目的任务边界拿到项目要求后我第一件事不是急着敲命令而是把课程大纲和验收标准并排放在一起逐条圈出这个项目到底覆盖了哪些内容。你会发现它几乎把RHCSA考纲里的核心模块全装进去了。任务域典型验收点对应核心知识点系统初始化主机名正确、重启后IP不变、SSH可用nmcli、hostnamectl、autoconnect用户权限指定用户/组存在共享目录权限生效useradd/groupadd、setgid、sudo存储管理LVM卷挂载到指定目录重启不丢pvcreate/vgcreate/lvcreate、fstab服务管理自定义服务开机启动定时任务生效systemd unit、cron网络存储客户端能自动访问NFS共享NFS export、autofs安全加固防火墙开放最小端口SELinux保持Enforcingfirewalld、semanage/restorecon验收复现重启后所有功能仍然正常综合排障能力这样整理完会发现项目不会单独考你“会不会建用户”“会不会开端口”而是把问题揉在一起NFS访问不了可能因为防火墙可能因为SELinux布尔值也可能因为autofs没启动。这就是结课项目比单项练习难的地方它逼着你建立排查顺序。我在做之前就把这张表打印出来贴在显示器旁边每完成一项就打个勾最后验收时心里非常有底。1.2 实验环境规划三个决定让后面少走三倍弯路我的实验环境很简单但很关键宿主机上跑一个虚拟机软件里面建了两台虚拟机一台作为被改造的服务器A一台作为验证NFS和认证功能的客户端B两台都在同一个虚拟网络里。如果你只是单机一个人练我也会强烈建议至少拆成两台因为很多项目要求NFS、SSH互访、firewalld规则只有在跨主机场景下才测得出效果。只在一台机器上开回环地址自测看着能通一到真正交付就会露馅。剩下三个决定我认为比虚拟机配置还重要。第一每完成一个阶段就手动快照一次。这个习惯救了我至少两次。一次是把fstab写错导致重启后直接进维护模式一次是SELinux改错上下文折腾了半天靠快照回滚重做而不是在错误配置上越陷越深。第二统一使用最小化安装。结课项目的目标系统不是桌面环境最小化安装既能贴近真实服务器也能避免图形界面占用资源更重要的是它逼着你用命令行完成所有操作这是RHCSA的基本功。桌面版日常用起来舒服但练习时的肌肉记忆完全是另一套。第三提前解决软件源。课程统一使用某企业级Linux发行版考试和项目环境默认也是这种。网络条件不好的话建议先把本地源或者可用镜像站配好别把时间耗在安装包下载上。我见过有同学在项目现场才去装nfs-utils结果下载卡了半小时后面的安排全被打乱。2. 网络、用户与权限初始化阶段最容易扣分2.1 主机名与静态IP的配置套路结课项目开场通常是这样的登录一台刚从模板克隆出来的机器然后要求把它设置成指定的主机名和静态IP。很多人习惯直接去改网络配置文件但这里我建议你把NetworkManager的nmcli当作首选。nmcli的优点有两个一是它会同步更新NetworkManager的配置数据库避免手动改文件后配置与NM状态不一致二是它本身就支持命令行补全和脚本化在自动验收环境里特别有用。以网卡名为ens160的机器为例hostnamectl set-hostname server-a.example.lan nmcli con mod ens160 ipv4.addresses 192.168.10.20/24 \ ipv4.gateway 192.168.10.1 ipv4.dns 192.168.10.1 \ ipv4.method manual connection.autoconnect yes nmcli con up ens160做完以后不要急着往下走先ip addr show ens160确认IP生效再ping -c 3 192.168.10.1确认网关通。我特别想提醒的是最后那项connection.autoconnect yes。某次我在实际项目里漏了这个参数当场测试完全正常重启后网络直接消失排查了十分钟才发现是NM没有把它设成自动连接。这类“当下正常、重启失效”的问题是结课项目验收最擅长设置的陷阱。2.2 用户、用户组和共享目录权限怎么搭不返工用户权限模块看起来简单但返工率极高。项目通常会给出这样的需求建立若干用户和组某些用户同时属于多个组还要在某个共享目录上做到“组内成员可以写入文件自动继承组身份”。我当时的做法是先把用户和组的从属关系画在一张纸上明确谁是谁的主组、谁在哪个附加组里避免在命令行里现想现敲。以几个虚构用户为例groupadd finance groupadd hr groupadd it useradd -g finance alice useradd -g hr bob useradd -g it carol usermod -aG finance bob usermod -aG it alice这里要注意-g设置的是主组-G追加的是附加组。主组对用户新建文件的默认属组有影响而附加组往往用于“能访问某个共享目录”这类需求。如果你把两者混为一谈后面排障会很痛苦因为不同工具查出来的组信息对不上。共享目录权限是另一个高分值点。假设要求/srv/finance只允许finance组写入并且组内新建文件自动属于finance组mkdir -p /srv/finance chown root:finance /srv/finance chmod 2770 /srv/finance这里的数字是有讲究的。2是setgid位它让这个目录下新建的文件自动继承目录的所属组而不是创建者的主组7代表拥有人和组的读写执行权限最后的0表示其他人完全无权限。如果需求是“所有人都能写但不能互相删别人的文件”那就得用sticky bit比如1770这种。权限数字一定要自己会算而不能只靠记住某个命令模板。sudo的配置也经常被考到。现在推荐的做法不是直接编辑主sudoers文件而是在/etc/sudoers.d/下放一个独立文件usermod -aG wheel alice echo alice ALL(ALL) NOPASSWD:ALL /etc/sudoers.d/alice-admin chmod 440 /etc/sudoers.d/alice-admin visudo -c为什么放独立文件一是好回滚改坏一个文件只影响单个配置二是验收时路径清清楚楚。文件权限必须设置成440sudo会忽略任何组外可写或全局可写的sudoers文件这是安全机制不是装样子。NOPASSWD的写法在自动化验收环境里很常用但如果项目没有明确要求我还是建议不配置这个选项保持最小化授权。2.3 权限自查清单一下午的返工都是因为没查这几点用户和权限模块做完后我强烈建议别急着做下一阶段先花十分钟自查一遍。这个习惯帮我避免了无数次返工。自查清单大概是这样的getent passwd alice、getent group finance能否看到内容id alice输出里附加组是否包含预期组ls -ld /srv/finance确认权限是drwxrws---那个s表示setgid已经生效用真实用户创建文件验证su - alice -c touch /srv/finance/test.txt然后ls -l /srv/finance/test.txt检查属组是不是finance如果不是赶紧回去检查目录的setgid位和alice的组成员关系sudo -l -U alice查看alice的sudo权限是否符合要求。为什么要用真实用户去创建文件因为ls -ld只能看到目录的权限位而“自动继承属组”这个行为只有实际创建文件才会触发。很多同学自测时只看目录权限导致验收脚本一跑就暴露问题。这一阶段的工作量不大但检查价值极高算是整个项目里性价比最高的一次自查。3. LVM、fstab 与 NFS/autofs存储链路实操记录3.1 LVM创建和扩容先弄懂逻辑卷再敲命令存储模块是结课项目里动手量最大的一块。项目给的是两块没有分区的空闲磁盘整体要求是建成逻辑卷、挂载到指定目录、能扩容并且重启后依然有效。先明确一个概念LVM把物理磁盘变成物理卷PV多个PV组成卷组VG再从VG里切割出逻辑卷LV。这样做的价值在于单个磁盘分区不够灵活时你可以跨磁盘聚合空间也可以随时在线扩容。我当时的操作是pvcreate /dev/vdb /dev/vdc vgcreate vgdata /dev/vdb /dev/vdc lvcreate -L 8G -n lvweb vgdata lvcreate -l 80%FREE -n lvsrv vgdata mkfs.xfs /dev/vgdata/lvweb mkfs.ext4 /dev/vgdata/lvsrv mkdir -p /srv/webdata /srv/srvdata mount /dev/vgdata/lvweb /srv/webdata mount /dev/vgdata/lvsrv /srv/srvdata这里我故意把两个LV用了不同文件系统一个XFS一个ext4。因为后续扩容操作正好能体现XFS和ext4的差异。XFS是RHEL系当前默认的文件系统它只能扩大不能缩小扩容时用xfs_growfs加挂载点lvextend -L 2G /dev/vgdata/lvweb xfs_growfs /srv/webdata注意xfs_growfs给的是挂载点路径不是设备路径这是很多新同学容易写错的地方。ext4则可以缩小但步骤要严谨先卸载、检查文件系统、缩减逻辑卷、再调整文件系统顺序不能乱。结课项目如果要求你“缩容”第一件事就是确认目标文件系统要是XFS还硬要缩基本等于给自己挖坑。我见过有同学对着XFS敲resize2fs结果命令报错后慌了最后把卷删了重建。3.2 /etc/fstab持久挂载的UUID原则挂载到目录只是暂时的重启后如果没写进fstab一切都白干。fstab看似简单实际是翻车重灾区。我最推荐用UUID来定位文件系统而不是/dev/vd*这样的设备名。原因很简单设备名在系统里不保证固定加了新磁盘或插拔顺序变化就可能错位UUID是文件系统创建时生成的唯一标识。用blkid查看并把它写进去blkid /dev/vgdata/lvweb然后把输出里的UUID填到/etc/fstabUUIDxxxxx-xxxx-xxxx /srv/webdata xfs defaults 0 0 UUIDyyyyy-yyyy-yyyy /srv/srvdata ext4 defaults 0 0写完以后不要直接重启先用mount -a测试再用findmnt /srv/webdata确认。最后一定要重启一次再回来检查df -h。这一步不能省因为fstab写错会导致系统在启动早期进入维护模式很多同学就是在验收前一刻重启结果眼睁睁看着系统起不来。写UUID的时候从blkid复制粘贴过去别手打手打出错的概率比你想象中大得多。3.3 NFS共享与autofs自动挂载的搭配用法NFS部分是“跨主机”考核的重头戏。服务器A上要导出一个共享目录客户端B要能访问。如果只在一台机器上测试很容易漏掉防火墙和SELinux层面的问题所以前面我特别建议准备两台虚拟机。服务器端要装nfs-utils配置导出目录dnf install -y nfs-utils mkdir -p /srv/share cat /etc/exports EOF /srv/share 192.168.10.0/24(rw,no_root_squash) EOF exportfs -rv systemctl enable --now nfs-server这里rw表示可读写no_root_squash允许NFS客户端root保留root权限。实际生产环境通常不建议开no_root_squash但项目有时会明确要求这时候理解含义比照抄更重要。如果验收时要求客户端能创建文件导出选项里别漏了rw否则后续排查会绕一大圈。客户端这边我用的是autofs而不是直接写fstab。autofs的特点是“用到才挂载、不用就卸载”不会因为NFS服务器暂时不可用就一直卡在启动流程里。配置方式是在主映射目录下放专门文件dnf install -y autofs mkdir -p /shares/proj cat /etc/auto.master.d/proj.autofs EOF /shares/proj /etc/auto.proj EOF cat /etc/auto.proj EOF final -rw,sync 192.168.10.20:/srv/share EOF systemctl enable --now autofs之后在客户端执行ls /shares/proj/final如果能看到服务器端文件说明链路打通。这里有个容易忽略的步骤autofs服务必须处于运行状态否则挂载点目录看起来是空的很多人以为导出配置错了其实只是没启动服务。另一个细节是如果客户端用fstab静态挂载NFS记得加_netdev选项否则开机时网络还没就绪就会挂载失败系统启动流程被卡住。4. systemd服务、定时任务与日志验证4.1 自定义systemd服务别让脚本裸奔在rc.local结课项目里经常出现这样的需求写一个脚本让系统开机后自动执行并要求服务可以被systemd管理、查看状态。现在正确的做法是把它做成systemd单元而不是丢进rc.local。为什么rc.local在新版系统中默认没有可执行权限而且它只是一个线性的启动阶段出了问题你查不到运行时长、退出状态更谈不上start/stop/restart。systemd单元则自带依赖、状态、日志是一等公民。我当时写的服务是这样组织的cat /usr/local/bin/boot-report.sh EOF #!/bin/bash echo $(date %F %T) boot executed /var/log/boot-report.log EOF chmod x /usr/local/bin/boot-report.sh[Unit] DescriptionBoot report service Afternetwork.target [Service] Typeoneshot ExecStart/usr/local/bin/boot-report.sh RemainAfterExityes [Install] WantedBymulti-user.target把服务文件放到/etc/systemd/system/boot-report.service然后systemctl daemon-reload systemctl enable --now boot-report.service systemctl status boot-report.service这段代码有几个坑点ExecStart必须是绝对路径且脚本要有可执行权限Typeoneshot表示这是一个执行完就退出的任务配合RemainAfterExityes让服务在完成操作后仍然显示active状态每次修改.service文件后一定要执行daemon-reload否则systemd还在用旧配置。判断服务是否真的在启动阶段执行过不要只看状态去看journalctl -u boot-report.service -b启动日志白纸黑字。4.2 cron定时任务系统cron和用户crontab怎么选定时任务也是高频考点。做法上有区别系统级管理任务推荐放在/etc/cron.d/下格式里要写明用户用户级任务则用crontab -e去维护。两者背后的调度机制虽然都是cron但管理位置和用户维度不同验收时查的位置也不同。我当时的项目需求大概是这样每天2点30分以root身份清理临时文件。这个属于系统级任务放/etc/cron.d/cat /etc/cron.d/cleanup EOF 30 2 * * * root /usr/local/sbin/clean-tmp.sh EOFcron的五个时间字段顺序是分、时、日、月、星期写的时候别记错。用户级任务则不同不需要写用户名而是直接用crontab工具管理crontab -u alice -e # 内容示例每天8点执行一次 0 8 * * * /home/alice/daily-report.sh验证定时任务时有个小技巧正式项目里你不可能等上好几个小时才看到结果。调试阶段我会临时把时间改成下一分钟比如现在是14:05就写成5 14 * * *等确认跑通了再改成正式时间。这个习惯帮我少熬了很多夜。另外别忘了crontab -l查看当前用户的任务列表验收时经常用。4.3 journalctl与日志验证不只是看有没有报错服务和定时任务都配置完后一定要用日志验证而不是只看“状态是active”。systemd的日志中心是journald查服务的启动记录非常方便journalctl -u boot-report.service -b journalctl -u boot-report.service --since 10 minutes ago-b表示只看本次启动的日志能把系统里历史遗留的干扰项过滤掉。查cron任务执行情况则可以看/var/log/cron如果脚本没执行先看日志里有没有调度记录再手动执行脚本排除脚本自身问题。这一个简单的排查思路能帮你把“任务没跑”这个问题切成两半是调度器没触发还是脚本跑失败。自己写的日志文件也建议配上logrotate轮转策略在/etc/logrotate.d/下放一个独立配置按天或按大小切分防止日志无限增长把磁盘撑满。这个属于加分项但结课项目里做过和没做过给验收者的印象完全不一样。有同学把自己的脚本输出写进系统日志目录却没有配置轮转结果一个晚上生成了好几个G的文件磁盘直接爆掉。日志管理看起来不起眼实际上是最有生产味道的细节。5. firewalld与SELinux安全两件套的正确打开方式5.1 firewalld最小开放原则防火墙模块只要踩过一次坑你就再也不敢忘--permanent。firewalld的工作方式是分运行时和永久两种配置规则要求永久生效时必须在命令里加--permanent操作完还要--reload把永久配置加载到运行时。我做的第一件事是启动firewalld然后按“最小开放”原则逐个添加服务systemctl enable --now firewalld firewall-cmd --permanent --add-servicessh firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --add-servicenfs firewall-cmd --permanent --add-servicemountd firewall-cmd --permanent --add-servicerpc-bind firewall-cmd --reload firewall-cmd --list-all加NFS服务时尤其要提醒NFS除了2049端口还涉及rpcbind和mountd组件。如果只开2049客户端showmount -e还是会失败。这也是为什么我把它拆成多个服务逐一添加。项目验收时最常出现的问题就是“我明明加了规则为什么还是不通”十有八九是少开了一个服务或者改了规则没reload。另一个容易忽略的点是--add-service修改的是默认zone验收时用firewall-cmd --list-all看看默认zone是不是你期望的那一个避免规则加到了别的zone上。5.2 SELinux模式下如何不摔跟头RHCSA结课项目对SELinux的要求一般是保持Enforcing并且能正确放行服务。很多同学一遇到权限问题就想关SELinux这是最不可取的做法。你真正要做的是理解SELinux的强制访问机制学会给进程和文件打上正确的上下文标签。举一个最常见的场景默认目录放不下管理员把网站数据放到/srv/webapp启动httpd后却一直403。如果只看文件和目录权限一切正常因为问题根本不在ACL而在SELinux上下文。正确的做法是给这个自定义路径添加类型标签规则semanage fcontext -a -t httpd_sys_content_t /srv/webapp(/.*)? restorecon -Rv /srv/webapp如果系统提示semanage命令不存在先安装对应的工具包配置完标签再回头做存储和服务的验证。semanage fcontext是向SELinux的策略数据库里注册规则以后即使执行restorecon恢复文件标签这条规则仍然有效。如果只用chcon临时改标签当时能访问一旦系统运行restorecon或文件系统重置标签又被改回去问题复发。项目里重点考察的是你懂不懂这个区别。除了文件上下文布尔值也是一大考点。比如允许httpd访问NFS目录需要打开httpd_use_nfsgetsebool -a | grep httpd setsebool -P httpd_use_nfs on-P表示持久化重启后依然生效。用getsebool先查再改是避免瞎猜的有效方式。查看文件当前上下文可以用ls -lZ很多权限问题一眼就能看出类型标签对不对。5.3 NFS/HTTP场景排障实录从denied日志到问题定位这一节我用自己的真实排障过程来演示。项目验收时我发现客户端访问服务器上的网页服务返回403而首页文件明明存在、权限也是644。我首先排除了权限和防火墙接着去看SELinux日志ausearch -m avc -ts recent sealert -a /var/log/audit/audit.logausearch能快速过滤出最近的AVC拒绝记录sealert则会给出比较人性化的解决方案提示。日志里显示/srv/webapp的类型是default_t而httpd进程期望的是httpd_sys_content_t。这就直接对上了前面说的SELinux上下文问题。我执行了semanage fcontext加restorecon刷新页面立即正常。另一类与NFS相关的问题是布尔值。比如httpd要为NFS上的某目录提供下载服务即使文件标签对了如果httpd_use_nfs是off依然会被拒绝。这种问题在日志里也能看到但因为NFS的SELinux上下文跨越网络文件系统很多人会绕很远的路。我的经验是排障顺序固定为防火墙规则 → SELinux日志 → 文件上下文 → 布尔值每一步都用命令验证不要凭感觉这样能少走大量弯路。遇到denied日志先读它给出的源类型和目标类型再决定改哪个方向不要急着chmod 777绕过问题。6. 验收脚本复盘与给后来者的硬核建议6.1 写一份验收脚本把“我觉得没问题”变成“它确实没问题”结课项目验收时考官不可能一条条手敲命令去查更多时候会用一个验收脚本批量检测。与其被动等脚本跑出来再修不如自己提前写一份差不多的脚本自测。我当时的脚本长这样#!/bin/bash fail0 for u in alice bob carol; do id $u /dev/null 21 || { echo FAIL: user $u missing; fail1; } done getent group finance || { echo FAIL: group finance missing; fail1; } mountpoint /srv/webdata /dev/null || { echo FAIL: /srv/webdata not mounted; fail1; } systemctl is-active nfs-server /dev/null 21 || { echo FAIL: nfs-server inactive; fail1; } firewall-cmd --list-services 2/dev/null | grep -q http || { echo FAIL: http service not open; fail1; } restorecon -nRv /srv/webapp 21 | grep -q restore { echo FAIL: SELinux context incorrect; fail1; } exit $fail写脚本的过程本身就是一次全盘复习因为你要把每个验收点翻译成可执行的检查命令。比如检查SELinux上下文正确性用restorecon -nRv配合grep restore来判断是否“需要恢复”而不是简单的ls -lZ看标签。如果restorecon真的输出了“restore”字样说明有标签需要修复就标记失败。脚本跑一遍所有功能模块的“体检报告”都在手上。6.2 做结课项目时我踩过的坑现在一条条提醒你以下这些坑我几乎都踩过有的还踩了不止一遍整理出来供你提前绕开。第一fstab里的UUID手抄抄错。这不是技术问题是注意力问题。我后来一律从blkid输出直接复制绝不手打。第二忘了autoconnect。nmcli con mod之后不重启看不出来以为没问题结果一重启网络就没了。配置完必查connection.autoconnect的值。第三想给XFS缩容。XFS设计上只能扩容遇到“缩小逻辑卷”需求要确认文件系统类型再设计方案否则折腾半天全是白工。第四firewalld规则忘了--permanent。改完当时有用一 reload 就回到解放前。确认规则要两步先带--permanent改再--reload最后--list-all验证。第五只检查目录权限不看setgid实际效果。必须用真实用户去touch一个文件确认文件属组是组而不是用户。光看权限位验收脚本一检查新文件就露馅。第六autofs配完没启动服务。挂载点看起来空空的白白排查了半天导出配置。先systemctl status autofs再做其他检测。第七SELinux用chcon改标签后没有注册规则。当时能访问过几天或做restorecon后又坏了教训是“要想长久就用semanagerestorecon”。这些问题看起来都不复杂但每一个都能让项目验收当场翻车。我自己就是在踩完这些坑之后才真正理解了“系统管理是门实践科学”这句话。6.3 个人复盘什么样的练习方式对RHCSA最有效如果让我总结结课项目做得最值得的几件事我不会说是具体某个命令或某个配置而是三个习惯。第一个习惯是“先规划后动手”。每次动手前把需求拆成状态和动作目标状态是什么、当前状态是什么、中间有哪些操作路径。这样做的好处是出问题时你很清楚自己在哪一步而不是满系统乱试。第二个习惯是“改完就想怎么验证”。配置网络要重启验证配置fstab要重启验证配置SELinux要访问服务验证。如果你改完只是看一眼配置文件就继续那和没改没什么区别。验证本身就是把配置和实际行为挂钩的过程没有验证的配置只能算半成品。第三个习惯是“用手敲而不是复制粘贴”。复制粘贴看起来效率高但命令一旦报错你连上下文都不清楚手敲虽然慢却会逼着你想清楚每个参数的含义。我很多知识点都是结课项目前那几天手敲命令敲扎实的。最后再分享一点个人体会。结课项目的验收报告交掉那一刻我记住的不是“我通过了”而是“我知道这台机器的每一个配置为什么要这样写”。“知道为什么”和“能敲出来”之间隔着一整条运维习惯的距离。希望这份复盘能帮你少走一点弯路早点跨过那条距离。