READONLY文件系统配置

前言

系统是运行在内存中的,硬盘只是系统运行中的存储媒介。当硬盘对应到内存的数据发生改变时,就需要系统将内存的数据同步更新到硬盘进行存储。 异常掉电之所以具备破坏力,是因为异常掉电会不可预知的中断系统将内存数据回写到硬盘的过程,直接导致文件系统数据紊乱。绝大多数带有日志的文件系统(ext3,ext4,xfs等),大多数情况可以依靠文件系统日志自恢复或者依靠fsck命令恢复,问题是并不是所有损坏都可以被修复。 因此,将整个系统设置为只读模式,防止整个回写过程的发生就成了整个方案的出发点。

Case1-方案实施

系统环境 Linux发行版操作系统Red Hat Enterprise Linux 6.4 64位

在Red Hat Enterprise Linux 6.4系统中已经集成了READONLY的配置能力。整个配置过程主要涉及到3个系统配置文件。 > /etc/sysconfig/readonly-root

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Set to 'yes' to mount the system filesystems read-only.
READONLY=yes
# Set to 'yes' to mount various temporary state as either tmpfs
# or on the block device labelled RW_LABEL. Implied by READONLY
TEMPORARY_STATE=yes
# Place to put a tmpfs for temporary scratch writable space
RW_MOUNT=/var/lib/stateless/writable
# Label on local filesystem which can be used for temporary scratch space
RW_LABEL=stateless-rw
# Options to use for temporary mount
RW_OPTIONS=
# Label for partition with persistent data
STATE_LABEL=stateless-state
# Where to mount to the persistent data
STATE_MOUNT=/var/lib/stateless/state
# Options to use for peristent mount
STATE_OPTIONS=
  1. READONLY=yes表示将文件系统挂载为只读模式;
  2. TEMPORARY_STATE=yes表示将系统启动过程中存放临时的状态的路径挂载为tmpfs(内存文件系统,掉电丢失),或者挂载到被标记为RW_LABEL的块设备。 系统在启动过程需要实时更新一部分系统文件,例如/var/log/messages(记录系统启动日志的文件),这个关键字的作用是保证这部分文件的属性为可读写;
  3. RW_MOUNT是可读写文件的挂载路径,即/var/lib/stateless/writable下文件具备可读写属性;
  4. RW_LABEL是可读写的标识;
  5. 对应的有不需要发生变化的“persistent data”,可以用STATE的关键字表示,这里方案并没有到,不做说明。

/etc/rwtab

这个配置文件记录了,当系统被设置为只读时,被排除在外依然可读写的路径和文件。 部分摘录如下:

1
2
3
dirs	/var/log
empty /tmp
files /etc/adjtime
当在图形界面登陆系统时,在登陆账户下的.ICEauthority会被系统刷新,如果此时账户为只读,则会弹出如下警告,以root账户为例。 图1 为了解决这个问题,需要将/root设置为可读写属性。因此在/etc/rwtab添加如下字段: > files /root

表示将/root账户下的文件设置为可读写。同理,如果有其他账户,则需要一并设置。

/etc/rc.sysinit

实际上这个文件是rc.d/rc.sysinit的软连接。这个文件是系统启动流程,早期阶段的一个关键脚本,将会依据上述配置文件,对文件系统的挂载进行处理。脚本内容比较多,只摘录了跟配置方案相关的这段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if [ -f /etc/sysconfig/readonly-root ]; then
. /etc/sysconfig/readonly-root
Fi

if [ "$READONLY" = "yes" -o "$TEMPORARY_STATE" = "yes" ]; then
for file in /etc/rwtab /etc/rwtab.d/* /dev/.initramfs/rwtab ; do
is_ignored_file "$file" && continue
[ -f $file ] && cat $file | while read type path ; do
case "$type" in
empty)
mount_empty $path
;;
files)
mount_files $path
;;
dirs)
mount_dirs $path
;;
*)
;;
esac
[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"
done
done
fi

这段脚本作用是判断/etc/sysconfig/readonly-root文件会否存在,存在则将其中关键字加到环境变量,然后解析/etc/rwtab文件,从中匹配$type关键字并执行对应case脚本函数。 mount_empty作用是将$path路径拷贝到$RW_MOUNT路径(/etc/sysconfig/readonly-root中的关键字),这里只拷贝路径,empty顾名思义就是不包含路径下的子路径和文件。 mount_files作用是将$path路径下的文件拷贝到$RW_MOUNT路径,包含文件夹; mount_dirs作用是将$path路径下的文件夹依照原样的路径结构拷贝到$RW_MOUNT路径; 拷贝完成后,执行 > mount -n --bind "$RW_MOUNT$1" "$1"

这段就是整个方案的核心思路:将需要读写属性的文件及文件夹原样拷贝到具有读写权限的/var/lib/stateless/writable路径下,随后执行mount --bind将对应路径挂回原路径,实现这部分文件可读写而不影响其他文件。 配置好后就会出现如下图的效果,/root路径的文件系统类型是tmpfs可读写,而系统其他路径则是readonly。 图2 当需要对根文件系统读写修改时,执行 > mount -o remount rw /

可临时的将文件系统重新赋予读写属性。 需要将系统永久恢复时,此时修改/etc/sysconfig/readonly-root配置文件,将READONLY和TEMPORARY_STATE的键值YES修改为NO即可。


Case2-方案实施

Linux发行版操作系统Red Hat Enterprise Linux 7.1 64位

本想使用上述步骤配置完成需求,但发现RHEL7.1已经开始使用systemd做系统启动和服务管理,已经不存在/etc/rc.sysinit脚本,也就无法按照第一集的步骤将系统配置成只读属性。 幸运的是,在systemd的既定框架内,rhel采用rhel-readonly.service服务将原先低版本系统的/etc/rc.sysinit脚本取而代之。如下图所示,该服务已经默认启动。 图3 查看/usr/lib/systemd/system/rhel-readonly.service服务脚本,分析后发现与/etc/rc.sysinit脚本大同小异,也就存在将文件系统配置成只读模式的可行性。

/etc/sysconfig/readonly-root READONLY=yes TEMPORARY_STATE=yes

READONLY和TEMPORARY_STATE设置成yes,使能只读模式。 其他键值按需求配置,这里默认即可。

将/root设置为可读写属性,因此在/etc/rwtab添加如下字段: > files /root

表示将/root账户下的文件设置为可读写。 同理,如果有其他账户,则需要一并设置。以保证在登陆账户时,该账户下的.ICEauthority能顺利被系统刷新。

/etc/fstab

这一步是与Case1中最大的区别。需要手动将/分区设置成“ro”挂载属性,如下图所示: 图4 分析原因,推测可能是systemd并不是完全依赖rhel-readonly.service进行readonly的设置,需要/etc/fstab的配合。 执行上述三步后重启,即可完成只读模式的配置。

PS: 上图/etc/fstab中/cr分区是应用程序的部署分区。如上图所示,添加对应条目,即可按照需求配置成rw属性,其他分区配置同理。


Case2-问题

操作系统只读需求,安装好系统,使用一段时间后,发现系统内存耗尽,且不同板卡,内存消耗程度不同。系统版本RHEL7.2。

问题分析: 其中系统下内存使用状态如下: 图5 从图中看出似乎/tmp下被占用了562MB空间,实际分析/tmp并无大文件,此处应该是df命令的解析错误BUG。 对系统其他文件夹分析后,发现/var路径占用过大。 只读属性的文件系统,在硬盘分区配成只读后,会将必须保证读写能力的文件系统路径以tmpfs(内存文件系统)的形式挂载到系统(由/etc/rwtab可配),其中/var路径就是该种情况。 进一步分析/var路径,如下图所示:/var/crash和/var/spool/abrt路径下会存在一些vmcore文件夹,以该板卡为例,/var/spool/abrt下的vmcore文件就已经占用了555MB。 图6 该文件是kdump机制生成的用于分析内核崩溃原因的dump文件,该选项在安装系统时可选择是否使能。 通过这个结论可以推出问题的原因: 应用在开发的过程中,可能发生了一些导致内核崩溃的操作,内核依托kdump机制生成了vmcore文件到/var/crash和/var/spool/abrt下,占用了大部分的内存文件系统空间(也即内存空间,甚者会导致1.9G耗尽)

问题解决: 方案1:已经安装好系统,且系统使能kdump 1、还原文件系统为可读写属性,重启 2、删除/var/crash和/var/spool/abrt下的vmcore文件夹 3、systemctl disable kdump (关闭kdump服务) 4、还原文件系统为只读属性,重启

方案2:从源头解决。 安装系统过程中,不使能kdump功能。 坏处是,内核崩溃只能实时查看栈信息,无法保存。 可鉴于实际使用环境,自主选择是否使能。

PS:内存文件系统tmpfs最大为内存的一半,该项目系板卡物理内存4GB,所以tmpfs最大容量为2GB,原则上该上限可由内核选项配置。

-------------The End-------------
🙈坚持原创技术分享,感谢支持🙈
0%