CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Linux 服务器入门/课时/综合练习
RawBlame
课时目录12 节

Linux 服务器入门

  1. 01Linux 是什么
  2. 02Shell 与 Bash
  3. 03文件系统与权限
  4. 04常用命令
  5. 05编辑器与配置
  6. 06进程与服务
  7. 07用户与 sudo
  8. 08包管理
  9. 09SSH 与密钥
  10. 10防火墙与端口
  11. 11部署 CodeRoadMap
  12. 12综合练习

综合练习

从零排查 502 与端口占用。

40 分钟

综合练习

这一课你将能做到

  1. 按固定顺序独立排查四类生产故障:502、端口占用、Permission denied、磁盘打满,全程说出「命令依据」
  2. 完成「从裸机到上线」的 15 分钟全流程演练:装环境 → 配服务 → 开门 → 验收,一次通过
  3. 产出一份自己的《上线/排障检查单》(≤10 条),并完成一次限时故障演习(15 分钟内定位根因)

为什么要学

单课会命令不等于会运维。生产故障从不单挑:磁盘满引发 MySQL 写失败,MySQL 超时引发 API 5xx,5xx 期间你重启了应用导致配置错乱——故障是链式的,慌乱会毁掉证据。若每次都靠「重装面板/重启整机」,日志没了、根因永远查不到,下次同样慌。

本课把 intro 到 deploy 十二课串成肌肉记忆:四个故障场景(每个都来自真实运维),一次全流程上线演练,最后固化成检查单。练的是冷静的顺序,不是运气。

先建立图像

排障总图:先分层,再下钻

访客报障
  │
  ├─ 1. 应用层   curl 本机端口(3000/8080)      上游活吗?接口健康吗?
  ├─ 2. 进程层   ss / pm2 list / systemctl     进程在吗?谁在监听?
  ├─ 3. 反代层   nginx -t + error.log          转发写对了吗?
  ├─ 4. 资源层   df -h / free -h / top         磁盘/内存/CPU 有没有爆?
  ├─ 5. 权限层   ls -l + 进程用户对照          读得到文件吗?写得了日志吗?
  └─ 6. 门禁层   ufw status + 云安全组          门开对了吗?监听地址对吗?

顺序的意义:从应用层往下查,因为报障最常见的原因就是上游死了;每层都有「快刀」,30 秒内能定性。记住一句行话:先止血,再查因;证据在日志里,别用重启毁掉它。

跟着做

场景一:502 全流程(主推场景,务必走完整遍)

制造故障(实验环境):

pm2 stop platform 2>/dev/null            # 或 sudo systemctl stop coderoadmap-backend
# 浏览器访问首页 → 502

标准排查链(每步解释现象):

# A. 上游还活着吗?(应用层)
curl -s -o /dev/null -w "front:%{http_code}\n" http://127.0.0.1:3000/    # 000=死
curl -s http://127.0.0.1:8080/actuator/health; echo

# B. 进程与监听(进程层)
pm2 list
sudo ss -tlnp | grep -E ':(3000|8080)\s'      # 没有监听=没人服务

# C. Nginx 怎么说?(反代层)
sudo tail -20 /var/log/nginx/error.log | grep -i upstream
# connect() failed (111: Connection refused) while connecting to upstream → 印证 A 的结论

# D. 修复 + 验活
pm2 start platform
curl -s -o /dev/null -w "front:%{http_code}\n" http://127.0.0.1:3000/    # 200

解释题(写进笔记):若 A 中 3000 失败而 8080 正常,502 的是首页还是 /api/?为什么?

场景二:Address already in use(端口占用)

# 制造:用 python 占住 8080
python3 -m http.server 8080 &          # 记下回显的 PID
# 此时重启后端 → journalctl 会看到 Web server failed to start. Port 8080 was already in use.

sudo ss -tlnp | grep 8080              # 定位:谁占的(进程名+PID)
ps -p <PID> -o user,pid,etime,cmd      # 是谁、跑了多久、什么命令

# 处置分流:
# 旧实例没杀干净 → 停它:
sudo systemctl restart coderoadmap-backend
# 是别的服务占的 → 改自己端口(--server.port=8081)而不是杀别人
# 杀掉本场景的实验占用者:
kill %1 2>/dev/null || kill <PID>

原则:端口唯一,占者未必是错误方。先确认身份再动手,多实例机器上 pkill -f java 级别的命令是禁区。

场景三:Permission denied(文件课/用户课联动)

# 制造:把日志目录属主改成 root(模拟 root 手滑上传后 chown 漏做)
sudo chown -R root:root /www/wwwroot/coderoadmap/logs
sudo systemctl restart coderoadmap-backend
journalctl -u coderoadmap-backend -n 20 --no-pager | grep -i denied
# → Permission denied: /www/wwwroot/coderoadmap/logs/... (或 logback 初始化失败)

# 排查三步:
systemctl show coderoadmap-backend -p User      # ① 进程是谁
ls -ld /www/wwwroot/coderoadmap/logs            # ② 目录归谁、权限几位
sudo -u www touch /www/wwwroot/coderoadmap/logs/.t && echo OK   # ③ 以进程身份复现

# 修复 + 验活:
sudo chown -R www:www /www/wwwroot/coderoadmap/logs
sudo systemctl restart coderoadmap-backend && sleep 12
curl -s http://127.0.0.1:8080/actuator/health; echo

场景四:磁盘打满(命令课 df/du 实战)

# 制造(造一个 1.5G 的大文件模拟失控日志):
df -h / | tail -1                       # 先记下当前可用
sudo fallocate -l 1500M /www/wwwroot/coderoadmap/logs/backend.log.huge

df -h /                                 # 观察骤降;真满时 MySQL 写失败 → API 5xx

# 定位元凶:从根下钻
sudo du -xh /www 2>/dev/null | sort -rh | head -10
sudo du -sh /var/log /tmp 2>/dev/null

# 处置:日志类直接清空(不 rm 正被写的文件!)
sudo truncate -s 0 /www/wwwroot/coderoadmap/logs/backend.log.huge
sudo rm /www/wwwroot/coderoadmap/logs/backend.log.huge   # 无进程占用才 rm
df -h / | tail -1                       # 恢复

# 预防:日志轮转(logrotate 一份配置管到底)
sudo vim /etc/logrotate.d/coderoadmap
# /www/wwwroot/coderoadmap/logs/*.log {
#     daily
#     rotate 7
#     compress
#     missingok
#     notifempty
#     copytruncate
# }
sudo logrotate -d /etc/logrotate.d/coderoadmap    # -d 干跑验证语法

演练二:从裸机到上线(15 分钟计时)

新开一台按量付费实例(或重置的 WSL),纯命令走完主链——计时,目标 ≤15 分钟:

# 1) 环境(包管理课) ~3min
sudo apt update && sudo apt install -y openjdk-17-jdk-headless nginx mysql-server curl
java -version && systemctl is-active mysql nginx

# 2) 目录与身份(文件/用户课) ~2min
sudo useradd -r -s /usr/sbin/nologin www 2>/dev/null || true
sudo mkdir -p /www/wwwroot/coderoadmap/{logs,releases}
sudo chown -R www:www /www/wwwroot/coderoadmap

# 3) 产物与 systemd(SSH/进程课) ~4min
scp 本机JAR test:/tmp/app.jar && sudo mv /tmp/app.jar /www/wwwroot/coderoadmap/backend.jar
# 写入单元文件(deploy 课模板)→ daemon-reload → enable --now → curl health

# 4) 门禁(防火墙课) ~2min
sudo ufw allow OpenSSH && sudo ufw allow 80,443/tcp && sudo ufw enable
# 应用绑 127.0.0.1(server.address)→ restart → ss 验证监听地址

# 5) 验收(deploy 课清单) ~2min
curl -s -o /dev/null -w "%{http_code}\n" http://localhost/          # Nginx 通
sudo ss -tlnp | grep -E ':(80|8080)\s'                              # 0.0.0.0:80 / 127.0.0.1:8080

练完把卡住的步骤标红——那就是你要回炉的课。

演练三:定稿《个人上线/排障检查单》

把下面模板抄进自己的笔记仓库,改成本项目的真实路径与单元名:

【上线检查单】
□ 1. cat /etc/os-release          确认系统与包管理器
□ 2. java -version / node -v      运行时版本对齐
□ 3. chown www:www + chmod 校对   产物与日志目录权限
□ 4. systemctl enable --now       服务托管 + 开机自启
□ 5. curl 127.0.0.1:8080/health   上游健康
□ 6. ss -tlnp                     0.0.0.0 只剩 80/443
□ 7. ufw status + 云安全组        双层门禁同源
□ 8. nginx -t && reload           反代生效
□ 9. 公网 curl 首页 + /api/       全链路 200
□ 10. releases/ 留有上一版本       回滚就绪

【502 排障顺序】curl 本机上游 → ss 监听 → pm2/systemctl 状态
                → nginx error.log → journalctl → df -h(磁盘连锁)

演练四:限时故障演习(自测)

让同伴(或用 cron 随机)制造一个故障:pm2 stop platform / chown root logs / fallocate 占磁盘 / python 占端口 四选一。你的目标:15 分钟内用检查单定位根因并恢复,同时说出「命令依据」。全程禁止重启整机、禁止重装。

# 起手三连(任何故障的第一分钟):
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/ http://127.0.0.1:8080/actuator/health
sudo ss -tlnp | grep -E ':(80|443|3000|8080|3306)\s'
df -h / && free -m | head -2
# 三条命令覆盖:应用层 + 进程层 + 资源层,60% 的故障在此定性

讲清楚要点

  1. 因为报障大多源于上游,所以第一刀永远是 curl 本机端口——30 秒内把「Nginx 问题」和「应用问题」切开,比打开宝塔看红点高效十倍。
  2. 因为日志是唯一的时间机器,所以禁止先重启毁证——journalctl --since 锁故障时间窗、nginx error.log 看上游拒绝、应用日志看异常堆栈。重启只能发生在有回滚保障的发布里。
  3. 因为端口唯一,所以端口冲突的解法是「确认身份」而非「互相残杀」——ss 定位 → ps 看身份 → 要么停旧要么改配置,pkill java 是多实例环境的自爆按钮。
  4. 因为权限判断者是进程,所以 Permission denied 的解法是「身份对齐」而非 777——进程用户查 systemctl show User,目录属主查 ls -ld,sudo -u 复现验证,chown 收尾。
  5. 因为磁盘是硬限制,所以 df 必须进每张检查单——日志轮转(logrotate)是预防,truncate 清被占用文件是急救,rm 只留给无进程占用的文件。
  6. 因为故障是链式的,所以要把「分层排查」练成本能——应用 → 进程 → 反代 → 资源 → 权限 → 门禁,每层一把快刀;查不到就说明「问题在你以为的层之外」,回到总图换个方向。

你可能会懵的地方

  • 本机 curl 全 200,公网还是 502? 问题在「外面」:Nginx 的 upstream 指向了别的机器/别的端口、HTTPS 证书配置与 HTTP 混淆、云上还有一层 LB/CDN 在报 502。curl -I 看响应头里 server 字段是谁;nginx -T | grep proxy_pass 核对真实生效配置。
  • journalctl 里查不到我的服务? 说明进程不是 systemd 托管(nohup/宝塔自定义/PM2 起的)。分流:PM2 用 pm2 logs;宝塔 Java 项目看它面板里配置的日志路径;nohup 的去你重定向的那个文件。先问「谁在管家」,再找对应的日志源。
  • kill 会不会丢数据? 分对象:无状态 Web 进程(Java/Node)kill -15 几乎无损(Spring Boot 优雅停机兜底);数据库进程严禁 kill -9(InnoDB 有崩溃恢复但代价是慢和吓人)。规范顺序永远先 systemctl stop。
  • 练习环境没有完整 CodeRoadMap 怎么办? 用替身练「顺序」:python3 -m http.server 8080 当后端、python3 -m http.server 3000 当前端,Nginx 照常反代——502/端口/权限/磁盘四个场景全部可复现。工具不重要,流程才是肌肉。
  • 检查单要多久更新一次? 每次真实故障后追加一条「这次踩的坑」;每次架构变化(换面板/上 Docker/多机)重审一遍。检查单是活文档,三个月不动的检查单等于没检查单。

错法对照

错法问题正解
一见 502 就重装系统/面板毁掉全部日志证据固定 A→B→C 顺序,先定性再动手
不确认 PID 直接 killall java误杀同机其他服务ss + ps 定位 → systemctl 精准操作
忽略 df -h把磁盘满误判成代码 bug起手三连必含 df;检查单固化
只看面板「运行中」绿灯假活:进程在但接口 5xxcurl 业务健康接口才算数
改配置不留记录不备份无法回滚,越修越乱cp x x.bak + 变更写进笔记
修完不做全链路验证「我这里好了」≠用户好了公网 curl 首页 + /api/ 双验收
排障时疯狂 restart 刷日志真实报错被淹在启动日志里一次失败取足证据,修好再一次启动

卡点急救

  1. 故障演习卡住超时:回到「起手三连」重新定性——大多数卡死是因为跳层(没 curl 本机就去改 Nginx)。把每一步的「预期输出」写下来对照,偏差处即问题层。
  2. Nginx error.log 权限不够读不了:sudo tail -50 /var/log/nginx/error.log。若你是 deploy 用户且无 sudo,向管理员要 sudo 白名单(用户课的 NOPASSWD 可加 tail 场景)。
  3. 造的故障恢复不了(服务怎么都起不来):回到 deploy 课的分层排查——单元文件路径/ExecStart 绝对路径/端口占用/DB 连通性四查;极端情况 journalctl -u xxx -n 200 一定写明了失败原因,service 没骗你。
  4. 检查单写不出来:把本课演练记录原文抄一遍再删减——「现象 → 命令 → 结论」三列格式,先抄后改,别追求一次完美。

面试常问

  • 线上服务 502,描述你的完整排查过程。 分层:① curl 127.0.0.1 上游端口(区分应用死/Nginx 错);② ss -tlnp + pm2/systemctl status 看进程与监听;③ tail nginx error.log 找 upstream 拒绝;④ journalctl -u 服务 看临终日志;⑤ df -h 排除磁盘连锁(MySQL 写失败→API 挂→502);⑥ 核对最近发布(是否半发布:传了没重启/多机发错台)。修复后公网双验收。关键表达:顺序固定、每步有判据、先止血再查因。

  • 磁盘使用率 100% 时你的处理流程? 立即止血:定位最大可清项(du -xh / | sort -rh | head),日志类 truncate -s 0(不 rm 被占用文件),确认 MySQL 等核心服务恢复写入。根治:logrotate 轮转、备份迁移、清理旧镜像/旧安装包。复盘:监控告警阈值(80% 预警)+ 扩容评估。

  • 如何证明「新版本」真的生效了? 四证据:ls -lt releases/ 新文件落位时间;软链指向(readlink backend.jar);systemctl status 的 ActiveEnterTimestamp 在发布时间之后;健康接口返回的新版本号(actuator/info 或响应头 X-Version)。浏览器再 Ctrl+Shift+R 排除缓存。四者齐了才说「上线完成」。

  • 生产事故复盘里你贡献过什么? 用 STAR 讲一个:S(现象:API 大面积超时)T(我的职责:Linux 层排查)A(做了什么:df 发现日志撑爆磁盘,truncate 止血 + logrotate 根治)R(结果:5 分钟恢复,之后 30 天零复发)。面试官考察的是流程化思维与证据意识,不是运气好。

  • 怎么评价一台你从没接触过的服务器的健康状况? 五分钟体检单:cat /etc/os-release(系统)、uptime(负载与重启史)、free -h / top(内存与 CPU)、df -h(磁盘)、ss -tlnp(暴露面)、systemctl --failed(失败单元)、journalctl -p err --since today(今日错误)、last | head(登录审计)。输出一份「哪里异常 + 建议动作」清单——这就是检查单思维的浓缩版。

自测三问

  1. 写出 502 排查前四步的命令(含每步的「判据」:看到什么算什么病)。
  2. 「scp 成功但用户看到的还是旧版本」可能漏了哪些环节?按概率排序。
  3. 为什么 Permission denied 不应该第一反应 chmod 777?给出规范修复路径的命令序列。

小结一句话

运维能力的分水岭不在命令量,而在顺序:起手三连定性、分层排查下钻、证据先于动作、检查单固化经验——十二课的所有命令,最终都服务这张排障总图。

延伸

  • Nginx 官方 — 调试日志
  • logrotate 官方手册
  • 本 track 下一站:nginx-essentials(把反代这门课学成专家)、docker-essentials(部署的容器化解法)、github-actions-essentials(把本课的发布脚本自动化进 CI)。
加载本节练习…
← 上一课部署 CodeRoadMap