首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
【FDE系列】阶段2:Day 39:Linux 综合实战 — 让服务无人值守
📅 2026/10/24 5:23:53
✍️ 爱科研究院
👁 阅读 3,247
前言FDE系列内容总纲【大纲】FDE 前沿部署工程师学习系列教程-CSDN博客前置课程列表见文档结尾附录。阶段2·Day 39Linux 综合实战 — 让服务无人值守FDE 学习系列教程 · 第二阶段 · 第 4 周 · Day 4预计时长2.5 小时 | 难度★★★☆☆ | 前置知识Day 36-38 全部内容一句话目标用 nohup / screen 让 FastAPI 后台常驻用 tail -f 盯日志用 crontab 配置定时备份和健康检查实现服务挂了自动重启。 开场你不可能 24 小时守着终端先想一个问题你的 FastAPI 现在是怎么跑的uvicorn main:app --reload它占着当前终端窗口——窗口一关、SSH 一断、电脑一锁屏服务立刻没了。这在开发时没问题但在客户现场是致命的客户的系统得 7×24 小时跑着你总不能让一台电脑永远开着一个黑窗口、还不许碰。今天解决四件事让服务具备无人值守能力┌────────────────────────────────────────────────────────┐ │ ① 后台常驻关终端/断 SSH服务照样跑nohup/screen │ │ ② 实时盯日志服务在后台干了啥随时能看tail -f │ │ ③ 定时任务备份/巡检到点自动执行crontab │ │ ④ 自愈服务挂了健康检查脚本自动重启 │ └────────────────────────────────────────────────────────┘这就是把一个开发模式的程序变成服务器上常驻服务的关键一步。下周学 Docker 之前先用最朴素的方式体验一遍部署这件事。 一、先理解为什么关终端程序就会死要理解 nohup先得知道一个概念——信号Signal。而nohup的字面意思就是no hangup别挂断——让程序忽略 SIGHUP 信号终端关了它也装作没听见继续跑。️ 二、nohup让服务后台常驻准备确保项目就绪cd ~/fde_project ls # main.py venv/ source venv/bin/activate确保main.py里有/health接口健康检查要用最小版本from fastapi import FastAPI import uvicorn app FastAPI() app.get(/) def root(): return {msg: FDE API running in background} app.get(/health) def health(): return {status: ok} if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)一条命令后台启动nohup uvicorn main:app --host 0.0.0.0 --port 8000 app.log 21 别看这一行短每个符号都有讲究逐个拆解nohup 忽略挂断信号关终端不死 uvicorn main:app --host 0.0.0.0 --port 8000 你的服务命令 app.log 标准输出(1)写进 app.log 21 错误输出(2)合并到标准输出(1) → 正常日志和报错都进 app.log 扔到后台运行终端立刻还给你敲完回车你会看到类似[1] 9876 ← [1]是后台任务号9876 是进程 PID nohup: ignoring input and redirecting stderr to stdout终端立刻可以继续用了——服务在后台跑着。验证服务真的活着# ① 用 curl 访问 curl http://localhost:8000/ # {msg:FDE API running in background} curl http://localhost:8000/health # {status:ok} # ② 查进程 ps aux | grep uvicorn | grep -v grep # fde 9876 ... uvicorn main:app --host 0.0.0.0 --port 8000 # ③ 看日志 cat app.log终极测试关掉这个终端窗口直接关掉Ubuntu 窗口然后重新开一个ps aux | grep uvicorn | grep -v grep # 进程还在 curl http://localhost:8000/health # 服务照样响应 # {status:ok}这就是后台常驻。这一步成功你会真切体会到部署和开发运行的区别。停止后台服务# 找到 PID 再 kill标准做法 ps aux | grep uvicorn | grep -v grep kill 9876 # 或者一条命令按名字杀 pkill -f uvicorn main:app # 确认端口释放 ps aux | grep uvicorn | grep -v grep # 没输出 已停止 三、screen给服务开一个关不掉的房间nohup 有个缺点服务扔后台后你没法再回到它的交互界面。screen 解决了这个问题——它能创建一个可以随时进出的终端会话。┌────────────────────────────────────────────────────┐ │ screen 就像一个独立的终端房间 │ │ │ │ 你走进房间启动 uvicorn │ │ 按 CtrlA, D 暂时离开房间detach服务继续跑 │ │ 关电脑/断网都不影响房间里的程序 │ │ 随时 screen -r 回到房间服务的画面原封不动 │ └────────────────────────────────────────────────────┘ 对比 nohup nohup 把程序扔后台只能通过日志文件看输出 screen 程序在房间里跑随时能推门进去看实时界面安装与使用sudo apt install -y screen # ① 创建一个名叫 fde_api 的会话并进入 screen -S fde_api # 屏幕会清一下你已经在房间里了正常启动服务前台方式即可 cd ~/fde_project source venv/bin/activate uvicorn main:app --host 0.0.0.0 --port 8000 # ② 脱离会话先按住 CtrlA松开再按一下 D # detach。你回到了原始终端但服务还在房间里跑 # 底部会提示[detached from 9876.fde_api] # ③ 查看当前有哪些会话 screen -ls # There is a screen on: # 9876.fde_api (09/18/26 15:00:00) (Detached) # ④ 重新进入会话resume screen -r fde_api # 你会看到 uvicorn 的实时输出画面跟离开时一模一样 # ⑤ 彻底结束会话进入后 CtrlC 停掉服务再输入 exit # 或者从外部直接杀掉screen -X -S fde_api quit选 nohup 还是 screen场景推荐就想让服务安静地跑输出全进日志nohup简单配日志文件足够需要随时回去看程序的实时交互界面screen要同时挂多个需要观察的任务开多个 screen 会话命名区分生产环境长期稳定运行systemd 服务更正规本系列后续阶段讲 FDE 在客户现场临时部署、跑长任务数据迁移、批量脚本screen 极其常用——断 SSH 不怕重连screen -r接着看。今天 nohup 和 screen 都会用即可。️ 四、tail -f实时盯后台日志服务进了后台怎么知道它在干嘛、有没有报错不能 cat 一下看一下得用实时追踪tail -f app.log # 屏幕停住不动app.log 一旦有新内容立刻刷出来 # 新开另一个终端 curl 几次接口这边能看到请求日志实时滚动 # CtrlC 退出追踪只退出查看不影响服务tail -f 的进阶组合# 只盯着错误看管道过滤 tail -f app.log | grep ERROR # 同时盯错误和警告-E 正则 tail -f app.log | grep -E ERROR|WARNING # 先看最后 50 行再继续实时追踪 tail -n 50 -f app.log # 同时追踪多个日志文件 tail -f app.log backup.log 排障标准动作记住服务后台跑着 → 新开终端tail -f app.log→ 另一个终端复现操作 → 实时观察日志输出。两个终端配合问题无所遁形。 五、crontab让任务到点自己跑备份脚本写好了难道每天凌晨 2 点爬起来手动敲当然不用。crontab是 Linux 内置的定时任务调度器你写好时间表它到点自动执行。crontab 基本命令crontab -e # 编辑当前用户的定时任务表第一次会让你选编辑器选 nano 即可 crontab -l # list查看当前所有定时任务 crontab -r # remove清空所有定时任务⚠️ 慎用cron的特殊符号符号含义例*任意值* * * * *每分钟,枚举0,30 * * * *每半点-范围0 9-18 * * *9~18 点整/步长*/10 * * * *每 10 分钟特殊字符串快捷写法字符串等价于reboot开机启动时执行一次hourly0 * * * *daily0 0 * * *weekly0 0 * * 0monthly0 0 1 * *yearly0 0 1 1 *cron 时间表的五颗星这是 cron 的核心语法一条任务长这样┌───────── 分钟 (0-59) │ ┌─────── 小时 (0-23) │ │ ┌───── 日 (1-31) │ │ │ ┌─── 月 (1-12) │ │ │ │ ┌─ 星期 (0-70和7都是周日) │ │ │ │ │ * * * * * 要执行的命令对着例子理解最快0 2 * * * 每天凌晨 2:00 整 */5 * * * * 每 5 分钟 30 8 * * 1-5 每周一到周五的 8:30 0 */2 * * * 每 2 小时0点、2点、4点... 0 0 1 * * 每月 1 号的 0:00 30 9 * * 6 每周六上午 9:30 * * * * * 每分钟调试时临时用┌────────────────────────────────────────────────────────┐ │ 符号速查 │ │ * 每一每个时间单位都匹配 │ │ */5 每隔 5能整除时触发 │ │ 1,3,5 枚举第1、3、5 │ │ 1-5 范围1 到 5 │ └────────────────────────────────────────────────────────┘配置两个实战定时任务先把昨天的备份脚本放到固定位置并确保有执行权限chmod x ~/fde_lab/backup.sh mkdir -p ~/backups ~/logs执行crontab -e在文件末尾加入# 每天凌晨 2:00 备份 fde_project日志追加到 backup.log 0 2 * * * /home/fde/fde_lab/backup.sh /home/fde/fde_project /home/fde/backups /home/fde/logs/backup.log 21 # 每 5 分钟做一次服务健康检查health_check.sh 下一节写 */5 * * * * /home/fde/fde_lab/health_check.sh /home/fde/logs/health.log 21保存退出nanoCtrlO 回车保存CtrlX 退出看到crontab: installing new crontab就生效了。crontab -l # 确认任务已写入cron 的三个血泪坑⚠️坑 1命令必须用绝对路径cron 执行时没有你登录后的 PATH 环境uvicorn、python3这些命令可能找不到。所以脚本路径写全/home/fde/fde_lab/backup.sh不能写./backup.sh脚本内部用到的命令也尽量写绝对路径或在脚本开头加source ~/.bashrc/ 手动设 PATH⚠️坑 2输出一定要重定向到文件cron 任务没有终端输出没地方去有些系统会给你发本地邮件多数直接丢弃。务必像上面那样 xxx.log 21否则出了错你啥都看不到。⚠️坑 3cron 不会自动激活虚拟环境你的 uvicorn 装在 venv 里cron 直接调会找不到。健康检查/启动脚本里要先source /home/fde/fde_project/venv/bin/activate或直接用 venv 里的绝对路径/home/fde/fde_project/venv/bin/uvicorn。不用等到凌晨临时验证任务把备份任务临时改成*/2 * * * *每 2 分钟等两分钟后检查ls -lt ~/backups/ # 看是否生成了新备份包 cat ~/logs/backup.log # 看备份日志验证完记得改回0 2 * * *别让它每 2 分钟备份一次把磁盘塞满。️ 六、健康检查脚本服务挂了自动拉起来这是今天的综合产物。思路很朴素定时探测服务 → 活着就记一笔 → 连续探测失败就重启。新建health_check.sh#!/bin/bash # # 健康检查 自动重启脚本 # 由 crontab 每 5 分钟调用一次 # set -euo pipefail # ---------- 配置区 ---------- API_URLhttp://localhost:8000/health MAX_RETRY3 # 最多重试次数 WAIT_SECONDS10 # 每次重试间隔 PROJECT_DIR/home/fde/fde_project VENV_UVICORN/home/fde/fde_project/venv/bin/uvicorn # --------------------------- log() { echo $(date %Y-%m-%d %H:%M:%S) $1 } RETRY0 while [ $RETRY -lt $MAX_RETRY ]; do # curl -s 静默 -f HTTP 错误码也算失败输出丢进黑洞只看退出码 if curl -sf $API_URL /dev/null 21; then log ✅ 服务正常 exit 0 # 探测成功脚本结束 fi RETRY$((RETRY 1)) log ⚠️ 第 ${RETRY}/${MAX_RETRY} 次探测失败${WAIT_SECONDS} 秒后重试... sleep $WAIT_SECONDS done # 三次都失败判定服务挂了 → 重启 log 连续 ${MAX_RETRY} 次探测失败判定服务异常开始重启... cd $PROJECT_DIR # 先清理可能残留的旧进程防止端口占用 pkill -f uvicorn main:app 2/dev/null || true sleep 2 # 用 venv 里的 uvicorn 绝对路径后台启动 nohup $VENV_UVICORN main:app --host 0.0.0.0 --port 8000 \ app.log 21 sleep 5 # 等服务启动 # 重启后再验证一次 if curl -sf $API_URL /dev/null 21; then log 服务已成功重启并恢复正常 else log ❌ 重启后服务仍不可用需要人工介入 exit 1 fiset -euo pipefail严格模式让脚本遇错早退是健壮脚本的关键选项作用-e任何命令返回非 0 就立即退出-u使用未定义变量时报错退出-o pipefail管道中任一环节失败整条管道算失败注意后面多处用|| true显式忽略失败正是为了绕开-e。为什么要连续 3 次避免偶发抖动如一次 GC、瞬时高负载误触发重启。全部用绝对路径——因为 cron 环境PATH很精简相对路径会找不到。MAX_RETRY × WAIT_SECONDS 30 秒即单次 cron 运行最多容忍 30 秒不可用才重启。curl -sf参数含义关键参数作用-ssilent静默不输出进度条-ffailHTTP 状态码 ≥400 时返回非 0否则 500 也会被当成功配合 /dev/null 21丢弃输出只看退出码0健康非 0异常。循环逻辑探测成功 → 打 ✅exit 0结束不重启。失败 → 计数 1打 ⚠️sleep 10后重试。最多 3 次。注意第 3 次失败后仍会 sleep 10 秒再跳出循环轻微浪费但无害。为什么要重试 3 次而不是一次失败就重启探测失败 ≠ 服务一定挂了可能是 · 服务正在处理一个慢请求响应慢了 · 系统那一瞬间 CPU 繁忙 · 网络抖了一下 所以设计成连续 3 次、每次间隔 10 秒都失败才判定死亡 避免一次抖动就误杀好进程。这叫容错/防抖思想。实测自愈效果chmod x health_check.sh # ① 确保 cron 已配置*/5 那行或先手动跑一次验证脚本本身没问题 ./health_check.sh # 2026-09-18 15:10:00 ✅ 服务正常 # ② 模拟服务挂掉手动杀掉 uvicorn pkill -f uvicorn main:app curl http://localhost:8000/health # 已经连不上了 # ③ 立即手动跑健康检查不用等 5 分钟观察自愈全过程 ./health_check.sh # ⚠️ 第 1/3 次探测失败10 秒后重试... # ⚠️ 第 2/3 次探测失败10 秒后重试... # ⚠️ 第 3/3 次探测失败10 秒后重试... # 连续 3 次探测失败判定服务异常开始重启... # 服务已成功重启并恢复正常 # ④ 再验证 curl http://localhost:8000/health # {status:ok} 活了今天的完整部署全景 本课小结能力工具/命令关键点后台常驻nohup 命令 log 21 忽略 SIGHUP输出进日志 放后台会话管理screen -S 名/-r 名/ CtrlA,D创建/进入/脱离可恢复的终端房间看实时日志tail -f app.log配合 grep 只看错误停止服务pkill -f/kill PID先找进程再杀定时任务crontab -e/-l五颗星分 时 日 月 周备份定时0 2 * * * 脚本 log 21每天 2 点巡检定时*/5 * * * * 脚本每 5 分钟健康检查curl -sf URL看退出码失败重试 3 次再重启cron 三坑绝对路径/重定向/venv一个都不能忘 核心认知让服务无人值守靠的是一套组合拳——nohup/screen 解决不死日志解决可观测crontab 解决自动触发健康检查解决自愈。这正是生产环境运维思想的缩影虽然真正的生产环境会用 systemd/Docker/监控平台但核心逻辑今天你已经亲手实现了一遍。 课后练习练习 1nohup 后台验证约 20 分钟用 nohup 启动 FastAPI确认app.log生成、curl能访问关掉终端窗口重开后确认进程还在ps aux | grep用tail -f app.log在另一个终端实时看请求日志然后用 curl 打几次/health观察日志滚动用 pkill 停掉服务练习 2screen 会话约 15 分钟创建名为work的 screen 会话在里面运行top用 CtrlA,D 脱离screen -ls确认会话 Detachedscreen -r work回到会话确认 top 画面还在最后退出并关闭会话练习 3crontab 健康检查约 30 分钟配置 cron每分钟把当前时间追加到~/logs/min.log* * * * * date ~/logs/min.log等 2-3 分钟后tail验证验证后删除该任务配置每天凌晨 2 点的备份任务用crontab -l确认手动杀掉 uvicorn运行health_check.sh观察3 次重试 → 自动重启 → 恢复全过程并查看health.log 下节预告今天你的服务已经能后台常驻、定时备份、挂了自愈像个真正的服务器程序了。明天是本周收官把 Shell 脚本打磨到生产级set -euo pipefail严格模式为什么你的脚本明明出错了还傻乎乎往下跑trap 信号处理脚本被 CtrlC 打断时如何自动清理临时文件case 语句写一个./service.sh start|stop|status|restart这样的服务管理脚本一键掌控服务最后做本周总复习和验收。明天见附录前置课程列表阶段一认知启蒙AI 认知与 FDE 角色AI 认知【FDE系列】阶段1Day 1AI 层级关系 — 四个嵌套的圈-CSDN博客【FDE系列】阶段1Day 2AI 三阶段发展史 — 会认 → 会判断 → 会创造-CSDN博客【FDE系列】阶段1Day 3符号 AI vs 机器学习 — 两条路线的本质区别-CSDN博客【FDE系列】阶段1Day 4Transformer 的历史意义 — 2017 年的分水岭-CSDN博客【FDE系列】阶段1Day 5本周复习与自测 — 检验你的 AI 认知地基-CSDN博客【FDE系列】阶段1Day 6Transformer 架构 — 一张图纸盖出千千万万栋楼-CSDN博客【FDE系列】阶段1Day 7LLM 本质 — 文字接龙机器-CSDN博客【FDE系列】阶段1Day 8Token — 模型眼中的最小单位-CSDN博客【FDE系列】阶段1Day 9AI 幻觉 — 为什么会一本正经地胡说八道-CSDN博客【FDE系列】阶段1Day 10上下文窗口 — 模型的记忆力上限 本周复习-CSDN博客【FDE系列】阶段1Day 11Prompt — 给模型立规矩-CSDN博客【FDE系列】阶段1Day 12Memory — 让模型记住上下文【FDE系列】阶段1Day 13RAG — 给模型配图书管理员-CSDN博客【FDE系列】阶段1Day 14Tool Use — 让模型动手操作-CSDN博客【FDE系列】阶段1Day 15MCP — 统一的工具接口标准 第三周复习-CSDN博客FDE 基础概念【FDE系列】阶段1Day 16什么是 FDE — 把 AI 变成客户结果的人-CSDN博客【FDE系列】阶段1Day 17FDE vs 传统实施 — 三大本质区别-CSDN博客【FDE系列】阶段1Day 18FDE 三重身份 C6 胜任力模型-CSDN博客【FDE系列】阶段1Day 19七阶段行动路径 行业经验的价值-CSDN博客【FDE系列】阶段1Day 20阶段总结与产出物 — 第一阶段收官-CSDN博客阶段二技术地基Python FastAPI SQL Docker API 集成Python基础【FDE系列】阶段2Day 21Python 环境搭建 — 写出你的第一行代码-CSDN博客【FDE系列】阶段2Day 22变量、数据类型、条件判断 — Python 的“记忆“和“判断“-CSDN博客【FDE系列】阶段2Day 23循环与函数 — 让代码跑 100 遍、把逻辑打包复用-CSDN博客【FDE系列】阶段2Day 24数据结构 — 列表、字典、集合、元组-CSDN博客【FDE系列】阶段2Day 25文件读写与 JSON — 让程序连通外部数据第一周收官-CSDN博客【FDE系列】阶段2Day 26模块化编程 — 把代码拆成“抽屉柜“-CSDN博客【FDE系列】阶段2Day 27异常处理与日志 — 让程序“摔不烂、查得到“-CSDN博客FastAPI入门到进阶【FDE系列】阶段2Day 28FastAPI 入门 — 把你的函数变成 API 服务-CSDN博客【FDE系列】阶段2Day 29FastAPI 进阶 — Pydantic 模型与完整 CRUD 实战-CSDN博客【FDE系列】阶段2Day 30生产代码规范 — 测试、类型注解、配置管理第二周收官-CSDN博客SQL基础【FDE系列】阶段2Day 31SQL 基础 — 增删改查一把梭-CSDN博客【FDE系列】阶段2Day 32多表查询 — JOIN 与聚合-CSDN博客【FDE系列】阶段2Day 33进阶查询 — 窗口函数与 CTE-CSDN博客【FDE系列】阶段2Day 34数据清洗 — 把脏数据捋干净-CSDN博客【FDE系列】阶段2Day 35Python SQL — 工单接入 MySQL 本周收官-CSDN博客【FDE系列】阶段2Day 36Linux 入门与文件操作 — 扔掉鼠标的第一天-CSDN博客【FDE系列】阶段2Day 37权限、进程与文本三剑客-CSDN博客【FDE系列】阶段2Day 38Shell 脚本 — 把命令串起来自动跑-CSDN博客
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/24 5:23:53
2026 年 DTF 烫画机选购指南:宏彩 MC 系列机型深度评测与实战选型建议
2026/10/24 5:23:53
【FDE系列】阶段2:Day 38:Shell 脚本 — 把命令串起来自动跑
2026/10/24 5:23:53
Kafka请求分发器:completedReceives里的请求是怎么被处理的
2026/10/24 6:23:56
freehire Airswift 适配器设计解析:用“过期标记”把已关闭职位从“读不懂”中区分出来
2026/10/24 6:23:56
《普林斯顿微积分读本》PDF高效阅读指南:从零基础到应试全攻略
2026/10/24 6:23:56
土木本科生的 STM32 探索之旅:以物联网监测为起点(第一篇)
2026/10/24 6:23:56
简单EKF滤波算法的MATLAB软件仿真
2026/10/24 6:23:56
AXI总线详细完整介绍:AMBA AXI协议与FPGA实现
2026/10/24 6:18:55
MFC按钮不显示?深入解析CButton::Create与样式组合
2026/10/24 0:02:52
UDP协议实现局域网音量与关机控制:后台常驻与批量管理
2026/10/24 0:02:52
MATLAB缩进快捷键与批量格式化实战指南
2026/10/24 0:02:52
用Poco实现Qt风格信号与槽的跨平台C++方案
2026/10/24 4:01:50
OpenResearch实战:Claude Code、Codex、OpenCode、Cursor 工作流搭建与故障排查
2026/10/24 4:01:49
知识管理核弹:用Obsidian构建第二大脑的工程化方案(TaoToken 统一 Key 接入版)
2026/10/24 0:59:24
金融AI落地指南:从调研报告到技术选型与工程实践
2026/10/23 10:58:39
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/23 10:58:39
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/23 10:58:39
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)