[{"data":1,"prerenderedAt":1202},["ShallowReactive",2],{"content:\u002Fposts\u002Fraid-mdadm":3,"surround:\u002Fposts\u002Fraid-mdadm":1191},{"id":4,"title":5,"body":6,"categories":1166,"date":1168,"description":1169,"draft":1170,"extension":1171,"image":1172,"meta":1173,"navigation":1175,"path":1176,"permalink":1177,"pinned":1170,"published":1177,"readingTime":1178,"recommend":1177,"references":1177,"seo":1183,"sitemap":1184,"stem":1185,"tags":1186,"type":1188,"updated":1189,"__hash__":1190},"content\u002Fposts\u002Fposts\u002Fraid-mdadm.md","Linux 软 RAID 实战指南：使用 mdadm 构建可靠存储",{"type":7,"value":8,"toc":1133},"minimark",[9,19,22,26,38,54,95,99,102,249],[10,11,15],"alert",{"title":12,"type":13,"icon":14},"AI 迁移提示","info","tabler:robot",[16,17,18],"p",{},"本文由 AI 协助从旧站迁移，尚未完成逐篇人工审校；内容如有疏漏，将在复核后修订。",[10,20],{"title":21,"type":13},"> 本文部分内容由 AI 辅助整理，已结合实际操作进行校验，请根据自身环境谨慎使用。",[23,24,25],"h2",{"id":25},"为什么要做这件事",[16,27,28,29,33,34,37],{},"Ubuntu Server 上跑一堆 Docker 容器，数据都落在某一块数据盘上——",[30,31,32],"strong",{},"单盘 = 单点故障","，盘一坏数据全没。",[30,35,36],{},"软 RAID"," 是成本最低、最通用的冗余方案：不用阵列卡、不用特殊硬件，两块空闲盘 + 半小时就能把可靠性拉高一个量级。",[16,39,40,41,44,45,49,50,53],{},"本文记录从零做一套 ",[30,42,43],{},"RAID 1（镜像）"," 的完整流程：准备磁盘 → 创建阵列 → 持久化 → 挂载到 ",[46,47,48],"code",{"code":48},"\u002Fdata"," 给 Docker 用 → 故障盘替换 → ",[30,51,52],{},"邮件 + Bark 告警","。",[55,56,57,72],"blockquote",{},[16,58,59,63,64,67,68,71],{},[60,61,62],"span",{},"!IMPORTANT"," RAID ≠ 备份\nRAID 防的是",[30,65,66],{},"单块磁盘硬件故障","。以下场景 RAID ",[30,69,70],{},"完全不保护","：",[73,74,75,82,85,88],"ul",{},[76,77,78,79],"li",{},"误删、误 ",[46,80,81],{"code":81},"rm -rf",[76,83,84],{},"勒索病毒、应用 bug 写坏数据",[76,86,87],{},"文件系统损坏、同时多盘坏",[76,89,90,91,94],{},"电源 \u002F 控制器 \u002F 主板问题打穿所有盘\n",[30,92,93],{},"RAID 是高可用方案，不是备份方案。"," 重要数据仍然要做独立备份（rsync 到另一台机器 \u002F PBS \u002F 云盘都行），两者互不替代。",[23,96,98],{"id":97},"_1-raid-级别速览","1. RAID 级别速览",[16,100,101],{},"本文只用 RAID 1，但选型思路通用，列一张对比表方便以后扩展：",[103,104,105,133],"table",{},[106,107,108],"thead",{},[109,110,111,115,118,121,124,127,130],"tr",{},[112,113,114],"th",{},"级别",[112,116,117],{},"最少盘数",[112,119,120],{},"容错",[112,122,123],{},"读性能",[112,125,126],{},"写性能",[112,128,129],{},"容量利用率",[112,131,132],{},"典型场景",[134,135,136,159,185,207,229],"tbody",{},[109,137,138,142,145,148,151,153,156],{},[139,140,141],"td",{},"RAID 0",[139,143,144],{},"2",[139,146,147],{},"❌ 无",[139,149,150],{},"最快",[139,152,150],{},[139,154,155],{},"100%",[139,157,158],{},"临时 scratch 数据，丢了无所谓",[109,160,161,166,168,171,174,177,180],{},[139,162,163],{},[30,164,165],{},"RAID 1",[139,167,144],{},[139,169,170],{},"任 1 盘",[139,172,173],{},"快（双路读）",[139,175,176],{},"单盘速度",[139,178,179],{},"50%",[139,181,182],{},[30,183,184],{},"系统盘、数据量不大的重要数据",[109,186,187,190,193,195,198,201,204],{},[139,188,189],{},"RAID 5",[139,191,192],{},"3",[139,194,170],{},[139,196,197],{},"快",[139,199,200],{},"中（parity 计算）",[139,202,203],{},"(N-1)\u002FN",[139,205,206],{},"大容量 + 成本敏感",[109,208,209,212,215,218,220,223,226],{},[139,210,211],{},"RAID 6",[139,213,214],{},"4",[139,216,217],{},"任 2 盘",[139,219,197],{},[139,221,222],{},"慢（双 parity）",[139,224,225],{},"(N-2)\u002FN",[139,227,228],{},"大盘组（4 TB+），怕 URE",[109,230,231,234,236,239,241,244,246],{},[139,232,233],{},"RAID 10",[139,235,214],{},[139,237,238],{},"每 mirror 1 盘",[139,240,150],{},[139,242,243],{},"很快",[139,245,179],{},[139,247,248],{},"数据库、高 IO 负载",[10,250,253,260,264,279,282,292,312,345,349,355,377,381,387,407,414,418,424,430,453,456,464,467,471,477,510,513,519,526,531,537,551,555,561,568,587,591,597,611,615,621,629,635,641,648,654,659,689,693,699,703,709,712,718,721,727,737,741,747,751,757,761,767,784,788,791,797,800,804,810,820,824,830,843,847,857,873,883,892,898,907,913,919,925,932,941,953,957,960,966,971,975,1110],{"title":251,"type":252},"小规模 HomeLab 优先选 RAID 1","tip",[16,254,255,256,259],{},"两块相同容量的盘做 RAID 1，",[30,257,258],{},"可用性最高、操作最简单、故障场景最容易理解","。RAID 5\u002F6 容量利用率高但有\"写惩罚\"和 rebuild 期间再坏盘就全丢的风险，建议 4 盘以上再考虑。",[23,261,263],{"id":262},"_2-前置条件","2. 前置条件",[73,265,266,269,276],{},[76,267,268],{},"Ubuntu Server（本文基于 22.04 \u002F 24.04 验证）",[76,270,271,272,275],{},"至少 ",[30,273,274],{},"2 块容量相同的空闲数据盘","（容量不同也能做，但会以小盘为准，多出来的浪费）",[76,277,278],{},"root \u002F sudo 权限",[16,280,281],{},"先看看当前磁盘：",[283,284,290],"pre",{"className":285,"code":287,"language":288,"meta":289},[286],"language-bash","lsblk\n# 假设 sda 是系统盘、sdb 和 sdc 是要做 RAID 的数据盘\n","bash","",[46,291,287],{"__ignoreMap":289},[16,293,294,297,298,301,302,301,305,308,309,53],{},[60,295,296],{},"!WARNING"," 严重提醒：下面的操作会抹掉目标盘\n后续 ",[46,299,300],{"code":300},"wipefs"," \u002F ",[46,303,304],{"code":304},"parted",[46,306,307],{"code":307},"mdadm --create"," 都是",[30,310,311],{},"不可逆破坏性操作",[73,313,314,325,338],{},[76,315,316,317,320,321,324],{},"执行前务必用 ",[46,318,319],{"code":319},"lsblk"," + ",[46,322,323],{"code":323},"sudo fdisk -l"," 反复确认目标盘",[76,326,327],{},[30,328,329,330,333,334,337],{},"绝对不要把系统盘（通常是 ",[46,331,332],{"code":332},"\u002Fdev\u002Fsda"," 或 ",[46,335,336],{"code":336},"\u002Fdev\u002Fnvme0n1","）当成目标盘",[76,339,340,341,344],{},"不确定时，先 ",[46,342,343],{"code":343},"mount | grep \u003C盘名>"," 看盘是否被系统挂着",[23,346,348],{"id":347},"_3-准备磁盘","3. 准备磁盘",[283,350,353],{"className":351,"code":352,"language":288,"meta":289},[286],"# 再次确认目标盘\nlsblk\nsudo fdisk -l \u002Fdev\u002Fsdb \u002Fdev\u002Fsdc\n\n# 擦除磁盘元数据（旧分区表、文件系统签名、RAID 残留等）\nsudo wipefs -a \u002Fdev\u002Fsdb\nsudo wipefs -a \u002Fdev\u002Fsdc\n\n# 创建 GPT 分区表\nsudo parted \u002Fdev\u002Fsdb --script mklabel gpt\nsudo parted \u002Fdev\u002Fsdc --script mklabel gpt\n\n# 创建占满整盘的分区（0% 100% 让 parted 自动做 4K 对齐）\nsudo parted \u002Fdev\u002Fsdb --script mkpart primary 0% 100%\nsudo parted \u002Fdev\u002Fsdc --script mkpart primary 0% 100%\n\n# 设置 RAID 标志，告诉内核这些分区将用作 RAID 成员\nsudo parted \u002Fdev\u002Fsdb --script set 1 raid on\nsudo parted \u002Fdev\u002Fsdc --script set 1 raid on\n\n# 确认：应该看到 sdb1 和 sdc1，大小相同\nlsblk\n",[46,354,352],{"__ignoreMap":289},[16,356,357,360,361,364,365,368,369,372,373,376],{},[60,358,359],{},"!TIP"," GPT 上的 \"primary\" 是什么\nGPT 分区表",[30,362,363],{},"没有"," primary \u002F extended 的概念（那是 MBR 老术语）。",[46,366,367],{"code":367},"parted mkpart primary ..."," 里的 ",[46,370,371],{"code":371},"primary"," 在 GPT 上只是充当分区名字，不影响功能。用 ",[46,374,375],{"code":375},"mkpart data"," 或其他名字也一样。",[23,378,380],{"id":379},"_4-创建-raid-1-阵列","4. 创建 RAID 1 阵列",[283,382,385],{"className":383,"code":384,"language":288,"meta":289},[286],"sudo mdadm --create --verbose \u002Fdev\u002Fmd0 \\\n  --level=1 \\\n  --raid-devices=2 \\\n  \u002Fdev\u002Fsdb1 \u002Fdev\u002Fsdc1\n",[46,386,384],{"__ignoreMap":289},[73,388,389,395,401],{},[76,390,391,394],{},[46,392,393],{"code":393},"\u002Fdev\u002Fmd0","：RAID 设备节点名字，多个阵列时递增（md0、md1...）",[76,396,397,400],{},[46,398,399],{"code":399},"--level=1","：RAID 级别（想换别的级别就改这里，对应第 1 节表格）",[76,402,403,406],{},[46,404,405],{"code":405},"--raid-devices=2","：参与成员数量",[16,408,409,410,413],{},"命令执行后，阵列",[30,411,412],{},"立即开始首次同步","——把两块盘的数据对齐（即使现在都是空盘也会全盘对齐一次）。",[23,415,417],{"id":416},"_5-监控同步进度","5. 监控同步进度",[283,419,422],{"className":420,"code":421,"language":288,"meta":289},[286],"# 实时看同步进度（5 秒刷新一次即可，太频繁反而占 CPU）\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n\n# 或单次看详细状态\nsudo mdadm --detail \u002Fdev\u002Fmd0\n",[46,423,421],{"__ignoreMap":289},[16,425,426,429],{},[30,427,428],{},"判定同步完成","需要两个条件同时满足：",[431,432,433,440],"ol",{},[76,434,435,436,439],{},"状态显示 ",[46,437,438],{"code":438},"[UU]","（两块盘都是 Up）",[76,441,442,444,445,448,449,452],{},[30,443,363],{}," ",[46,446,447],{"code":447},"resync","、",[46,450,451],{"code":451},"recovery"," 这种进度行",[16,454,455],{},"例如完成状态的输出：",[283,457,462],{"className":458,"code":460,"language":461},[459],"language-text","md0 : active raid1 sdc1[1] sdb1[0]\n      1048512 blocks super 1.2 [2\u002F2] [UU]\n\nunused devices: \u003Cnone>\n","text",[46,463,460],{"__ignoreMap":289},[16,465,466],{},"同步期间阵列仍可使用（性能略低），但推荐等完成再挂数据。",[23,468,470],{"id":469},"_6-持久化配置","6. 持久化配置",[16,472,473,476],{},[60,474,475],{},"!NOTE"," mdadm 配置文件路径因发行版而异",[73,478,479,488,500],{},[76,480,481,71,484,487],{},[30,482,483],{},"Debian \u002F Ubuntu",[46,485,486],{"code":486},"\u002Fetc\u002Fmdadm\u002Fmdadm.conf","（本文用这个）",[76,489,490,71,493,496,497,499],{},[30,491,492],{},"CentOS \u002F RHEL \u002F Rocky",[46,494,495],{"code":495},"\u002Fetc\u002Fmdadm.conf","（",[30,498,363],{}," mdadm 子目录）",[76,501,502,503,506,507],{},"对应的 initramfs 刷新命令：Debian\u002FUbuntu 是 ",[46,504,505],{"code":505},"update-initramfs -u","，CentOS\u002FRHEL 是 ",[46,508,509],{"code":509},"dracut -f",[16,511,512],{},"先 dry-run 看要写入什么：",[283,514,517],{"className":515,"code":516,"language":288,"meta":289},[286],"sudo mdadm --detail --scan\n# 输出类似：\n# ARRAY \u002Fdev\u002Fmd0 metadata=1.2 name=server-01:0 UUID=abcd1234:5678efgh:9012ijkl:3456mnop\n",[46,518,516],{"__ignoreMap":289},[16,520,521,522,525],{},"然后写进配置文件，",[30,523,524],{},"根据系统是否已存在其他 mdadm RAID","选一种方式：",[527,528,530],"h3",{"id":529},"_61-方式-a追加系统上已经有其他-raid-时选这个","6.1 方式 A：追加（系统上已经有其他 RAID 时选这个）",[283,532,535],{"className":533,"code":534,"language":288,"meta":289},[286],"sudo mdadm --detail --scan | sudo tee -a \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n",[46,536,534],{"__ignoreMap":289},[16,538,539,542,543,546,547,550],{},[46,540,541],{"code":541},"tee -a"," 的 ",[46,544,545],{"code":545},"-a"," 是 ",[30,548,549],{},"append（追加）","，原文件里的条目保留，新阵列追加到末尾。适合\"加阵列\"场景。",[527,552,554],{"id":553},"_62-方式-b备份后覆盖全新系统只做这一个-raid","6.2 方式 B：备份后覆盖（全新系统、只做这一个 RAID）",[283,556,559],{"className":557,"code":558,"language":288,"meta":289},[286],"# 先备份原文件\nsudo cp \u002Fetc\u002Fmdadm\u002Fmdadm.conf \u002Fetc\u002Fmdadm\u002Fmdadm.conf.bak\n\n# 然后覆盖写入\nsudo mdadm --detail --scan | sudo tee \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n",[46,560,558],{"__ignoreMap":289},[16,562,563,564,567],{},"好处是文件干净、无历史残留；坏处是一旦手误漏写了某个阵列的 UUID，重启后那个阵列就识别不出来——好在有 ",[46,565,566],{"code":566},".bak"," 备份可以恢复。",[16,569,570,572,573,496,576,582,583,586],{},[60,571,296],{}," 不要裸用 tee 覆盖\n直接 ",[46,574,575],{"code":575},"... | sudo tee \u002Fetc\u002Fmdadm\u002Fmdadm.conf",[30,577,578,579,581],{},"不加 ",[46,580,545],{"code":545},"、不备份","）是最危险的写法。如果系统里已有其他 mdadm RAID，原配置会被",[30,584,585],{},"直接抹掉","，重启后那个阵列认不出来。不确定时选 6.1 的追加方式更稳。",[527,588,590],{"id":589},"_63-更新-initramfs","6.3 更新 initramfs",[283,592,595],{"className":593,"code":594,"language":288,"meta":289},[286],"sudo update-initramfs -u\n",[46,596,594],{"__ignoreMap":289},[16,598,599,600,603,604,606,607,610],{},"这一步把 RAID 配置打包进内核启动镜像。对",[30,601,602],{},"数据盘"," RAID 不是强制必需，但做了可以避免极个别\"重启后 ",[46,605,393],{"code":393}," 变成 ",[46,608,609],{"code":609},"\u002Fdev\u002Fmd127","\"之类的扫盘顺序问题。",[23,612,614],{"id":613},"_7-创建文件系统并挂载","7. 创建文件系统并挂载",[283,616,619],{"className":617,"code":618,"language":288,"meta":289},[286],"# 创建 ext4 文件系统\nsudo mkfs.ext4 \u002Fdev\u002Fmd0\n\n# 创建挂载点\nsudo mkdir -p \u002Fdata\n\n# 临时挂载一下看是否正常（重启会失效，下一步才是开机自动挂载）\nsudo mount \u002Fdev\u002Fmd0 \u002Fdata\n\n# 确认\ndf -h \u002Fdata\n",[46,620,618],{"__ignoreMap":289},[527,622,624,625,628],{"id":623},"_71-写入-etcfstab让重启后自动挂载","7.1 写入 ",[46,626,627],{"code":627},"\u002Fetc\u002Ffstab","，让重启后自动挂载",[16,630,631,632,634],{},"用 UUID 挂载比用 ",[46,633,393],{"code":393}," 更稳（设备名有概率变成 md127 之类）：",[283,636,639],{"className":637,"code":638,"language":288,"meta":289},[286],"# 获取 md0 的 UUID\nUUID=$(sudo blkid -s UUID -o value \u002Fdev\u002Fmd0)\n\n# 追加到 fstab\necho \"UUID=$UUID \u002Fdata ext4 defaults 0 2\" | sudo tee -a \u002Fetc\u002Ffstab\n\n# 验证 fstab 语法没错（不会真的重新挂载，只是 lint）\nsudo mount -a\n",[46,640,638],{"__ignoreMap":289},[16,642,643,644,647],{},"强烈建议",[30,645,646],{},"重启一次实际测试","一下：",[283,649,652],{"className":650,"code":651,"language":288,"meta":289},[286],"sudo reboot\n# 重启后：\ndf -h \u002Fdata          # 应该能看到\ncat \u002Fproc\u002Fmdstat     # 应该 [UU]\n",[46,653,651],{"__ignoreMap":289},[16,655,656,658],{},[60,657,359],{}," fstab 最后两列的含义",[73,660,661,672],{},[76,662,663,669,670],{},[30,664,665,666],{},"第 5 列 ",[46,667,668],{"code":668},"0","：dump 备份工具的扫描标志，现在都不用 dump，填 ",[46,671,668],{"code":668},[76,673,674,679,680,683,684,686,687],{},[30,675,676,677],{},"第 6 列 ",[46,678,144],{"code":144},"：fsck 启动时的检查顺序——根分区填 ",[46,681,682],{"code":682},"1","，其他数据分区填 ",[46,685,144],{"code":144},"，不检查填 ",[46,688,668],{"code":668},[23,690,692],{"id":691},"_8-故障磁盘替换","8. 故障磁盘替换",[16,694,695,696,53],{},"RAID 1 的核心价值：一块盘挂了另一块继续工作，换盘后 rebuild 即可，",[30,697,698],{},"不丢数据",[527,700,702],{"id":701},"_81-识别故障盘","8.1 识别故障盘",[283,704,707],{"className":705,"code":706,"language":288,"meta":289},[286],"cat \u002Fproc\u002Fmdstat\n",[46,708,706],{"__ignoreMap":289},[16,710,711],{},"正常：",[283,713,716],{"className":714,"code":715,"language":461},[459],"md0 : active raid1 sdc1[1] sdb1[0]\n      ... [2\u002F2] [UU]\n",[46,717,715],{"__ignoreMap":289},[16,719,720],{},"有盘故障：",[283,722,725],{"className":723,"code":724,"language":461},[459],"md0 : active raid1 sdc1[1](F) sdb1[0]\n      ... [2\u002F1] [U_]\n",[46,726,724],{"__ignoreMap":289},[16,728,729,732,733,736],{},[46,730,731],{"code":731},"[U_]"," 的下划线就是挂掉的那一块，",[46,734,735],{"code":735},"(F)"," 标志位也印证了状态是 failed。",[527,738,740],{"id":739},"_82-把故障盘正式移除","8.2 把故障盘正式移除",[283,742,745],{"className":743,"code":744,"language":288,"meta":289},[286],"# 先标记为 fail（状态已经 fail 的也要走这一步）\nsudo mdadm --manage \u002Fdev\u002Fmd0 --fail \u002Fdev\u002Fsdc1\n\n# 再从阵列里移除\nsudo mdadm --manage \u002Fdev\u002Fmd0 --remove \u002Fdev\u002Fsdc1\n",[46,746,744],{"__ignoreMap":289},[527,748,750],{"id":749},"_83-物理换盘-对新盘分区","8.3 物理换盘 + 对新盘分区",[283,752,755],{"className":753,"code":754,"language":288,"meta":289},[286],"# 新盘插上后，假设还是识别为 \u002Fdev\u002Fsdc\nsudo wipefs -a \u002Fdev\u002Fsdc\nsudo parted \u002Fdev\u002Fsdc --script mklabel gpt\nsudo parted \u002Fdev\u002Fsdc --script mkpart primary 0% 100%\nsudo parted \u002Fdev\u002Fsdc --script set 1 raid on\n",[46,756,754],{"__ignoreMap":289},[527,758,760],{"id":759},"_84-加回阵列自动开始-rebuild","8.4 加回阵列，自动开始 rebuild",[283,762,765],{"className":763,"code":764,"language":288,"meta":289},[286],"sudo mdadm --manage \u002Fdev\u002Fmd0 --add \u002Fdev\u002Fsdc1\n\n# 观察 rebuild 进度\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n",[46,766,764],{"__ignoreMap":289},[16,768,769,772,773,776,777,780,781,783],{},[46,770,771],{"code":771},"\u002Fproc\u002Fmdstat"," 会多出一行 ",[46,774,775],{"code":775},"recovery = X% (done)","。rebuild 期间阵列",[30,778,779],{},"仍可用","（降级模式），性能略低；等 ",[46,782,438],{"code":438}," 且无 recovery 行即恢复完成。",[527,785,787],{"id":786},"_85-上线前的故障演练推荐新手做一次","8.5 上线前的故障演练（推荐新手做一次）",[16,789,790],{},"RAID 坏盘的那一刻通常来得毫无预警。上线前主动模拟一次，心里有数：",[283,792,795],{"className":793,"code":794,"language":288,"meta":289},[286],"# 手动把 sdc1 标记为故障\nsudo mdadm --manage \u002Fdev\u002Fmd0 --fail \u002Fdev\u002Fsdc1\ncat \u002Fproc\u002Fmdstat    # 此时应进入降级状态 [U_]\n\n# 模拟完成后，把它重新加回来观察 rebuild\nsudo mdadm --manage \u002Fdev\u002Fmd0 --remove \u002Fdev\u002Fsdc1\nsudo mdadm --manage \u002Fdev\u002Fmd0 --add \u002Fdev\u002Fsdc1\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n",[46,796,794],{"__ignoreMap":289},[16,798,799],{},"走完一遍，真出故障时直接按流程复刻，不会临时抓瞎。",[23,801,803],{"id":802},"_9-故障监控与告警","9. 故障监控与告警",[16,805,806,807,53],{},"RAID 坏了一块盘后如果没人注意，下一步很可能又坏一块——两块都坏就全丢。",[30,808,809],{},"必须配监控告警",[16,811,812,813,333,816,819],{},"Ubuntu 装 mdadm 时会自动装 mdmonitor 服务（systemd 单元通常名为 ",[46,814,815],{"code":815},"mdmonitor",[46,817,818],{"code":818},"mdadm","，视版本而定），它周期性扫描所有阵列，一旦状态变化就按配置好的方式通知。",[527,821,823],{"id":822},"_91-邮件通知传统方式","9.1 邮件通知（传统方式）",[283,825,828],{"className":826,"code":827,"language":288,"meta":289},[286],"# 在 \u002Fetc\u002Fmdadm\u002Fmdadm.conf 里加一行邮件地址\necho \"MAILADDR your-email@example.com\" | sudo tee -a \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n\n# 重启 mdmonitor 服务\nsudo systemctl restart mdmonitor\n\n# 触发一条测试通知\nsudo mdadm --monitor --scan --test --oneshot\n",[46,829,827],{"__ignoreMap":289},[16,831,832,833,301,836,301,839,842],{},"前提是这台机器本身能发邮件（装了 ",[46,834,835],{"code":835},"postfix",[46,837,838],{"code":838},"msmtp",[46,840,841],{"code":841},"ssmtp"," 等本地邮件转发工具）。对 HomeLab 用户这往往比较麻烦——下面的 HTTP Webhook 方式更现代。",[527,844,846],{"id":845},"_92-http-webhook-通知推荐以-bark-为例","9.2 HTTP Webhook 通知（推荐，以 Bark 为例）",[16,848,849,856],{},[850,851,855],"a",{"href":852,"rel":853},"https:\u002F\u002Fgithub.com\u002FFinb\u002FBark",[854],"nofollow","Bark"," 是 iOS 上一个免费的 Push 应用，服务端只需要发 HTTP POST。配置思路：",[431,858,859,866],{},[76,860,861,862,865],{},"mdmonitor 发现故障 → 调用 ",[46,863,864],{"code":864},"PROGRAM"," 指定的脚本",[76,867,868,869,872],{},"脚本里用 ",[46,870,871],{"code":871},"curl"," POST 到 Bark API → 手机收到推送",[16,874,875,878,879,882],{},[30,876,877],{},"第 1 步","：在 iPhone 上安装 Bark App，复制它给你的 API URL（形如 ",[46,880,881],{"code":881},"https:\u002F\u002Fapi.day.app\u002Fyour_device_key","）。",[16,884,885,888,889,71],{},[30,886,887],{},"第 2 步","：写通知脚本 ",[46,890,891],{"code":891},"\u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh",[283,893,896],{"className":894,"code":895,"language":288,"meta":289},[286],"sudo tee \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh > \u002Fdev\u002Fnull \u003C\u003C'EOF'\n#!\u002Fbin\u002Fbash\n# mdmonitor 触发时以三个参数调用本脚本：\n#   $1 = 事件类型 (Fail \u002F DegradedArray \u002F RebuildFinished \u002F TestMessage 等)\n#   $2 = 涉及的阵列 (如 \u002Fdev\u002Fmd0)\n#   $3 = 涉及的成员盘 (Fail 等事件会带，其他可能为空)\n\nEVENT=\"$1\"\nARRAY=\"$2\"\nDEV=\"$3\"\n\nBARK_KEY=\"your_device_key_here\"        # ← 改成你自己的 key\nHOSTNAME=\"$(hostname)\"\n\ncurl -s -X POST \"https:\u002F\u002Fapi.day.app\u002F$BARK_KEY\" \\\n  --data-urlencode \"title=[$HOSTNAME] RAID $EVENT\" \\\n  --data-urlencode \"body=Array: $ARRAY  Device: $DEV\" \\\n  --data-urlencode \"group=mdadm\" \\\n  > \u002Fdev\u002Fnull\nEOF\n\nsudo chmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh\n",[46,897,895],{"__ignoreMap":289},[16,899,900,903,904,906],{},[30,901,902],{},"第 3 步","：在 ",[46,905,486],{"code":486}," 里加一行，让 mdmonitor 触发这个脚本：",[283,908,911],{"className":909,"code":910,"language":461},[459],"PROGRAM \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh\n",[46,912,910],{"__ignoreMap":289},[16,914,915,918],{},[30,916,917],{},"第 4 步","：重启 mdmonitor 并测试：",[283,920,923],{"className":921,"code":922,"language":288,"meta":289},[286],"sudo systemctl restart mdmonitor\n\n# 触发一条测试事件，会同时调用 PROGRAM 脚本和 MAILADDR 邮件\nsudo mdadm --monitor --scan --test --oneshot\n",[46,924,922],{"__ignoreMap":289},[16,926,927,928,931],{},"iPhone 应该立即收到一条 Bark 推送，标题类似 ",[46,929,930],{"code":930},"[server-01] RAID TestMessage","，说明链路已通。",[16,933,934,937,938,940],{},[30,935,936],{},"换成其他服务同理","：把 ",[46,939,871],{"code":871}," 里的 Bark URL 换成企业微信机器人、钉钉机器人、Discord \u002F Telegram Bot、Gotify \u002F ntfy 等任一个接收 HTTP POST 的服务即可。",[16,942,943,945,946,949,950,952],{},[60,944,359],{}," 邮件 + HTTP 建议同时配\n",[46,947,948],{"code":948},"MAILADDR"," 和 ",[46,951,864],{"code":864}," 可以并存，mdmonitor 会两个都触发。关键数据盘推荐都配上——万一 Bark 服务抖动，还有邮件作兜底通道。",[23,954,956],{"id":955},"_10-销毁-停用-raid","10. 销毁 \u002F 停用 RAID",[16,958,959],{},"以后如果不想用 RAID 了（换方案、要拆盘、清理旧环境），正确的流程：",[283,961,964],{"className":962,"code":963,"language":288,"meta":289},[286],"# 1. 卸载文件系统\nsudo umount \u002Fdata\n\n# 2. 从 \u002Fetc\u002Ffstab 里删除对应行（避免下次开机挂载失败阻塞启动）\nsudo sed -i '\u002F\\\u002Fdata\u002Fd' \u002Fetc\u002Ffstab\n\n# 3. 停止阵列\nsudo mdadm --stop \u002Fdev\u002Fmd0\n\n# 4. 擦除每块成员盘上的 mdadm 超级块（关键！）\nsudo mdadm --zero-superblock \u002Fdev\u002Fsdb1\nsudo mdadm --zero-superblock \u002Fdev\u002Fsdc1\n\n# 5. 从 \u002Fetc\u002Fmdadm\u002Fmdadm.conf 里删掉对应的 ARRAY 行（手动编辑）\nsudo nano \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n\n# 6. 更新 initramfs\nsudo update-initramfs -u\n\n# 7. (可选) 完全擦磁盘，准备做新用途\nsudo wipefs -a \u002Fdev\u002Fsdb\nsudo wipefs -a \u002Fdev\u002Fsdc\n",[46,965,963],{"__ignoreMap":289},[16,967,968,970],{},[60,969,296],{}," 第 4 步 --zero-superblock 最容易漏\n不擦掉超级块的话，这两块盘上的 RAID 元数据还在，下次你想用它们建别的 RAID、或当普通盘用时，系统会报警或\"默默把它们认成旧阵列的一部分\"。务必执行。",[23,972,974],{"id":973},"_11-常见故障排查","11. 常见故障排查",[103,976,977,990],{},[106,978,979],{},[109,980,981,984,987],{},[112,982,983],{},"现象",[112,985,986],{},"可能原因",[112,988,989],{},"对策",[134,991,992,1012,1029,1046,1060,1077,1095],{},[109,993,994,1002,1005],{},[139,995,996,998,999],{},[46,997,307],{"code":307}," 报 ",[46,1000,1001],{"code":1001},"not large enough",[139,1003,1004],{},"两块盘实际可用空间不一致（哪怕标称一样）",[139,1006,1007,1008,1011],{},"用 ",[46,1009,1010],{"code":1010},"--size=\u003C具体值>"," 显式指定较小值，单位 K",[109,1013,1014,1020,1026],{},[139,1015,1016,1017,1019],{},"重启后 ",[46,1018,48],{"code":48}," 没自动挂载",[139,1021,1022,1023,1025],{},"fstab 里用了 ",[46,1024,393],{"code":393}," 但设备名变了",[139,1027,1028],{},"改用 UUID（见 7.1 节）",[109,1030,1031,1037,1040],{},[139,1032,1016,1033,606,1035],{},[46,1034,393],{"code":393},[46,1036,609],{"code":609},[139,1038,1039],{},"mdadm.conf 里没有该阵列的 ARRAY 行，或 initramfs 没更新",[139,1041,1042,1043],{},"重写 mdadm.conf + ",[46,1044,1045],{"code":1045},"sudo update-initramfs -u",[109,1047,1048,1051,1054],{},[139,1049,1050],{},"Rebuild 速度很慢",[139,1052,1053],{},"内核默认速度上限偏低",[139,1055,1056,1059],{},[46,1057,1058],{"code":1058},"echo 200000 | sudo tee \u002Fproc\u002Fsys\u002Fdev\u002Fraid\u002Fspeed_limit_max","（单位 KB\u002Fs）",[109,1061,1062,1065,1068],{},[139,1063,1064],{},"mdmonitor 不发通知",[139,1066,1067],{},"服务没起 \u002F mdadm.conf 格式错 \u002F MAILADDR 写错",[139,1069,1070,320,1073,1076],{},[46,1071,1072],{"code":1072},"systemctl status mdmonitor",[46,1074,1075],{"code":1075},"journalctl -u mdmonitor"," 看日志",[109,1078,1079,1082,1085],{},[139,1080,1081],{},"Bark 脚本不触发",[139,1083,1084],{},"PROGRAM 路径错 \u002F 脚本没可执行权限",[139,1086,1087,1088,1091,1092],{},"确认脚本已 ",[46,1089,1090],{"code":1090},"chmod +x","，首行是 ",[46,1093,1094],{"code":1094},"#!\u002Fbin\u002Fbash",[109,1096,1097,1104,1107],{},[139,1098,1099,1100,1103],{},"换完盘 ",[46,1101,1102],{"code":1102},"--add"," 后 rebuild 立刻失败",[139,1105,1106],{},"新盘也有问题 \u002F 新分区比老分区小",[139,1108,1109],{},"SMART 检查新盘；确认新分区 ≥ 老分区",[16,1111,1112,1113,1116,1117,1119,1120,1122,1123,1125,1126,1128,1129,1132],{},"本文基于 Ubuntu Server 22.04 \u002F 24.04 + 数据盘 RAID 的场景整理。",[1114,1115],"br",{},"\n对 CentOS \u002F RHEL 系读者，主要差异是 ",[46,1118,495],{"code":495},"（无子目录）和 ",[46,1121,509],{"code":509}," 替代 ",[46,1124,505],{"code":505},"；其他命令和流程通用。",[1114,1127],{},"\n如果要做",[30,1130,1131],{},"系统盘 RAID","（root \u002F boot 在 RAID 上），复杂度显著提升——涉及 GRUB、initramfs 内的 raid 模块、metadata 版本选择等，本文不涉及。",{"title":289,"searchDepth":1134,"depth":1134,"links":1135},4,[1136,1138,1139,1140,1141,1142,1143,1149,1153,1160,1164,1165],{"id":25,"depth":1137,"text":25},2,{"id":97,"depth":1137,"text":98},{"id":262,"depth":1137,"text":263},{"id":347,"depth":1137,"text":348},{"id":379,"depth":1137,"text":380},{"id":416,"depth":1137,"text":417},{"id":469,"depth":1137,"text":470,"children":1144},[1145,1147,1148],{"id":529,"depth":1146,"text":530},3,{"id":553,"depth":1146,"text":554},{"id":589,"depth":1146,"text":590},{"id":613,"depth":1137,"text":614,"children":1150},[1151],{"id":623,"depth":1146,"text":1152},"7.1 写入 \u002Fetc\u002Ffstab，让重启后自动挂载",{"id":691,"depth":1137,"text":692,"children":1154},[1155,1156,1157,1158,1159],{"id":701,"depth":1146,"text":702},{"id":739,"depth":1146,"text":740},{"id":749,"depth":1146,"text":750},{"id":759,"depth":1146,"text":760},{"id":786,"depth":1146,"text":787},{"id":802,"depth":1137,"text":803,"children":1161},[1162,1163],{"id":822,"depth":1146,"text":823},{"id":845,"depth":1146,"text":846},{"id":955,"depth":1137,"text":956},{"id":973,"depth":1137,"text":974},[1167],"Linux","2026-02-10 14:18:34","在 Ubuntu Server 上用 mdadm 把两块以上数据盘做成软 RAID，承载 Docker 等应用数据——从磁盘准备、RAID 1 创建、持久化挂载，到故障磁盘替换、mdmonitor 邮件\u002FBark 告警的完整流程。",false,"md","https:\u002F\u002Fimg.olinl.com\u002Ffile\u002Fpost-img\u002Fcover\u002F6QqEMPCW.webp",{"slots":1174},{},true,"\u002Fposts\u002Fraid-mdadm",null,{"text":1179,"minutes":1180,"time":1181,"words":1182},"16 min read",15.68,940800,3136,{"title":5,"description":1169},{"loc":1176},"posts\u002Fposts\u002Fraid-mdadm",[1187,818],"RAID","tech","2026-07-26 13:19:17","M3aHnzg6-PKtllAlbGVD9KxPdVjfSgbgs5R2oX76TmY",[1192,1197],{"title":1193,"path":1194,"stem":1195,"date":1196,"type":1188,"children":-1},"使用 TrueNAS 运行 Alist 容器","\u002Fposts\u002Ftruenas-alist","posts\u002Fposts\u002Ftruenas-alist","2026-02-10",{"title":1198,"path":1199,"stem":1200,"date":1201,"type":1188,"children":-1},"Beszel 服务器监控工具部署指南","\u002Fposts\u002Fbeszel-install","posts\u002Fposts\u002Fbeszel-install","2026-02-11",1788712223987]