前言
前不久,刚使用组里的一台服务器,这台服务器平时用的人不多, 没有严格的管理机制,大家都使用同一个用户名进行远程连接,人人都有sudo权限。我因为对Linux不是非常熟悉,使用管理员权限下执行了一个删除文件的操作(sudo rm-rf),直接把系统搞崩,差点给全组造成难以估量的损失,从删库到跑路差点在我身上上演。。
最危险的命令
不少人都听说过Linux中最危险的命令就是sudo rm -rf /*
这个命令可以拆解成以下几个部分:
- sudo:获取管理员权限
- rm:remove删除
- -r:递归地删除子目录和子目录中的文件
- -f:强制删除,不再一一向用户提示确认
- /*:根目录下所有的内容
因此,执行此命令就意味着把整个系统内容全部删除,是相当危险的,听说过不少误删库导致原地离职的职场案例。
我当然清楚这种命令的危险性,不至于去直接执行,但是却用类似的命令得到了相似的后果,下面就来复盘一下案发经过。
案发经过
案发时,我主要想在服务器上装一个软件。
首先,新建一个空文件夹来存放软件的位置
代码语言:javascript复制mkdir soft
然后,查询了一下文件系统
代码语言:javascript复制df -h
输出:
文件系统 容量 已用 可用 已用% 挂载点
udev 32G 0 32G 0% /dev
tmpfs 6.3G 2.5M 6.3G 1% /run
/dev/nvme0n1p2 457G 163G 272G 38% /
tmpfs 32G 0 32G 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 32G 0 32G 0% /sys/fs/cgroup
......
找到了挂载在根目录下文件系统/dev/nvme0n1p2
,然后根据一个安装教程,把该系统挂到新建的文件夹下
mount /dev/nvme0n1p2 soft
不知道为什么要这样操作,当时并不清楚mount的作用,就跟着做了,然后捣鼓半天,依然安装失败,于是想把文件夹删了,再重新安装。
代码语言:javascript复制sudo rm -rf soft
结果系统提示:
代码语言:javascript复制rm: it is dangerous to operate recursively on '/'
rm: use --no-preserve-root to override this failsafe
我一头雾水,我删一个自己建的文件夹,也没有在里面放很多文件,怎么会被系统提示这操作是危险(dangerous)的呢?
轻蔑一笑,根据系统提示,继续执行:
代码语言:javascript复制sudo rm -rf soft --no-preserve-root
回车一敲,惨案酿成。
远程连接的ssh终端会话并没有结束,但是新的ssh连接已经无法成功,在会话中输入ls
,cp
等基础命令均提示找不到命令,只留下了一个仍然可以用的cd
命令以及一脸懵逼和冷汗直冒的我。。
因为当时对Linux的文件系统并不了解,因此我下意识地认为删除了一个挂载在根目录下的文件系统,就等价于执行了上面那条危险命令。删了系统倒是问题不严重,严重的是这台服务器上还有几个T的实验数据和成果,如果误删,那我成了全组的“千古罪人”。
为了给师兄和同门一个交代,我赶紧去补习了一下Linux文件系统的相关知识。于是就有了下面的一些知识笔记。
Linux文件系统知识
Linux目录树结构
在Linux系统中,文件目录树如下图[1]所示。
其中,各目录有着特殊含义:
- /bin:存放用户经常使用的命令
- /boot:启动加载程序的静态文件
- /dev:设备文件目录
- /etc:系统配置文件目录
- /home:普通用户的家目录
- /root:系统管理员的家目录
- /run:进程的运行数据存放的目录
- /sbin:存放系统管理员用户使用的命令
- /tmp:临时文件目录;任何人都可以访问,存放周期10天
- /usr:存放程序文件,库文件,共享文件,各种文档等
- /usr/bin:存放用户命令
- /usr/local:程序安装目录
- /usr/sbin:类似/sbin;存放管理员用户使用的命令
- /usr/tmp:被抛弃的临时文件目录
- /var:动态数据文件目录;日志文件log,数据库,缓存目录等
- /lib:存放程序的库文件
- /lib64:存放64位程序库文件
- /media:移动媒体的挂载点
- /mnt:临时挂载的文件系统的挂载点
- /opt:存放第三方软件服务
- /proc:伪文件系统,内核映射文
- /srv: 用来存储本机提供的服务或数据
- /sys:伪文件系统,跟硬件设备相关的属性映射文件
所有的目录文件通常不是放在一整块硬盘之上,就像windows中,基本会单独区分C盘和D盘,盘符就是挂载点。 挂载的含义就是将硬盘和一个文件夹进行绑定连接,这样通过文件夹就可以访问到硬盘的数据。在Linux中,并不会像Windows那样自动生成挂载点,需要手动进行挂载。
如果有两块硬盘,通常的硬盘挂载分布如下,一块硬盘用来挂载根分区和系统相关的文件,另一块硬盘挂载在home文件夹下,即用户信息和数据文件。
看到这里,稍稍松了口气,在之前的惨案中,显然根目录的硬盘挂在了一个空文件夹下,这就导致了空文件夹中包含了系统相关的内容,因此再进行删除会提示危险命令。同时,删除之后,系统报废,但数据之类的内容都挂在了其它盘,不受影响。
硬盘分区
发现问题并没有想象中严重,那么继续往下学习。假设一个新场景,服务器如果新增了一块硬盘,应该如何进行分区?因为硬盘很大,对齐进行分区之后能够更方便进行资源管理,同时也增加了安全性(外一一个和我一样的憨批把整个分区误删了呢,这样其它分区可以不受影响)。
首先要了解一下分区类型,对于一个硬盘来说,通常分为主分区、扩展分区和逻辑分区。 主分区最多存在4个(包含拓展分区),通常用来存储系统相关命令和驱动,类似windows的C盘。 除去主分区之外,剩下的分区被称为拓展分区,在拓展分区中,可以划分成数个逻辑分区(IDE硬盘最多支持59个逻辑分区,SCSI硬盘最多支持11个逻辑分区)
下图[2]中展示了两种不同的分区方式,无论哪种分区,逻辑分区的命名均从sda5开始。
在分区之前,可以使用df
命令来查看已挂载磁盘的总容量、使用容量、剩余容量等信息
df [选项] [挂载点]
选项:
-a 显示所有的文件系统信息,包括特殊文件系统,如/proc、/sysfs
-h 使用习惯单位显示容量,如KB,MB或GB等
-T 显示文件系统类型
-m 以MB为单位显示容量
-k 以KB为单位显示容量。默认就是以KB为单位
在服务器上输入df -h
,输出以下信息:
可以看到,服务器上有这几类文件系统:
- udev
挂载在
/dev
目录下,起设备管理器的作用 - tmpfs tmpfs是一种基于内存的文件系统,无需格式化可以直接使用,读写速度快,重启后丢失
- /dev/loop loop是一种伪设备,能使用户像块设备一样访问一个文件
- /dev/nvme0n1 系统硬盘,p1,p2是该硬盘上的分区
- /dev/sda 系统硬盘
因此可以发现,该系统上只挂载了两块硬盘nvme0n1
和sda
,其中,nvme0n1
划分了两个子分区,sda
没有划分分区。
使用lsblk
命令,可以看得更加清楚一些:
在Linux中,使用du
命令可以查看文件夹大小
du [选项] [目录或文件名]
选项:
-a 显示每个子文件的磁盘占用量。默认只统计
子目录的磁盘占用量
-h 使用习惯单位显示磁盘占用量,如KB,MB
或GB等
-s 统计总占用量,而不列出子目录和子文件的
占用量
在上面可以看到sda
这块硬盘挂在/mnt
目录下,已经使用939G的空间。
那用du
命令来查看一下该文件夹的大小,神奇的是该文件夹大小只有912G。
主要原因是:
- df命令是从文件系统考虑的,不光要考虑文件占用的空间,还要统计被命令或程序 占用的空间(最常见的就是文件已经删除,但是程序并没有释放空间)
- du命令是面向文件的,只会计算文件或目录占用的空间
因此,df命令查出来的所用空间会比du命令查出来的更大。同时,这样启示服务器的管理者需要定期对服务器进行重启,释放那些临时文件空间。
下面学习分区,硬盘分区需要使用fdisk命令。
示例:
代码语言:javascript复制fdisk /dev/sdb
输入n
,新建分区
e:extended 代表新建拓展分区
p:primary partition 主分区
输入p
,输入1,新建1号主分区
内存分配输入 2G
,给1号主分区分配2G大小
分区完之后,输入p
,可以查看到硬盘中的新分区信息
分完一号主分区之后,再分一个2号主分区作为拓展分区,命令类似
拓展分区分完分逻辑分区
硬盘分区分完之后,需要进行格式化。
格式化命令:
代码语言:javascript复制mkfs -t ext4 /dev/sdb1
硬盘挂载
硬盘分区完之后,需要挂载到空文件夹才能使用。
输入mount
,可以查询系统中已经挂载的设备。
mount命令格式:
mount [-t 文件系统] [-L 卷标名] [-o 特殊选项] 设备文件名 挂载点
选项:
-t 文件系统:加入文件系统类型来指定挂载的类型,可以ext3、ext4、iso9660等文件系统
-L 卷标名:挂载指定卷标的分区,而不是安装设备文件名挂载
-o 特殊选项:可以指定挂载的额外选项
特殊选项:
通常来说,只需要mount 设备文件名 挂载点
即可
如果需要卸载(卸载就类似于Windows中的弹出),输入umount 设备文件名
或umount 挂载点
对于外接硬盘,每次挂载完之后,重启之后需要重新挂载,因此对于长期插在机器上使用的硬盘,可以设置其自动挂载
自动挂载需要修改/etc/fstab
这个文件,该文件每行有六个字段,含义如下:
- 第一字段:分区设备文件名或UUID(硬盘通用唯一识别码)
- 第二字段:挂载点
- 第三字段:文件系统名称
- 第四字段:挂载参数
- 第五字段:指定分区是否被dump备份,0代表不备份,1代表每天备份,2代表不定期备份
- 第六字段:指定分区是否被fsck检测,0代表不检测,其他数字代表检测的优先级,那么当然1的优先级比2高
如果需要自动挂载,就在该文件中添加信息,示例如下:
注意写完之后务必要执行mount -a
,该命令是依据配置文件/etc/fstab的内容,执行自动挂载,相当于进行一次测试,如果该文件出现问题,会导致系统无法正常启动。
意外防止方案
Linux文件系统了解到这里,回到案发现场。学习完这些内容后,我联系到了服务器管理的运维人员,重装系统,重打驱动,顺利解决这个篓子。
那么,为了防止下一次出现这种状况,我总结了一些防止意外的方案。
方案一:大数据备份
该方案在很多企业中被广泛采用,基本是搭建Hadoop集群,实现数据和文件的备份,不过该方案需要依赖较多的资源投入,对于普通实验室来说并不适用。
方案二:严格权限管理
看到不少实验室共用服务器是给每一个学生都新建一个用户,这样大家各自用各自的工作区,互不影响。并且,限制用户的权限,sudo权限仅给予服务器管理员账户中,这样可以直接防止一个用户毁坏整个服务器。而且,管理员可以查看到各用户的历史记录.bash_history
,更方便管理。但麻烦之处在于每次需要管理员来单独开辟用户并授权,对于小型实验室来说过于繁琐。
方案三:回收站机制
windows有个回收站,可以防止误删文件。Linux没有这项机制,但是可以新建一个文件作为回收站,每次执行rm
命令时,自动将rm
替换成mv
,将删除的文件移动到回收站,之后定期清理回收站内容即可。
该方案主要参考自:https://blog.csdn.net/geek64581/article/details/101095854
首先创建一个回收站:
代码语言:javascript复制mkdir -p ~/.trash
然后编辑:~/.bashrc
文件
vim ~/.bashrc
文件最后添加:
代码语言:javascript复制alias rm=del
del()
{
mv $@ ~/.trash/
}
cleartrash()
{
read -p "clear sure?[Input 'y' or 'Y' to confirm. && Input 'n' to cancel.]" confirm
[ $confirm == 'y' ] || [ $confirm == 'Y' ] && /bin/rm -rf ~/.trash/*
}
保存修改退出,运行source ~/.bashrc
使其立即生效
这样就配置完毕,定期执行cleartrash
清空回收站即可
References
[1]《鸟哥的Linux私房菜》(第4版) [2]兄弟连Linux教程:https://www.bilibili.com/video/BV1DA4y1X7ZB [3]教程笔记:https://blog.csdn.net/yy150122/article/details/106146414 [4]https://blog.csdn.net/geek64581/article/details/101095854