Linux 学习笔记
Linux 学习笔记
基础 Linux 命令
软件安装
# 1. 如果软件已经添加到软件源中,使用 apt 命令
sudo apt-get install git
sudo apt install gimp -y
# 2. 使用 dpkg 命令安装 deb 包
sudo dpkg -i 文件名.deb
# ubuntu 图标一般放在 /user/share/application 下,可以复制到桌面
# 3. 使用源码安装
# 下载 tgz 文件
# 解压
tar -xzvf 文件名.tgz
# 进入目标文件夹
cd 文件名
# 编译
./configure
make
# 安装
sudo make install
美化 bash
sudo vim ~/.bashrc
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;35;40m\]\u\[\033[00;00;40m\]@\[\033[01;35;40m\]\h\[\033[00;31;40m\]:\[\033[00;00;40m\]\w \[\033[01;32;40m\]\$ \[\033[01;36;40m\]'
source ~/.bashrc
常用系统工作命令
echo
:在终端输出字符串或变量提取后的值,格式为“echo [字符串 | $变量]”
wget
:用于在终端中下载网络文件,格式为“wget [参数]下载地址”
。ps
:用于查看系统中的进程状态
Linux 系统中,有五种常见的进程状态:
- R(运行):进程正在运行或在队列中等待
- S(中断):进程处于休眠中,当某个条件形成后或者接收到信号时,则脱离该状态
- D(不可中断):进程不响应系统异步信号,即便用
kill
命令也不能将其中断- Z(僵死):进程已经终止,但进程描述符依然存在,直到父进程调用
wait4()
系统函数后将进程释放- T(停止):进程收到停止信号后停止运行
top
:用于动态监视进程活动与系统负载等信息,能够动态查看系统运维状态pidof
:用来查询某个指定服务进程的 PID 值,pidof sshd
kill
:用于终止某个指定 PID 的服务进程killall
:用于终止某个指定名称的服务器所对应的全部进程passwd
:更改使用者的密码
passwd [-k] [-l] [-u [-f]] [-d] [-S] [username]
# 修改用户密码
passwd lockegogo
# 显示账号密码信息
passed -S lockegogo
# 删除用户密码
passwd -d lockegogo
系统状态检测命令
作为一名合格的运维人员,想要更快、更好地了解 Linux 服务器,必须具备快速查看 Linux 系统运行状态的能力,因此接下来会逐个讲解与网卡网络、系统内核、系统负载、内存使用情况、当前启用终端数量、历史登录记录、命令执行记录以及及救援诊断等相关命令的使用方法。
ifconfig
:用于获取网卡配置与网络状态等信息,主要查看网卡名称、inet 参数后面的 IP 地址,ether 参数后面的网卡物理地址(又称为 MAC 地址),以及 RX & TX 的接受数据包与发送数据包的个数及累计流量
-
uname
:用于查看系统内核与系统版本等信息,一般固定搭配-a
来完整地查看当前系统的内核名称、主机名、内核发行版本、节点名、系统时间、硬件名称、硬件平台、处理器类型以及操作系统名称等信息 -
uptime
:用于查看系统的负载信息,可以显示当前系统时间,系统已运行时间、启用终端数量以及平均负载值等信息,平均负载值指的是系统在最近1分钟、5分钟、15分钟内的压力情况(下面加粗的信息部分);负载值越低越好,尽量不要长期超过1,在生产环境中不要超过5。 -
free
:用于显示当前系统中内存的使用量信息。为了保证 Linux 系统不会因资源耗尽而突然宕机,运维人员需要时刻关注内存的使用量,使用固定搭配-h
参数以更人性化的方式输出当前内存的实时使用量信息。 -
who
:用于查看当前登入主机的用户终端信息 -
last
:用于查看所有系统的登录记录,但是注意,由于这些信息都是以日志文件的形式保存在系统中,因此黑客可以很容易地对内容进行篡改,千万不要单纯以该命令的输出信息而判断系统有无恶意入侵! -
history
:用于显示历史执行过的命令,使用!5
就可以执行第五条命令,历史文件会保存到用户家目录中的.bash_history
文件中,以·.
开头的就是隐藏文件,可用cat
查看文件内容 -
sosreport
:用于收集系统配置及架构信息并输出诊断文档
工作目录切换命令
pwd
:用于显示用户当前所处的工作目录cd
:用于切换目录cd -
:返回到上一次所处的目录cd ..
:进入上级目录cd ~
:切换到当前用户的家目录
ls
:显示目录中的文件信息ls -l
:查看文件的属性、大小等详细信息ls -a
:看到全部文件,包括隐藏文件
文本文件编辑命令
cat
:用于查看纯文本文件(内容较少),加n
可以显示行号more
:用于查看纯文本文件(内容较多),一旦使用cat
命令阅读长篇的文本内容,信息就会在屏幕上快速翻滚,导致自己还没来得及看到,内容就已经翻篇了。more
会在最下面使用百分比的形式来提示您已经阅读了多少内容,您还可以使用空格键或回车键向下翻页head
:用于查看纯文本的前 N 行,head -n 20 initial-setup-ks.cfg
tail
:用于查看纯文本的后 N 行,tail
命令最强悍的功能是可以持续刷新一个文件的内容,当想要实时查看最新的日志文件时,这特别有用,tail -f /var/log/messages
tr
:用于替换文本文件中的字符,tr [原始字符] [目标字符]
当我们想要快速替换文本的一些词汇,又或者把整个文本内容都进行替换,可以先使用
cat
命令读取待处理的文本,然后通过管道符把这些文本内容传递给tr
命令进行替换操作,例如把某个文本内容中的英文全部替换为大写:cat anaconda-ks.cfg | tr [a-z] [A-Z]
wc
:用于统计指定文本的行数、字数、字节数,在 Linux 系统中,passwd
是用于保存系统账户信息的文件,要统计当前系统中有多少个用户,可以使用下面的命令来进行查询wc -l /etc/passwd
(-l
表示显示行数)stat
:用于查看文件的具体存储信息和时间等信息
cut
:用于按“列”提取文本字符,-d
设置间隔符号,-f
设置需要看的列数,例如我们用下述命令尝试提取出passwd
文件中的用户名信息:cut -d: -f1 /etc/passwd
diff
命令:用于比较多个文本文件的差异。在使用diff
命令时,不仅可以使用--brief
参数来确认两个文件是否不同,还可以使用-c
参数来详细比较多个文件的差异之处,这绝对是判断文件是否被篡改的有利神器
cat diff_A.txt
cat diff_B.txt
diff --brief diff_A.txt diff_B.txt
文件目录管理命令
touch
:用于创建空白文件或者设置文件的时间,touch -d "2017-05-04 15:44" anaconda-ks.cfg
mkdir
:用于创建空白的目录,通过-p
参数来递归创建出具有嵌套叠层关系的文件目录,mkdir -p a/b/c/d/e
cp
:用于复制文件或目录,cp 源文件 目标文件
-a:此选项通常在复制目录时使用,它保留链接、文件属性,并复制目录下的所有内容。其作用等于 dpR 参数组合。
-d:复制时保留链接。这里所说的链接相当于 Windows 系统中的快捷方式。
-f:覆盖已经存在的目标文件而不给出提示。
-i:与 -f 选项相反,在覆盖目标文件之前给出提示,要求用户确认是否覆盖,回答 y 时目标文件将被覆盖。
-p:除复制文件的内容外,还把修改时间和访问权限也复制到新文件中。
-r:若给出的源文件是一个目录文件,此时将复制该目录下所有的子目录和文件。
-l:不复制文件,只是生成链接文件。
-
mv
:用于剪切文件或将文件重命令,mv 源文件 目标路径|目标文件名
-
rm
:用于删除文件或目录,参数-r
用于删除一个目录 -
dd
:用于按照指定大小和个数的数据块来复制文件或转换文件,例如我们可以用dd
命令从 /dev/zero 设备文件中取出一个大小为 560MB 的数据块,然后保存成名为 560_file 的文件。在理解了这个命令后,以后就能随意创建任意大小的文件了:dd if=/dev/zero of=560_file count=1 bs=560M
dd
还可以压制光盘镜像文件
file
:用来查看文件的类型
打包压缩与搜索命令
tar
:用于对文件进行打包
-c: 创建压缩文件
-x:解开压缩文件
-t:查看压缩包内有哪些文件
grep
:用于在文本中执行关键词搜索,并显示匹配的结果
-b:将可执行文件(binary)当作文本文件(text)来搜索
-c:仅显示找到的行数
-i:忽略大小写
-n:显示行号
-v:反向选择——仅列出没有关键词的行
grep
命令时用途最广泛的文本搜索匹配工具,在 Linux 中,/etc/passwd
文件是保存着所有的用户信息,而一旦用户的登录终端设置为 /sbin/nologin,则不再被允许登录系统,因此可以使用grep
命令来查找出当前系统中不允许登录系统的所有用户信息:
grep /sbin/nologin /etc/passwd
find
:用于按照指定条件来查找文件
-name:匹配名称
-perm:匹配权限
-user:匹配所有者
-group:匹配所有组
-mtime -n +n 匹配修改内容的时间(-n 指 n 天以内,+n 指 n 天以前)
-atime -n +n 匹配访问文件的时间
-exec:后面可跟用于进一步处理搜索结果的命令,把 find 搜索到的结果交由紧随其后的命令作进一步处理
按照文件系统层次标准协议,Linux 系统中的配置文件会保存在 /etc 目录中,如果想要获得该目录中所有以 host 开头的文件列表,可以执行如下命令:
find /etc -name "host*" -print
如果要在整个系统中搜索权限中包括 SUID 权限的所有文件,只需要使用 -4000 即可:
find / -perm -4000 -print
注意 grep
和 find
的区别:
grep
是查找文件中匹配条件的行find
是搜索匹配条件的文件,类似于 everything
管道符、重定向与环境变量
输入输出重定向
Linux 系统默认提供三个已经打开的文件,它们的文件指针如下。
stdin
(标准输入):默认来源为键盘,文件指针编号为0
。stdout
(标准输出):默认目的地为显示器,文件指针编号为1
。stderr
(标准错误):默认目的地为显示器,文件指针编号为2
。
-
输入重定向:把文件导入到命令中
-
标准输入重定向:默认从键盘输入,也可以从其他文件或命令中输入
man bash > readme.txt
cat readme.txt
- 输出重定向:把原本要输出到屏幕的数据信息写入到指定文件中
- 标准输出重定向:默认输出到屏幕
- 错误输出重定向:默认输出到屏幕
$ demo > out.dat 2> err.txt
标准错误的重定向符号是 2>
。其中的 2
代表文件指针的编号,即 2>
表示将 2 号文件指针的写入,重定向到 err.txt
。2 号文件指针就是标准错误 stderr
。
上面示例中,demo
程序代码里面的 stderr
,会向文件 err.txt
写入报错信息。而 stdout
向文件 out.dat
写入。
管道命令符
在修改用户密码时,通常需要输入两次密码以进行确认,这在编写自动化脚本时将成为一个非常致命的缺陷。通过将管道符和 passwd
命令的 --stdin
参数相结合,我们可以用一条命令来完成密码重置操作:
echo “Fyf950209” | passwd --stdin root
命令行的通配符
通配符就是通用的匹配信息的符号,比如星号(*)代表匹配零个或多个字符,问号(?)代表匹配单个字符,中括号内加上数字 [0-9] 代表匹配 0~9 之间的单个数字的字符,而中括号内加上字母 [abc] 则是代表匹配 a、b、c 三个字符中的任意一个字符。
- 匹配所有在
/dev
目录中且以 sda 开头的文件:ls -l /dev/sda*
- 匹配所有在
/dev
目录中且以 sda 开头且后面紧跟一个字符的文件:ls -l /dev/sda?
- 使用 [0-9] 来匹配 0~9 之间的单个数字,也可以用 [135] 这样的方式仅匹配这三个指定数字中的一个:
ls -l /dev/sda[135]
常用的转义字符
4 个常见的转义字符如下:
- 反斜杠(\):使反斜杠后面的一个变量变为单纯的字符串。
- 单引号(''):转义其中所有的变量为单纯的字符串。
- 双引号(""):保留其中的变量属性,不进行转义处理。
- 反引号(``):把其中的命令执行后返回结果。
我们先定义一个名为 PRICE 的变量并赋值为 5,然后输出以双引号括起来的字符串与变量信息:
PRICE=5
echo "Price is $PRICE"
# 用反斜杠进行转义
echo "Price is \$$PRICE"
如果我们只需要某个命令的输出值时,可以将命令用反引号(不是单引号)括起来:
# 使用 echo 命令来查看本机的 Linux 版本和内核信息
echo `uname -a`
重要的环境变量
命令在Linux中的执行分为4个步骤:
- 判断用户是否以绝对路径或相对路径的方式输入命令(如/bin/ls),如果是的话则直接执行。
- Linux 系统检查用户输入的命令是否为“别名命令”,即用一个自定义的命令名称来替换原本的命令名称。
- Bash 解释器判断用户输入的是内部命令还是外部命令。
- 系统在多个路径中查找用户输入的命令文件,而定义这些路径的变量叫作 PATH,可以简单地把它理解成是“解释器的小助手”,作用是告诉 Bash 解释器待执行的命令可能存放的位置,然后 Bash 解释器就会乖乖地在这些位置中逐个查找。PATH 是由多个路径值组成的变量,每个路径值之间用冒号间隔,对这些路径的增加和删除操作将影响到Bash解释器对 Linux 命令的查找。
Linux 系统最重要的环境变量:
使用 export
命令可以将局部变量设置为全局变量,以供其他用户使用:
mkdir /home/workdir
WORKDIR=/home/workdir
export WORKDIR
Vim 编辑器与 Shell 命令脚本
Vim 编辑器
Vim 编辑器有三种模式:命令模式、末行模式和编辑模式
- 命令模式:控制光标移动,可对文本进行复制、粘贴、删除和查找等工作
- 输入模式:正常的文本录入
- 末行模式:保存或退出文档,以及设置编辑环境
每次运行 Vim 编辑器时,默认进入命令模式,此时需要先切换到输入模式后再进行文档编写工作,而每次编写完文档后需要先返回命令模式,然后再进入末行模式,执行文档的保存或退出操作。
末行模式中的常见命令:
vim practice.txt
a
键和i
键分别是在光标后面一位和光标当前位置切换到输入模式o
键则是在光标的下面再创建一个空行
第一次按 a 进入编辑模式,第二次需要追加的时候可以按 o 进入编辑模式。
配置主机名称
在 Linux 系统中,主机名大多保存在 /etc/hostname
文件中,接下来将 /etc/hostname
文件的内容修改为 “linuxprobe.com”,步骤如下。
- 使用 Vim 编辑器修改 “/etc/hostname” 主机名称文件。
- 把原始主机名称删除 (
dd
) 后追加 “linuxprobe.com”。注意,使用 Vim 编辑器修改主机名称文件后,要在末行模式下执行:wq!
命令才能保存并退出文档。 - 保存并退出文档,然后使用 hostname 命令检查是否修改成功。
配置网卡名称
网卡 IP 地址配置的是否正确是两台服务器是否可以相互通信的前提。在 Linux 系统中,一切都是文件,因此配置网络服务的工作其实就是在编辑网卡配置文件。
现在有一个名称为 ifcfg-ens32
的网卡设备,我们将其配置为开机自启动,并且 IP 地址、子网、网关等信息由人工指定,其步骤应该如下所示:
- 首先切换到
/etc/sysconfig/network-scripts
目录中(存放着网卡的配置文件) - 使用 Vim 编辑器修改网卡文件
ifcfg-ens32
,逐项写入下面的配置参数并保存退出。
设备类型:TYPE=Ethernet
地址分配模式:BOOTPROTO=static
网卡名称:NAME=eno16777736
是否启动:ONBOOT=yes
IP地址:IPADDR=192.168.10.10
子网掩码:NETMASK=255.255.255.0
网关地址:GATEWAY=192.168.10.1
DNS地址:DNS1=192.168.10.1
- 重启网络服务并测试网络是否联通:
systemctl restart network
,然后通过ping
命令测试网络能否联通。
cd /etc/sysconfig/network-scripts
vim ifcfg-ens32
TYPE=Ethernet
BOOTPROTO=static
NAME=ens32
ONBOOT=yes
IPADDR=192.168.10.10
NETMASK=255.255.255.0
GATEWAY=192.168.10.1
DNS1=192.168.10.1
systemctl restart network
ping 192.168.10.10
注意 Linux 系统中
ping
命令不会自动终止,因此需要手动按下Ctrl-c
键来强行结束进程。
配置 Yum 软件仓库
Yum 仓库的作用是为了进一步简化 RPM 管理软件的难度以及自动分析所需软件包及其依赖关系的技术。搭建并配置Yum软件仓库的大致步骤如下所示:
- 进入到
/etc/yum.repos.d/
目录中(因为该目录存放着Yum软件仓库的配置文件)。 - 使用 Vim 编辑器创建一个名为
rhel7.repo
的新配置文件(文件名称可随意,但后缀必须为.repo
),逐项写入下面加粗的配置参数并保存退出(不要写后面的中文注释)。
[rhel-media]: Yum 软件仓库唯一标识符,避免与其他仓库冲突。
name=linuxprobe: Yum 软件仓库的名称描述,易于识别仓库用处。
baseurl=file:///media/cdrom:提供的方式包括FTP(ftp://..)、HTTP(http://..)、本地(file:///..)。
enabled=1:设置此源是否可用;1为可用,0为禁用。
gpgcheck=1:设置此源是否校验文件;1为校验,0为不校验。
gpgkey=file:///media/cdrom/RPM-GPG-KEY-redhat-release:若上面参数开启校验,那么请指定公钥文件地址。
- 按配置参数的路径挂载光盘,并把光盘挂载信息写入到
/etc/fstab
文件中 - 使用
yum install httpd -y
命令检查 Yum 软件仓库是否已经可用
cd /etc/yum.repos.d/
vim rhel7.repo
[rhel-media]
name=linuxprobe
baseurl=file:///media/cdrom
enabled=1
gpgcheck=1
gpgkey=file:///media/cdrom/RPM-GPG-KEY-redhat-release
mkdir -p /media/cdrom
mount /dev/cdrom /media/cdrom
vim /etc/fstab
/dev/cdrom /media/cdrom iso9660 defaults 0 0
yum install httpd
编写 Shell 脚本
Shell 脚本命令的工作方式有两种:交互式和批处理
- 交互式(Interative):用户每输入一条命令就立即执行
- 批处理(Batch):由用户事先编写好一个完整的Shell脚本,Shell会一次性执行脚本中诸多的命令。
编写简单的脚本
如果想查看当前工作路径并列出当前目录下所有的文件及属性信息:
vim example.sh
#! /bin/bash
#For Example BY linuxprobe.com
pwd
ls -al
bash example.sh
注意,第一行的脚本声明(#!)用来告诉系统使用哪种 Shell 解释器来执行该脚本;第二行的注释信息(#)是对脚本功能和某些命令的介绍信息,使得自己或他人在日后看到这个脚本内容时,可以快速知道该脚本的作用或一些警告信息。
接受用户的参数
Linux 内设了用于接受参数的变量,变量之间可以使用空格间隔。
例如 $0
对应的是当前Shell脚本程序的名称,$#
对应的是总共有几个参数,$*
对应的是所有位置的参数值,$?
对应的是显示上一次命令的执行返回值,而 $1
、$2
、$3
……则分别对应着第N个位置的参数值,
判断用户的参数
文件测试即使用指定条件来判断文件是否存在或权限是否满足等情况的运算符,具体的参数如下:
-d: 测试文件是否为目录类型
-e: 测试文件是否存在
-f: 判断是否为一般文件
-r: 测试当前用户是否有权限读取
-w: 测试当前用户是否有权限写入
-x: 测试当前用户是否有权限执行
下面使用文件测试语句来判断 /etc/fstab
是否为一个目录类型的文件,然后通过 Shell 解释器的内设 $?
变量显示上一条命令执行后的返回值。如果返回值为 0,则目录存在;如果返回值为非零的值,则意味着目录不存在:
[ -d /etc/fstab ]
echo $?
测试语句格式:[ 条件表达式 ],注意两边均应有一个空格
逻辑语句对于测试结果进行逻辑分析,根据测试结果可实现不同的效果。例如 Shell 终端中逻辑“与”的运算符是 &&
,它表示当前面的命令执行成功后才会执行它后面的命令,因此可以用来判断 /dev/cdrom
文件是否存在:
[ -e /dev/cdrom ] && echo "Exist"
除了逻辑“与”外,还有逻辑“或”,它在 Linux 系统中的运算符号为 ||
,表示当前面的命令执行失败后才会执行它后面的命令,因此可以用来结合系统环境变量 USER 来判断当前登录的用户是否为非管理员身份:
第三种逻辑语句是“非”,在Linux系统中的运算符号是一个叹号 !
,它表示把条件测试中的判断结果取相反值。也就是说,如果原本测试的结果是正确的,则将其变成错误的;原本测试错误的结果则将其变成正确的。
当前我们正在登录的即为管理员用户——root。下面这个示例的执行顺序是,先判断当前登录用户的 USER 变量名称是否等于 root,然后用逻辑运算符“非”进行取反操作,效果就变成了判断当前登录的用户是否为非管理员用户了。最后若条件成立则会根据逻辑“与”运算符输出 user 字样;或条件不满足则会通过逻辑“或”运算符输出 root 字样,而如果前面的 &&
不成立才会执行后面的 ||
符号。
[ ! $USER = root ] && echo "user" || echo "root"
整数比较运算符仅是对数字的操作,不能将数字与字符串、文件等内容一起操作,而且不能想当然地使用日常生活中的等号、大于号、小于号等来判断。因为等号与赋值命令符冲突,大于号和小于号分别与输出重定向命令符和输入重定向命令符冲突。因此一定要使用规范的整数比较运算符来进行操作。可用的整数比较运算符如下所示。
-eq: 是否等于
-ne: 是否不等于
-gt: 是否大于
-lt: 是否小于
-le: 是否等于或小于
-ge: 是否大于或等于
[root@linuxprobe /]# [ 10 -gt 10 ]
[root@linuxprobe /]# echo $?
1
[root@linuxprobe /]# [ 10 -eq 10 ]
[root@linuxprobe /]# echo $?
0
free
命令,它可以用来获取当前系统正在使用及可用的内存量信息。接下来先使用 free -m
命令查看内存使用量情况(单位为 MB),然后通过 grep Mem
:命令过滤出剩余内存量的行,再用 awk '{print $4}’
命令只保留第四列,最后用 FreeMem=语句
的方式把语句内执行的结果赋值给变量。
free -m | grep Mem | awk '{print $4}'
FreeMem=`free -m | grep Mem | awk '{print $4}'`
echo $FreeMem
我们使用整数运算符来判断内存可用量的值是否小于1024,若小于则会提示“Insufficient Memory”(内存不足)的字样:
[ $FreeMem -lt 1024 ] && echo "Insufficient Memory"
字符串比较语句用于判断测试字符串是否为空值,或两个字符串是否相同。它经常用来判断某个变量是否未被定义(即内容是空值)。
=: 比较字符串是否相同
!=: 比较字符串内容是否不同
-z: 判断字符串内容是否为空
接下来通过判断 String 变量是否为空值,进而判断是否定义了这个变量:
[root@linuxprobe /]# [ -z $String ]
[root@linuxprobe /]# echo $?
0
流程控制语句
if
条件测试语句
if
条件语句的单分支结构由 if、then、fi
关键词组成,而且只在条件成立后才执行预设的命令,相当于口语的“如果……那么……”。
下面使用单分支的 if
条件语句来判断 /media/cdrom
目录是否存在,若存在就结束条件判断和整个 Shell 脚本,反之则去创建这个目录:
vim mkcdrom.sh
#! /bin/bash
DIR="/media/cdrom"
if [ ! -e $DIR ]
then
mkdir -p $DIR
fi
bash mkcdrom.sh
ls -d /media/cdrom
if
条件语句的双分支结构由 if、then、else、fi
关键字组成。下面使用双分支的 if
条件语句来验证某台主机是否在线,然后根据返回值的结果,要么显示主机在线信息,要么显示主机不在线信息。这里主要使用 ping
命令来测试与对方主机的网络连通性,而 Linux 系统中的 ping
命令不像 Windows 一样尝试 4 次就结束,因此为了避免用户等待时间过长,需要通过 -c
参数来规定尝试的次数,并使用 -i
参数定义每个数据包的发送间隔,以及使用 -W
参数定义等待超时时间。
vim vhkhost.sh
#! /bin/bash
ping -c 3 -i 0.2 -W 3 $1 &> /dev/null
if [ $? -eq 0 ]
then
echo "Host $1 is On-line."
else
echo "Host $1 is Off-line."
fi
bash chkhost.sh 192.168.10.10
我们之前用过
$?
变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则$?
变量会显示数字 0,反之则显示一个非零的数字(可能为 1,也可能为 2,取决于系统版本)。因此可以使用整数比较运算符来判断$?
变量是否为 0,从而获知那条语句的最终判断情况。
if
条件语句的多分支结构由 if、then、else、elif、fi
关键词组成,它进行多次条件匹配判断,这多次判断中的任何一项在匹配成功后都会执行相应的预设命令。
下面使用多分支的 if
条件语句来判断用户输入的分数在哪个成绩区间内,然后输出如 Excellent、Pass、Fail 等提示信息。在 Linux 系统中,read
是用来读取用户输入信息的命令,能够把接收到的用户输入信息赋值给后面的指定变量,-p 参数用于向用户显示一定的提示信息。在下面的脚本示例中,只有当用户输入的分数大于等于 85 分且小于等于100 分,才输出 Excellent 字样;若分数不满足该条件(即匹配不成功),则继续判断分数是否大于等于 70 分且小于等于 84 分,如果是,则输出 Pass 字样;若两次都落空(即两次的匹配操作都失败了),则输出 Fail 字样:
read -p "Enter your score (0-100):" GRADE
for
条件循环语句
for 变量名 in 取值列表
do
命令序列
done
接下来编写 Shel l 脚本 Example.sh
。在脚本中使用 read 命令读取用户输入的密码值,然后赋值给 PASSWD 变量,并通过 -p 参数向用户显示一段提示信息,告诉用户正在输入的内容即将作为账户密码。在执行该脚本后,会自动使用从列表文件 users.txt 中获取到所有的用户名称,然后逐一使用 “id用户名” 命令查看用户的信息,并使用 $?
判断这条命令是否执行成功,也就是判断该用户是否已经存在。
需要多说一句,/dev/null 是一个被称作 Linux 黑洞的文件,把输出信息重定向到这个文件等同于删除数据(类似于没有回收功能的垃圾箱),可以让用户的屏幕窗口保持简洁。
在本例中,由于多余的信息通过输出重定向符转移到了
/dev/null
黑洞文件中,因此在正常情况下屏幕窗口除了 “用户账户创建成功” 的提示后不会有其他内容。
[root@linuxprobe ~]# vim Example.sh
#! /bin/bash
read -p "Enter The Users Password : " PASSWD
for UNAME in `cat users.txt`
do
id $UNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "Already exists"
else
useradd $UNAME &> /dev/null
echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "$UNAME , Create success"
else
echo "$UNAME , Create failure"
fi
fi
done
while
条件循环语句
while
的循环结构在执行前并不确定最终执行的次数,完全不同于 for
循环中有目标、有范围的使用场景。
接下来结合使用多分支的 if
条件测试语句与 while
条件循环语句,编写一个用来猜测数值大小的脚本 Guess.sh。该脚本使用 $RANDOM 变量来调取出一个随机的数值(范围为0~32767),将这个随机数对 1000 进行取余操作,并使用 expr 命令取得其结果,再用这个数值与用户通过 read 命令输入的数值进行比较判断。这个判断语句分为三种情况,分别是判断用户输入的数值是等于、大于还是小于使用 expr 命令取得的数值。当前,现在这些内容不是重点,我们当前要关注的是 while 条件循环语句中的条件测试始终为 true,因此判断语句会无限执行下去,直到用户输入的数值等于expr 命令取得的数值后,这两者相等之后才运行 exit 0
命令,终止脚本的执行。
[root@linuxprobe ~]# vim Guess.sh
#! /bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格为0-999之间,猜猜看是多少?"
while true
do
read -p "请输入您猜测的价格数目:" INT
let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜您答对了,实际价格是 $PRICE"
echo "您总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"
fi
done
case
条件测试语句
case
语句是在多个范围内匹配数据,若匹配成功则执行相关命令并结束整个条件测试;而如果数据不在所列出的范围内,则会去执行星号(*)中所定义的默认命令。
通过在脚本中组合使用 case
条件测试语句和通配符(详见第3章),完全可以满足这里的需求。接下来我们编写脚本 Checkkeys.sh
,提示用户输入一个字符并将其赋值给变量 KEY,然后根据变量 KEY 的值向用户显示其值是字母、数字还是其他字符。
[root@linuxprobe ~]# vim Checkkeys.sh
#! /bin/bash
read -p "请输入一个字符,并按Enter键确认:" KEY
case "$KEY" in
[a-z]|[A-Z])
echo "您输入的是 字母。"
;;
[0-9])
echo "您输入的是 数字。"
;;
*)
echo "您输入的是 空格、功能键或其他控制字符。"
esac
计划任务服务程序
经验丰富的系统运维工程师可以使得 Linux 在无需认为介入的情况下,在指定的时间段自动启用或停止某些服务或命令。从而实现运维的自动化。
计划任务分为一次性计划任务与长期性计划任务,大家可以按照如下方式理解。
- 一次性计划任务:今晚 11 点 30 分开启网站服务。
- 长期性计划任务:每周一的凌晨 3 点 25 分把 /home/wwwroot 目录打包备份为 backup.tar.gz。
一次性计划任务只执行一次,一般用于满足临时的工作需求。我们可以用 at 命令实现这种功能,只需要写成 at 时间
的形式就可以。如果想要查看已设置好但还未执行的一次性计划任务,可以使用 at -l
命令;要想将其删除,可以用 atrm任务序号
。在使用 at
命令来设置一次性计划任务时,默认采用的是交互式方法。例如,使用下述命令将系统设置为在今晚 23:30 分自动重启网站服务。
[root@linuxprobe ~]# at 23:30
at > systemctl restart httpd
at > 此处请同时按下Ctrl + D组合键来结束编写计划任务
job 3 at Mon Apr 27 23:30:002017
[root@linuxprobe ~]# at -l
3 Mon Apr 27 23:30:002017 a root
# 删除任务 3
[root@linuxprobe ~]# atrm 3
[root@linuxprobe ~]# echo "systemctl restart httpd" | at 23:30
job 4 at Mon Apr 27 23:30:002017
对周期性任务来说,Linux 系统中默认启用的 crond 服务简直再适合不过了。创建、编辑计划任务的命令为 crontab -e
,查看当前计划任务的命令为 crontab -l
,删除某条计划任务的命令为 crontab -r
,另外,如果您是以管理员的身份登录的系统,还可以在 crontab
命令中加上 -u
参数来编辑他人的计划任务。
使用 crond
服务设置任务的参数格式: 分、时、日、月、星期 命令
假设在每周一、三、五的凌晨 3 点 25 分,都需要使用 tar
命令把某个网站的数据目录进行打包处理,使其作为一个备份文件。我们可以使用 crontab -e
命令来创建计划任务。为自己创建计划任务无需使用 -u
参数,具体的实现效果的参数如 crontab -l
命令结果所示:
[root@linuxprobe ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
25 3 * * 1,3,5 /usr/bin/tar -czvf backup.tar.gz /home/wwwroot
[root@linuxprobe ~]# crontab -l
25 3 * * 1,3,5 /usr/bin/tar -czvf backup.tar.gz /home/wwwroot
需要说明的是,除了用逗号(,)来分别表示多个时间段,例如 “8,9,12” 表示8月、9月和12月。还可以用减号(-)来表示一段连续的时间周期(例如字段“日”的取值为 “12-15”,则表示每月的 12~15 日)。以及用除号(/)表示执行任务的间隔时间(例如 “/2” 表示每隔 2 分钟执行一次任务)之外。
如果在 crond 服务中需要同时包含多条计划任务的命令语句,应每行仅写一条。例如我们再添加一条计划任务,它的功能是每周一至周五的凌晨 1 点钟自动清空 /tmp 目录内的所有文件。尤其需要注意的是,在 crond 服务的计划任务参数中,所有命令一定要用绝对路径的方式来写,如果不知道绝对路径,请用 whereis 命令进行查询,rm 命令路径为下面输出信息中加粗部分。
[lockegogo@linuxprobe ~]$ whereis rm
rm: /usr/bin/rm /usr/share/man/man1/rm.1.gz /usr/share/man/man1p/rm.1p.gz
[lockegogo@linuxprobe ~]$
[root@linuxprobe ~]# crontab -e
crontab: installing new crontab
0 1 * * 1-5 /usr/bin/rm -rf /tmp/*
[root@linuxprobe ~]# crontab -l
25 3 * * 1,3,5 /usr/bin/tar -czvf backup.tar.gz /home/wwwroot
0 1 * * 1-5 /usr/bin/rm -rf /tmp/*
计划任务中的“分”字段必须有数值,绝对不能为空或是
*
号;“日”和“星期”字段不能同时使用,否则就会发生冲突。
用户身份与文件权限
用户身份与能力
useradd
命令
useradd
命令用于创建新的用户,格式为 “useradd [选项] 用户名
”。
可以使用 useradd
命令创建用户账户。使用该命令创建用户账户时,默认的用户家目录会被存放在 /home 目录中,默认的 Shell 解释器为 /bin/bash,而且默认会创建一个与该用户同名的基本用户组。这些默认设置可以根据表 5-1 中的 useradd
命令参数自行修改。
-d: 指定用户的家目录
-e: 账户的到期时间,格式为 YYYY-MM-DD
-u: 指定该用户的默认 UID
-g: 指定一个初始的用户基本组
-G: 指定一个或多个扩展用户组
-N: 不创建与该用户同名的基本用户组
-s: 指定该用户的默认 Shell 解释器
下面我们创建一个普通用户并指定家目录的路径、用户的 UID 以及 Shell 解释器。在下面的命令中,请注意 /sbin/nologin,它是终端解释器中的一员,与 Bash 解释器有着天壤之别。一旦用户的解释器被设置为 nologin,则代表该用户不能登录到系统中:
[root@linuxprobe ~]# useradd -d /home/linux -u 8888 -s /sbin/nologin linuxprobe
[root@linuxprobe ~]# id linuxprobe
uid=8888(linuxprobe) gid=8888(linuxprobe) groups=8888(linuxprobe)
groupadd
命令
groupadd
命令用于创建用户组,格式为“groupadd [选项] 群组名
”。
usermod
命令
usermod
命令用于修改用户的属性,格式为“usermod [选项] 用户名
”。
在系统中创建用户也就是修改配置文件的过程,用户信息保存在 /etc/passwd
文件中,可以直接用文本编辑器来修改其中的用户参数项目:
-c: 填写用户账户的备注信息
-d: 可以重新制定用户的家目录并自动把旧的数据转移过去
-e: 账户的到期时间,格式为 YYYY-MM-DD
-g: 变更所属用户组
-G: 变更扩展用户组
-L: 锁定用户禁止其登录系统
-U: 解锁用户,允许其登录系统
-s: 变更默认终端
-u: 修改用户的 UID
我们先来看一下账户linuxprobe的默认信息:
[root@linuxprobe ~]# id lockegogo
uid=1000(lockegogo) gid=1000(lockegogo) groups=1000(lockegogo)
然后将用户 linuxprobe 加入到 root 用户组中,这样扩展组列表中则会出现 root 用户组的字样,而基本组不会受到影响:
[root@linuxprobe ~]# usermod -G root lockegogo
[root@linuxprobe ~]# id lockegogo
uid=1000(lockegogo) gid=1000(lockegogo) groups=1000(lockegogo),0(root)
passwd
命令
passwd
命令用于修改用户密码、过期时间、认证信息等,格式为“passwd [选项][用户名]
”。
普通用户只能使用passwd
命令修改自身的系统密码,而 root 管理员则有权限修改其他所有人的密码。更酷的是,root管理员在 Linux 系统中修改自己或他人的密码时不需要验证旧密码,这一点特别方便。既然 root 管理员可以修改其他用户的密码,就表示完全拥有该用户的管理权限。
-l: 锁定用户,禁止其登录
-u: 解除锁定,允许用户登录
--stdin: 允许通过标准输入修改用户密码
-d: 该用户可用空密码登录
-e: 强制用户在下次登录时修改密码
-S: 显示用户的密码是否被锁定,以及密码所采用的加密算法名称
userdel
命令
userdel
命令用于删除用户,格式为“userdel [选项] 用户名
”。
-f: 强制删除用户
-r: 同时删除用户及用户家目录
chmod
命令
chmod
命令是一个非常实用的命令,能够用来设置文件或目录的权限,格式为“chmod [参数] 权限 文件或目录名称
”。
[root@linuxprobe ~]# ls -al test
-rw-rw-r--. 1 linuxprobe root 15 Feb 11 11:50 test
[root@linuxprobe ~]# chmod 760 test
[root@linuxprobe ~]# ls -l test
-rwxrw----. 1 linuxprobe root 15 Feb 11 11:50 test
chown
命令
chown
命令设置文件或目录的所有者和所属组,其格式为“chown [参数] 所有者:所属组 文件或目录名称
”。
[root@linuxprobe ~]# ls -l test
-rwxrw----. 1 linuxprobe root 15 Feb 11 11:50 test
[root@linuxprobe ~]# chown root:bin test
[root@linuxprobe ~]# ls -l test
-rwxrw----. 1 root bin 15 Feb 11 11:50 test
chmod
和chown
命令是用于修改文件属性和权限的最常用命令,它们还有一个特别的共性,就是针对目录进行操作时需要加上大写参数-R
来表示递归操作,即对目录内所有的文件进行整体操作。
文件权限与归属
Linux 系统使用了不同的字符来区分不同的文件:
-: 普通文件
d: 目录文件
l: 链接文件
b: 块设备文件
c: 字符设备文件
p: 管道文件
-
对一般文件来说:
- “可读”表示能够读取文件的实际内容
- “可写”表示能够编辑、新增、修改、删除文件的实际内容
- “可执行”则表示能够运行一个脚本程序。
-
对目录文件来说:
- “可读”表示能够读取目录内的文件列表
- “可写”表示能够在目录内新增、删除、重命名文件
- “可执行”则表示能够进入该目录。
文件的读、写、执行权限可以简写为 rwx
,亦可分别用数字 4、2、1 来表示,文件所有者,所属组及其他用户权限之间无关联。
文件的特殊权限
在复杂多变的生产环境中,单纯设置文件的 rwx 权限无法满足我们对安全和灵活性的需求,因此便有了 SUID
、SGID
和 SBIT
的特殊权限位。这是一种对文件权限进行设置的特殊功能,可以与一般权限同时使用,以弥补一般权限不能实现的功能:
SUID
SUID 是一种对二进制程序进行设置的特殊权限,可以让二进制程序的执行者临时拥有属主的权限。
例如,所有用户都可以执行 passwd
命令来修改自己的用户密码,而用户密码保存在 /etc/shadow
文件中。仔细查看这个文件就会发现它的默认权限是 000,也就是说除了 root 管理员以外,所有用户都没有查看或编辑该文件的权限。
但是,在使用 passwd
命令时如果加上 SUID 特殊权限位,就可以让普通用户临时获得程序所有者的身份,把变更的密码信息写入到 shadow
文件中。
[root@linuxprobe /]# ls -l /etc/shadow
----------. 1 root root 1275 Nov 2 23:25 /etc/shadow
[root@linuxprobe /]# ls -l /bin/passwd
-rwsr-xr-x. 1 root root 27936 Mar 23 2019 /bin/passwd
rwx 变成了 rws,表明该文件被赋予了 SUID 权限
SGID
SGID 主要实现如下两种功能:
- 让执行者临时拥有属组的权限(对拥有执行权限的二进制程序进行设置);
- 在某个目录中创建的文件自动继承该目录的用户组(只可以对目录进行设置)。
SBIT
现在,大学里的很多老师都要求学生将作业上传到服务器的特定共享目录中,但总是有几个“破坏分子”喜欢删除其他同学的作业,这时就要设置 SBIT(Sticky Bit)特殊权限位了(也可以称之为特殊权限位之粘滞位)。SBIT 特殊权限位可确保用户只能删除自己的文件,而不能删除其他用户的文件。换句话说,当对某个目录设置了 SBIT 粘滞位权限后,那么该目录中的文件就只能被其所有者执行删除操作了。
RHEL 7 系统中的 /tmp
作为一个共享文件的目录,默认已经设置了 SBIT 特殊权限位,因此除非是该目录的所有者,否则无法删除这里面的文件。
与前面所讲的 SUID 和 SGID 权限显示方法不同,当目录被设置 SBIT 特殊权限位后,文件的其他人权限部分的 x 执行权限就会被替换成 t 或者 T:原本有 x 执行权限则会写成 t,原本没有 x 执行权限则会被写成 T。
[root@linuxprobe tmp]# su - linuxprobe
Last login: Wed Feb 11 12:41:20 CST 2017 on pts/0
[linuxprobe@linuxprobe tmp]$ ls -ald /tmp
drwxrwxrwt . 17 root root 4096 Feb 11 13:03 /tmp
[linuxprobe@linuxprobe ~]$ cd /tmp
[linuxprobe@linuxprobe tmp]$ ls -ald
drwxrwxrwt . 17 root root 4096 Feb 11 13:03 .
[linuxprobe@linuxprobe tmp]$ echo "Welcome to linuxprobe.com" > test
[linuxprobe@linuxprobe tmp]$ chmod 777 test
[linuxprobe@linuxprobe tmp]$ ls -al test
-rwxrwxrwx. 1 linuxprobe linuxprobe 10 Feb 11 12:59 test
当然,要是也想对其他目录来设置 SBIT 特殊权限位,用 chmod 命令就可以了。对应的参数 o+t
代表设置 SBIT 粘滞位权限:
[blackshield@linuxprobe tmp]$ exit
Logout
[root@linuxprobe tmp]# cd ~
[root@linuxprobe ~]# mkdir linux
[root@linuxprobe ~]# chmod -R o+t linux/
[root@linuxprobe ~]# ls -ld linux/
drwxr-xr-t. 2 root root 6 Feb 11 19:34 linux/
文件的隐藏权限
Linux系统中的文件除了具备一般权限和特殊权限之外,还有一种隐藏权限,即被隐藏起来的权限,默认情况下不能直接被用户发觉。
chattr
命令
chattr
命令用于设置文件的隐藏权限,格式为“chattr [参数] 文件
”。如果想要把某个隐藏功能添加到文件上,则需要在命令后面追加“+参数”,如果想要把某个隐藏功能移出文件,则需要追加“-参数”。
[root@linuxprobe ~]# echo "for Test" > linuxprobe
[root@linuxprobe ~]# chattr +a linuxprobe
[root@linuxprobe ~]# rm linuxprobe
rm: remove regular file ‘linuxprobe’? y
rm: cannot remove ‘linuxprobe’: Operation not permitted
lsattr
命令
lsattr
命令用于显示文件的隐藏权限,格式为“lsattr [参数] 文件
”。在 Linux 系统中,文件的隐藏权限必须使用lsattr
命令来查看,平时使用的 ls
之类的命令则看不出端倪:
[root@linuxprobe ~]# ls -al linuxprobe
-rw-r--r--. 1 root root 9 Feb 12 11:42 linuxprobe
一旦使用 lsattr
命令后,文件上被赋予的隐藏权限马上就会原形毕露。此时可以按照显示的隐藏权限的类型(字母),使用 chattr
命令将其去掉:
[root@linuxprobe ~]# lsattr linuxprobe
-----a---------- linuxprobe
[root@linuxprobe ~]# chattr -a linuxprobe
[root@linuxprobe ~]# lsattr linuxprobe
---------------- linuxprobe
[root@linuxprobe ~]# rm linuxprobe
rm: remove regular file ‘linuxprobe’? y
文件访问控制列表
TODO
su
命令与 sudo
服务
su
命令可以解决切换用户身份的需求,使得当前用户在不退出登录的情况下,顺畅地切换到其他用户,比如从 root 管理员切换至普通用户:
[root@linuxprobe ~]# id
uid=0(root) gid=0(root) groups=0(root)
[root@linuxprobe ~]# su - linuxprobe
Last login: Wed Jan 4 01:17:25 EST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ id
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe) context=unconfined_
u:unconfined_r:unconfined_t:s0-s0:c0.c1023
上面的 su
命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。
另外,当从 root 管理员切换到普通用户时是不需要密码验证的,而从普通用户切换成 root 管理员就需要进行密码验证了;这也是一个必要的安全检查:
[linuxprobe@linuxprobe root]$ su root
Password:
[root@linuxprobe ~]# su - linuxprobe
Last login: Mon Aug 24 19:27:09 CST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ exit
logout
sudo
命令需要输入当前用户的密码,su
命令需要输入 root
用户的密码。
sudo
命令只允许使用提升的权限运行单个命令,而 su
命令会启动一个新的 shell,同时允许使用 root 权限运行尽可能多的命令,直到明确退出登录。
存储结构与磁盘划分
一切从 "/" 开始
在 Windows 操作系统中,想要找到一个文件,我们要依次进入该文件所在的磁盘分区(假设这里是 D 盘),然后在进入该分区下的具体目录,最终找到这个文件。
但是在 Linux 系统中并不存在 C/D/E/F 等盘符,Linux 系统中的一切文件都是从根 "/" 目录开始的,并按照文件系统层次化标准(FHS)采用树形结构来存放文件,已经定义了常见目录的用途。
Linux 系统中的文件和目录名称是严格区分大小写的。
目录名称 | 应放置文件的内容 |
---|---|
/boot | 开机所需文件:内核、开机菜单以及所需配置文件等 |
/dev | 以文件形式存放任何设备与接口 |
/etc | 配置文件 |
/home | 用户家目录 |
/bin | 存放单用户模式下还可以操作的命令 |
/lib | 开机时用到的函数库,以及 /bin 与 /sbin 下面的命令要调用的函数 |
/sbin | 开机过程中需要的命令 |
/media | 用于挂载设备文件的目录 |
/opt | 放置第三方的软件 |
/root | 系统管理员的家目录 |
/srv | 一些网络服务的数据文件目录 |
/tmp | 任何人均可使用的共享临时目录 |
/proc | 虚拟文件系统、例如系统内核、进程、外部设备及网络状态等 |
/usr/local | 用户自行安装的软件 |
/usr/sbin | Linux 系统开机时不会使用到的软件 / 命令 / 脚本 |
/usr/share | 帮助与说明文件,也可放置共享文件 |
/var | 主要存放经常变化的文件,如日志 |
/lost+found | 当文件系统发生错误时,将一些丢失的文件片段存放在这里 |
物理设备的命名规则
系统内核中的 udev
设备管理器会自动把硬件名称规范起来,目的是让用户通过设备文件的名字可以猜出设备大致的属性以及分区信息等。
首先,/dev/ 目录中保存的应当是硬件设备文件;其次,sd 表示是存储设备;然后,a表示系统中同类接口中第一个被识别到的设备,最后,5 表示这个设备是一个逻辑分区。一言以蔽之,“/dev/sda5” 表示的就是“这是系统中第一块被识别到的硬件设备中分区编号为 5 的逻辑分区的设备文件”。
硬盘设备是由大量的扇区组成的,每个扇区的容量为 512 字节,其中第一个扇区最重要,它里面保存着主引导记录与分区表信息。就第一个扇区来讲,主引导记录需要占用446字节,分区表为64字节,结束符占用2字节;其中分区表中每记录一个分区信息就需要16字节,这样一来最多只有 4 个分区信息可以写到第一个扇区中,这4个分区就是4个主分区。
问题是:第一个扇区最多只能创建出 4 个分区?于是为了解决分区个数不够的问题,可以将第一扇区的分区表中 16 字节(原本要写入主分区信息)的空间(称之为扩展分区)拿出来指向另外一个分区,也就是说,扩展分区其实并不是一个真正的分区,而更像是一个占用 16 字节分区表空间的指针(指向下一个分区,这种指针结构形成一个单向链表),这样,用户选择使用 3 个主分区加 1 个扩展分区的方法,然后在扩展分区中创建出数个逻辑分区,从而来满足多分区的需求。
文件系统和数据资料
文件系统的作用是合理规划硬盘,以保证用户正常的使用需求,常见的文件系统如下所示:
- Ext3:日志文件系统,能够在系统异常宕机时避免文件系统资料丢失,并能自动修复数据的不一致与错误。它会把整个磁盘的每个写入动作的细节都预先记录下来,以便在发生异常宕机之后能回溯追踪到被中断的部分,然后尝试进行修复。
- Ext4:Ext3 的改进版本,它支持的存储容量高达1EB(1EB=1,073,741,824GB),且能够有无限多的子目录。另外,Ext4文件系统能够批量分配block块,从而极大地提高了读写效率。
- XFS:高性能的日志文件系统,优势在于发生意外后可以快速恢复可能被破坏的文件。并且它最大可支持的存储容量为18EB,这几乎满足了所有需求。
挂载硬件设备
在拿到一块全新的硬盘存储设备后要先分区,然后格式化,最后才能挂载并正常使用。
当用户需要使用硬盘设备或分区中的数据时,需要先将其与一个已存在的目录文件进行关联,这个关联动作就是“挂载”。
mount 命令
mount
命令用于挂载文件系统,格式为“mount 文件系统 挂载目录
”。挂载是在使用硬件设备前所执行的最后一步操作,只需使用 mount
命令将硬盘设备或分区与一个目录文件进行关联,然后就能在这个目录中看到硬件设备中的数据了。
mount
中的 -a
参数则厉害了,它会在执行后自动检查 /etc/fstab
文件中有无疏漏被挂载的设备文件,如果有,则进行自动挂载操作。
-a
:挂载所有在/etc/fstab
中定义的文件系统
例如,要把设备 /dev/sdb2 挂载到 /backup 目录,只需要在 mount 命令中填写设备与挂载目录参数就行,系统会自动去判断要挂载文件的类型,因此只需要执行下述命令即可:
mount /dev/sdb2 /backup
虽然按照上面的方法执行 mount 命令后就能立即使用文件系统了,但系统在重启后挂载就会失效,也就是说我们需要每次开机后都手动挂载一下。这肯定不是我们想要的效果,如果想让硬件设备和目录永久地进行自动关联,就必须把挂载信息按照指定的填写格式 “设备文件 挂载目录 格式类型 权限选项 自检 优先级
” 写入到 /etc/fstab
文件中。这个文件中包含着挂载所需的诸多信息项目,一旦配置好之后就能一劳永逸了。
字段 | 意义 |
---|---|
设备文件 | 一般为设备的路径 + 设备名称,也可以写唯一识别码(UUID) |
挂载目录 | 指定要挂载到的目录,需在挂载前创建好 |
格式类型 | 指定文件系统的格式,比如 Ext3 |
权限选项 | 若设置为 defaults,则默认权限为:rw,suid, dev,exec |
自检 | 若为 1 则开机后进行磁盘自检,为 0 则不自检 |
优先级 | 若自检字段为 1,则可对多块硬盘进行自检优先级设置 |
如果想将文件系统为 ext4 的硬件设备 /dev/sdb2 在开机后自动挂载到 /backup 目录上,并保持默认权限且无需开机自检,就需要在 /etc/fstab 文件中写入下面的信息,这样在系统重启后也会成功挂载。
[root@linuxprobe ~]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed May 4 19:26:23 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 1 1
UUID=812b1f7c-8b5b-43da-8c06-b9999e0fe48b /boot xfs defaults 1 2
/dev/mapper /rhel-swap swap swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb2 /backup ext4 defaults 0 0
umount 命令
umount
命令用于撤销已经挂载的设备文件,格式为 “umount [挂载点/设备文件]
” 。我们挂载文件系统的目的是为了使用硬件资源,而卸载文件系统就意味着不再使用硬件的设备资源。相对应地,挂载操作就是把硬件设备与目录进行关联的动作,因此卸载操作只需要说明想要取消关联的设备文件或挂载目录的其中一项即可,一般不需要加其他额外的参数。我们来尝试手动卸载掉 /dev/sdb2
设备文件:
umount /dev/sdb2
添加硬件设备
我们先来理清一下添加硬盘设备的思路:首先需要在虚拟机中模拟添加一块新的硬盘存储设备,然后再进行分区、格式化、挂载等操作,最后通过检查系统的挂载状态并真实地使用硬盘来验证硬盘设备是否成功添加。
首先把虚拟机系统关机,稍等几分钟会自动返回到虚拟机管理主界面,然后单击“编辑虚拟机设置”选项,在弹出的界面中单击“添加”按钮,新增一块硬件设备,如图6-6所示。
在虚拟机中模拟添加了硬盘设备后就应该能看到抽象成的硬盘设备文件了,按照前文讲解的 udev 服务命名规则,第二个被识别的 SCSI 设备应该会被保存为 /dev/sdb,这个就是硬盘设备文件了。
fdisk 命令
在 Linux 系统中,管理硬盘设备最常用的方法就当属 fdisk
命令了。fdisk
命令用于管理磁盘分区,格式为“fdisk [磁盘名称]
”,它提供了集添加、删除、转换分区等功能于一身的“一站式分区服务”。不过与前面讲解的直接写到命令后面的参数不同,这条命令的参数(见表6-5)是交互式的,因此在管理硬盘设备时特别方便,可以根据需求动态调整。
参数 | 作用 |
---|---|
m | 显示菜单和帮助信息 |
a | 活动分区标记 / 引导分区 |
d | 删除分区 |
l | 显示分区类型 |
n | 新建分区 |
p | 显示分区信息 |
q | 退出不保存 |
t | 设置分区号 |
v | 进行分区检查 |
w | 保存修改 |
x | 扩展应用,高级功能 |
我们首先使用 fdisk
命令来尝试管理 /dev/sdb 硬盘设备。在看到提示信息后输入参数 p 来查看硬盘设备内已有的分区信息,其中包括了硬盘的容量大小、扇区个数等信息:
[root@linuxprobe ~]# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table
Building a new DOS disklabel with disk identifier 0x2772e830.
Command (m for help): p
Disk /dev/sdb: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x2772e830
Device Boot Start End Blocks Id System
Command (m for help):
输入参数 n 尝试添加新的分区,系统会要求您是选择继续输入参数 p 来创建主分区,还是输入参数 e 来创建扩展分区。这里输入参数 p 来创建一个主分区:
Command (m for help): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-41943039, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-41943039, default 41943039): +2G
Partition 1 of type Linux and of size 2 GiB is set
最后,系统会要求定义分区的结束扇区位置,这其实就是要去定义整个分区的大小是多少。我们不用去计算扇区的个数,只需要输入 +2G 即可创建出一个容量为 2GB 的硬盘分区。
再次使用参数 p 来查看硬盘设备中的分区信息。果然就能看到一个名称为 /dev/sdb1
、起始扇区位置为 2048、结束扇区位置为 4196351 的主分区了。这时候千万不要直接关闭窗口,而应该敲击参数 w 后回车,这样分区信息才是真正的写入成功啦。
在上述步骤执行完毕之后,Linux 系统会自动把这个硬盘主分区抽象成 /dev/sdb1
设备文件。我们可以使用 file
命令查看该文件的属性,
如果硬件存储设备没有进行格式化,则 Linux 系统无法得知怎么在其上写入数据。因此,在对存储设备进行分区后还需要进行格式化操作,命令为 mkfs
,mkfs.文件类型名称
。例如要格式分区为XFS的文件系统,则命令应为:
[root@linuxprobe ~]# mkfs.xfs /dev/sdb1
终于完成了存储设备的分区和格式化操作,接下来就是要来挂载并使用存储设备了。与之相关的步骤也非常简单:
- 首先是创建一个用于挂载设备的挂载点目录;
- 然后使用
mount
命令将存储设备与挂载点进行关联; - 最后使用
df -h
命令来查看挂载状态和硬盘使用量信息。
[root@linuxprobe ~]# mkdir /newFS
[root@linuxprobe ~]# mount /dev/sdb1 /newFS/
[root@linuxprobe ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 18G 3.5G 15G 20% /
devtmpfs 905M 0 905M 0% /dev
tmpfs 914M 140K 914M 1% /dev/shm
tmpfs 914M 8.8M 905M 1% /run
tmpfs 914M 0 914M 0% /sys/fs/cgroup
/dev/sr0 3.5G 3.5G 0 100% /media/cdrom
/dev/sda1 497M 119M 379M 24% /boot
/dev/sdb1 2.0G 33M 2.0G 2% /newFS
du 命令
既然存储设备已经顺利挂载,接下来就可以尝试通过挂载点目录向存储点设备中写入文件了,在写入文件之前,先介绍一下用于查看文件数据占用量的 du
命令。其格式为:du [选项] [文件]
,用来查看一个或多个文件占用了多大的硬盘空间:
[root@linuxprobe ~]# cp -rf /etc/* /newFS/
[root@linuxprobe ~]# ls /newFS/
abrt hosts pulse
adjtime hosts.allow purple
aliases hosts.deny qemu-ga
aliases.db hp qemu-kvm
alsa idmapd.conf radvd.conf
alternatives init.d rc0.d
anacrontab inittab rc1.d
………………省略部分输入信息………………
[root@linuxprobe ~]# du -sh /newFS/
48M /newFS/
记得将挂载信息写入到文件中,否则重启时信息会丢失。
[root@linuxprobe ~]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed May 4 19:26:23 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 1 1
UUID=812b1f7c-8b5b-43da-8c06-b9999e0fe48b /boot xfs defaults 1 2
/dev/mapper /rhel-swap swap swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
添加交换分区
SWAP(交换)分区是一种通过在硬盘中预先划分一定的空间,然后将把内存中暂时不常用的数据临时存放到硬盘中,以便腾出物理内存空间让更活跃的程序服务来使用的技术,其设计目的是为了解决真实物理内存不足的问题。
交换分区的创建过程与前文讲到的挂载并使用存储设备的过程非常相似。在对 /dev/sdb
存储设备进行分区操作前,有必要先说一下交换分区的划分建议:在生产环境中,交换分区的大小一般为真实物理内存的1.5~2倍,为了让大家更明显地感受交换分区空间的变化,这里取出一个大小为 5GB 的主分区作为交换分区资源。在分区创建完毕后保存并退出即可:DU
fdisk /dev/sdb
n
p
2
+5G
p
w
使用 SWAP
分区专用的格式化命令 mkswap
,对新建的主分区进行格式化操作:
mkswap /dev/sdb2
注意和普通的格式化进行比较:
mkfs.xfs /dev/sdb1
使用 swapon
命令把准备好的 SWAP 分区设备正式挂载到系统中。我们可以使用 free -m
命令查看交换分区的大小变化(由 2047MB 增加到 7167MB):
[root@linuxprobe ~]# free -m
total used free shared buff/cache available
Mem: 1819 770 451 13 597 884
Swap: 2047 0 2047
[root@linuxprobe ~]# swapon /dev/sdb2
[root@linuxprobe ~]# free -m
total used free shared buff/cache available
Mem: 1819 775 446 13 597 879
Swap: 7167 0 7167
[root@linuxprobe ~]#
为了能够让新的交换分区设备在重启后依然生效,需要按照下面的格式将相关挂载信息写入到配置文件中,并记得保存:
[root@linuxprobe ~]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed May 4 19:26:23 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 1 1
UUID=812b1f7c-8b5b-43da-8c06-b9999e0fe48b /boot xfs defaults 1 2
/dev/mapper /rhel-swap swap swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0
再回顾一下:添加新硬盘后,操作步骤为:
分区 \(\to\) 格式化(普通格式化 / 交换分区格式化)\(\to\) 挂载 \(\to\) 将挂载信息写入配置文件(/etc/fstab)。
磁盘容量配额
root 管理员可以使用磁盘容量配额服务来限制某位用户或某个用户组针对特定文件夹可以使用的最大磁盘空间或最大文件个数,一旦达到这个最大值就不再允许继续使用。可以使用 quota
进行磁盘容量配额管理,从而限制用户的硬盘可用容量或所能创建的最大文件个数。quota 命令还有软限制和硬限制的功能。
- 软限制:当达到软限制时会提示用户,但仍允许用户在限定的额度内继续使用。
- 硬限制:当达到硬限制时会提示用户,且强制终止用户的操作。
RHEL 7 系统中已经安装了 quota 磁盘容量配额服务程序包,但存储设备却默认没有开启对 quota 的支持,此时需要手动编辑配置文件,让 RHEL 7 系统中的 /boot 目录能够支持 quota 磁盘配额技术。
[root@linuxprobe ~]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed May 4 19:26:23 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 1 1
UUID=812b1f7c-8b5b-43da-8c06-b9999e0fe48b /boot xfs defaults,uquota 1 2
/dev/mapper /rhel-swap swap swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0
[root@linuxprobe ~]# reboot
[root@linuxprobe ~]# mount | grep boot
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,usrquota
)
接下来创建一个用于检查 quota
磁盘容量配额效果的用户 tom,并针对 /boot 目录增加其他人的写权限,保证用户能够正常写入数据:
[root@linuxprobe ~]# useradd tom
[root@linuxprobe ~]# chmod -Rf o+w /boot
xfs_quota 命令
xfs_quota
命令是一个专门针对 XFS 文件系统来管理 quota 磁盘容量配额服务而设计的命令,格式为:quota [参数] 配额 文件系统
。其中,-c
参数用于以参数的形式设置要执行的命令;-x
参数是专家模式,让运维人员能够对 quota 服务进行更多复杂的配置。接下来我们使用xfs_quota 命令来设置用户 tom 对 /boot 目录的 quota 磁盘容量配额。具体的限额控制包括:硬盘使用量的软限制和硬限制分别为 3MB 和 6MB;创建文件数量的软限制和硬限制分别为 3 个和 6 个。
[root@linuxprobe ~]# xfs_quota -x -c 'limit bsoft=3m bhard=6m isoft=3 ihard=6
tom' /boot
[root@linuxprobe ~]# xfs_quota -x -c report /boot
User quota on /boot (/dev/sda1) Blocks
User ID Used Soft Hard Warn/Grace
---------- -----------------------------------------
root 95084 0 0 00 [--------]
tom 0 3072 6144 00 [--------]
当配置好上述的各种软硬限制后,尝试切换到这个普通用户,然后分别尝试创建一个体积为 5MB 和 8MB 的文件。可以发现,在创建 8MB 的文件时受到了系统限制:
[root@linuxprobe ~]# su - tom
[tom@linuxprobe ~]$ dd if=/dev/zero of=/boot/tom bs=5M count=1
1+0 records in
1+0 records out
5242880 bytes (5.2 MB) copied, 0.123966 s, 42.3 MB/s
[tom@linuxprobe ~]$ dd if=/dev/zero of=/boot/tom bs=8M count=1
dd: error writing ‘/boot/tom’: Disk quota exceeded
1+0 records in
0+0 records out
6291456 bytes (6.3 MB) copied, 0.0201593 s, 312 MB/s
edquota 命令
edquota
命令用于编辑用户的 quota
配额限制,格式为“edquota [参数] [用户]
”。在为用户设置了 quota
磁盘容量配额限制后,可以使用 edquota
命令按需修改限额的数值。其中,-u
参数表示要针对哪个用户进行设置;-g
参数表示要针对哪个用户组进行设置。
[root@linuxprobe ~]# edquota -u tom
Disk quotas for user tom (uid 1001):
Filesystem blocks soft hard inodes soft hard
/dev/sda 6144 3072 8192 1 3 6
[root@linuxprobe ~]# su - tom
Last login: Mon Sep 7 16:43:12 CST 2017 on pts/0
[tom@linuxprobe ~]$ dd if=/dev/zero of=/boot/tom bs=8M count=1
1+0 records in
1+0 records out
8388608 bytes (8.4 MB) copied, 0.0268044 s, 313 MB/s
[tom@linuxprobe ~]$ dd if=/dev/zero of=/boot/tom bs=10M count=1
dd: error writing ‘/boot/tom’: Disk quota exceeded
1+0 records in
0+0 records out
8388608 bytes (8.4 MB) copied, 0.167529 s, 50.1 MB/s
软硬方式链接
在 Linux 系统中存在硬链接和软连接两种文件。
- 硬链接(hard link):可以将它理解为一个“指向原始文件 inode 的指针”,系统不为它分配独立的 inode 和文件,所以,硬链接文件与原始文件其实是同一个文件,只是名字不同。我们每添加一个硬链接,该文件的 inode 连接数就会增加1;而且只有当该文件的 inode 连接数为 0 时,才算彻底将它删除。
- 软链接(也称为符号链接[symbolic link]):仅仅包含所链接文件的路径名,因此能链接目录文件,也可以跨越文件系统进行链接。但是,当原始文件被删除后,链接文件也将失效,从这一点上来说与 Windows 系统中的“快捷方式”具有一样的性质。
ln 命令
ln
命令用于创建链接文件,格式为 “ln [选项] 目标
”:
参数 | 作用 |
---|---|
-s |
创建“符号链接” (软链接) |
-f |
强制创建文件或目录的链接 |
-i |
覆盖前先访问 |
-v |
显示创建链接的过程 |
接下来创建一个类似于Windows系统中快捷方式的软链接。这样,当原始文件被删除后,就无法读取新建的链接文件了:
[root@linuxprobe ~]# echo "Welcome to linuxprobe.com" > readme.txt
[root@linuxprobe ~]# ln -s readme.txt readit.txt
[root@linuxprobe ~]# cat readme.txt
Welcome to linuxprobe.com
[root@linuxprobe ~]# cat readit.txt
Welcome to linuxprobe.com
[root@linuxprobe ~]# ls -l readme.txt
-rw-r--r-- 1
root root 26 Jan 11 00:08 readme.txt
[root@linuxprobe ~]# rm -f readme.txt
[root@linuxprobe ~]# cat readit.txt
cat: readit.txt: No such file or directory
接下来针对一个原始文件创建一个硬链接,即相当于针对原始文件的硬盘存储位置创建了一个指针,这样一来,新创建的这个硬链接就不再依赖于原始文件的名称等信息,也不会因为原始文件的删除而导致无法读取。同时可以看到创建硬链接后,原始文件的硬盘链接数量增加到了 2。
[root@linuxprobe ~]# echo "Welcome to linuxprobe.com" > readme.txt
[root@linuxprobe ~]# ln readme.txt readit.txt
[root@linuxprobe ~]# cat readme.txt
Welcome to linuxprobe.com
[root@linuxprobe ~]# cat readit.txt
Welcome to linuxprobe.com
[root@linuxprobe ~]# ls -l readme.txt
-rw-r--r-- 2
root root 26 Jan 11 00:13 readme.txt
[root@linuxprobe ~]# rm -f readme.txt
[root@linuxprobe ~]# cat readit.txt
Welcome to linuxprobe.com
RAID 与 LVM 磁盘阵列技术
RAID (独立冗余磁盘阵列)
RAID 技术通过把多个硬盘设备组合成一个容量更大,安全性更好的磁盘阵列,并把数据切分成多个区段后分别存放在各个不同的物理硬盘设备上,然后利用分散读写技术来提升磁盘阵列整体的性能,同时把多个重要数据的副本同步到不同的物理硬盘设备上,从而起到了非常好的数据冗余备份效果。
RAID 0
RAID 0 技术把多块物理硬盘设备(至少两块)通过硬件或软件的方式串联在一起,组成一个大的卷组,并将数据依次写入到各个物理硬盘中。这样一来,在最理想的状态下,硬盘设备的读写性能会提升数倍,但是若任意一块硬盘发生故障将导致整个系统的数据都受到破坏。
RAID 1
RAID 1 是把两块以上的硬盘设备进行绑定,在写入数据时,是将数据同时写入到多块硬盘设备上(可以将其视为数据的镜像或备份)。当其中某一块硬盘发生故障后,一般会立即自动以热交换的方式来恢复数据的正常使用。
RAID 5
RAID 5 技术是把硬盘设备的数据奇偶校验信息保存到其他硬盘设备中。数据的奇偶校验信息并不是单独保存到某一块硬盘设备中,而是存储到除自身以外的其他每一块硬盘设备上,这样的好处是其中任何一设备损坏后不至于出现致命缺陷。换句话说,就是 RAID 5 技术实际上没有备份硬盘中的真实数据信息,而是当硬盘设备出现问题后通过奇偶校验信息来尝试重建损坏的数据。RAID 这样的技术特性“妥协”地兼顾了硬盘设备的读写速度、数据安全性与存储成本问题。
RAID 10
RAID 10 技术是 RAID 1 + RAID 0 技术的一个“组合体”。RAID 10 技术需要至少 4 块硬盘来组建,其中先分别两两制作成 RAID 1 磁盘阵列,以保证数据的安全性;然后再对两个 RAID 1 磁盘阵列实施 RAID 0 技术,进一步提高硬盘设备的读写速度。这样从理论上来讲,只要坏的不是同一组中的所有硬盘,那么最多可以损坏 50% 的硬盘设备而不丢失数据。由于RAID 10技术继承了 RAID 0 的高读写速度和 RAID 1 的数据安全性,在不考虑成本的情况下 RAID 10 的性能都超过了 RAID 5,因此当前成为广泛使用的一种存储技术。
部署磁盘阵列
- 首先在虚拟机中添加 4 块硬盘来制作一个 RAID 10 的磁盘阵列;
mdadm
命令用于管理 Linux 系统中的软件 RAID 硬盘阵列,格式为“mdadm [模式] <RAID设备名称> [选项] [成员设备名称]
”。接下来,使用mdadm
命令创建 RAID 10,名称为“/dev/md0
”。
参数 | 详细信息 |
---|---|
-D | 显示 RAID 设备的详细信息 |
-F | 选项监控模式 |
-G | 更改 RAID 设备的大小或形态 |
-I | 添加设备到 RAID 中,或从 RAID 中删除设备 |
-z | 组建 RAID1、RAID4、RAID5、RAID6 后从每个 RAID 成员获取的空间容量 |
-s | 扫描配置文件或 /proc/mdstat 以搜寻丢失的信息 |
-C | 把 RAID 信息写入每个成员超级块中 |
-v | 显示 RAID 创建过程中的详细信息 |
-B | 不把 RAID 信息写入每个成员的超级块中 |
-l | 指定 RAID 的级别 |
-n | 指定 RAID 中活动设备的数目 |
-f | 把 RAID 成员列为有问题,以便移除该成员 |
-r | 把 RAID 成员移出 RAID 设备 |
-a | 向 RAID 设备中添加一个成员 |
-E | 查看 RAID 成员详细信息 |
-c | 创建一个 RAID 设备时默认为 512kb |
-R | 开始部分组装 RAID |
-S | 停用 RAID 设备,释放所有资源 |
此时,就需要使用 mdadm 中的参数了。其中,-C 参数代表创建一个 RAID 阵列卡;-v 参数显示创建的过程,同时在后面追加一个设备名称 /dev/md0,这样 /dev/md0 就是创建后的 RAID 磁盘阵列的名称;-a yes 参数代表自动创建设备文件;-n 4 参数代表使用 4 块硬盘来部署这个 RAID 磁盘阵列;而 -l 10 参数则代表 RAID 10 方案;最后再加上 4 块硬盘设备的名称就搞定了。
[root@linuxprobe ~]# mdadm -Cv /dev/md0 -a yes -n 4 -l 10 /dev/sdb /dev/sdc /dev/sdd /dev/sde
mdadm: layout defaults to n2
mdadm: layout defaults to n2
mdadm: chunk size defaults to 512K
mdadm: size set to 20954624K
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
- 其次,把制作好的 RAID 磁盘阵列格式化为 ext4 格式。
[root@linuxprobe ~]# mkfs.ext4 /dev/md0
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=128 blocks, Stripe width=256 blocks
2621440 inodes, 10477312 blocks
523865 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2157969408
320 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
- 再次,创建挂载点然后把硬盘设备进行挂载操作。挂载成功后可看到可用空间为40GB。
mkdir /RAID
mount /dev/md0 /RAID
- 最后,查看
/dev/md0
磁盘阵列的详细信息,并把挂载信息写入到配置文件中,使其永久生效。
[root@linuxprobe ~]# mdadm -D /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Tue May 5 07:43:26 2017
Raid Level : raid10
Array Size : 41909248 (39.97 GiB 42.92 GB)
Used Dev Size : 20954624 (19.98 GiB 21.46 GB)
Raid Devices : 4
Total Devices : 4
Persistence : Superblock is persistent
Update Time : Tue May 5 07:46:59 2017
State : clean
Active Devices : 4
Working Devices : 4
Failed Devices : 0
Spare Devices : 0
Layout : near=2
Chunk Size : 512K
Name : localhost.localdomain:0 (local to host localhost.localdomain)
UUID : cc9a87d4:1e89e175:5383e1e8:a78ec62c
Events : 17
Number Major Minor RaidDevice State
0 8 16 0 active sync /dev/sdb
1 8 32 1 active sync /dev/sdc
2 8 48 2 active sync /dev/sdd
3 8 64 3 active sync /dev/sde
[root@linuxprobe ~]# echo "/dev/md0 /RAID ext4 defaults 0 0" >> /etc/fstab
损坏磁盘阵列及修复
在确认有一块物理硬盘设备出现损坏而不能继续正常使用后,应该使用 mdadm 命令将其移除,然后查看 RAID 磁盘阵列的状态,可以发现状态已经改变。
[root@linuxprobe ~]# mdadm /dev/md0 -f /dev/sdb
mdadm: set /dev/sdb faulty in /dev/md0
[root@linuxprobe ~]# mdadm -D /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Fri May 8 08:11:00 2017
Raid Level : raid10
Array Size : 41909248 (39.97 GiB 42.92 GB)
Used Dev Size : 20954624 (19.98 GiB 21.46 GB)
Raid Devices : 4
Total Devices : 4
Persistence : Superblock is persistent
Update Time : Fri May 8 08:27:18 2017
State : clean, degraded
Active Devices : 3
Working Devices : 3
Failed Devices : 1
Spare Devices : 0
Layout : near=2
Chunk Size : 512K
Name : linuxprobe.com:0 (local to host linuxprobe.com)
UUID : f2993bbd:99c1eb63:bd61d4d4:3f06c3b0
Events : 21
Number Major Minor RaidDevice State
0 0 0 0 removed
1 8 32 1 active sync /dev/sdc
2 8 48 2 active sync /dev/sdd
3 8 64 3 active sync /dev/sde
0 8 16 – faulty /dev/sdb
在RAID 10 级别的磁盘阵列中,当RAID 1 磁盘阵列中存在一个故障盘时并不影响RAID 10 磁盘阵列的使用。当购买了新的硬盘设备后再使用 mdadm
命令来予以替换即可,在此期间我们可以在 /RAID 目录中正常地创建或删除文件。由于我们是在虚拟机中模拟硬盘,所以先重启系统,然后再把新的硬盘添加到 RAID 磁盘阵列中。
[root@linuxprobe ~]# umount /RAID
[root@linuxprobe ~]# mdadm /dev/md0 -a /dev/sdb
[root@linuxprobe ~]# mdadm -D /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Mon Jan 30 00:08:56 2017
Raid Level : raid10
Array Size : 41909248 (39.97 GiB 42.92 GB)
Used Dev Size : 20954624 (19.98 GiB 21.46 GB)
Raid Devices : 4
Total Devices : 4
Persistence : Superblock is persistent
Update Time : Mon Jan 30 00:19:53 2017
State : clean
Active Devices : 4
Working Devices : 4
Failed Devices : 0
Spare Devices : 0
Layout : near=2
Chunk Size : 512K
Name : localhost.localdomain:0 (local to host localhost.localdomain)
UUID : d3491c05:cfc81ca0:32489f04:716a2cf0
Events : 56
Number Major Minor RaidDevice State
4 8 16 0 active sync /dev/sdb
1 8 32 1 active sync /dev/sdc
2 8 48 2 active sync /dev/sdd
3 8 64 3 active sync /dev/sde
[root@linuxprobe ~]# mount –a
mount –a
:挂载所有在/etc/fstab
中定义的文件系统
删除 RAID
- 查看 RAID 磁盘阵列信息,确认一下要关闭哪个
[root@linuxprobe ~]# cat /proc/mdstat
Personalities : [raid10]
md0 : active raid10 sdb[4] sdd[2] sde[3] sdc[1]
41908224 blocks super 1.2 512K chunks 2 near-copies [4/4] [UUUU]
- 卸载 md0 这个 RAID 的挂载点
[root@linuxprobe ~]# umount /RAID
- 停止 md0 这个阵列,并释放与该阵列相关的所有资源
[root@linuxprobe ~]# mdadm -S /dev/md0
mdadm: stopped /dev/md0
- 清除成员磁盘当中阵列的超级块信息
[root@linuxprobe ~]# mdadm --zero-superblock /dev/sdb /dev/sdc /dev/sdd /dev/sde
- 删除或注释
/etc/fstab
上的挂载信息
[root@linuxprobe ~]# vim /etc/fstab
- 删除或注释
/etc/mdadm.conf
对应的 RAID 信息:
[root@linuxprobe ~]# vim /etc/mdadm.conf
- 如果做完上面所有操作后,发现 /dev 下还有 md0 这个设备文件存在,直接
rm -f /dev/md0
即可
LVM(逻辑卷管理器)
前面学习的硬盘设备管理技术虽然能够有效地提高硬盘设备的读写速度以及数据的安全性,但是在硬盘分好区或者部署为 RAID 磁盘阵列之后,再想修改硬盘分区大小就不容易了。换句话说,当用户想要随着实际需求的变化调整硬盘分区的大小时,会受到硬盘灵活性的限制。LVM 的创建初衷是为了解决硬盘设备在创建分区后不易修改分区大小的缺陷。尽管对传统的硬盘分区进行强制扩容或缩容从理论上讲是可行的,但是却可能造成数据的丢失,而 LVM 技术是在硬盘分区和文件系统之间添加了一个逻辑层,它提供了一个抽象的卷组,可以把多块硬盘进行卷组合并,这样一来,用户不必关心物理硬盘设备的底层架构和布局,就可以实现对硬盘分区的动态调整。
卷组建立在物理卷之上,一个卷组可以包含多个物理卷,而且在卷组创建之后也可以继续向其中添加新的物理卷。逻辑卷是用卷组中空闲的资源建立的,并且逻辑卷在建立后可以动态地扩展或缩小空间。这就是LVM的核心理念。
部署逻辑卷
部署 LVM 时,需要逐个配置物理卷、卷组和逻辑卷。
功能 / 命令 | 物理卷管理 | 卷组管理 | 逻辑卷管理 |
---|---|---|---|
扫描 | pvscan |
vgscan |
lvscan |
建立 | pvcreate |
vgcreate |
lvcreate |
显示 | pvdisplay |
vgdisplay |
lvdisplay |
删除 | pvremove |
vgremove |
lvremove |
扩展 | vgextend |
lvextend |
|
缩小 | vgreduce |
lvreduce |
- 让新添加的两块硬盘设备支持 LVM 技术;
[root@linuxprobe ~]# pvcreate /dev/sdb /dev/sdc
Physical volume "/dev/sdb" successfully created
Physical volume "/dev/sdc" successfully created
- 把两块硬盘设备加入到 storage 卷组中,然后查看卷组的状态;
[root@linuxprobe ~]# vgcreate storage /dev/sdb /dev/sdc
Volume group "storage" successfully created
[root@linuxprobe ~]# vgdisplay
--- Volume group ---
VG Name storage
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 1
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 0
Open LV 0
Max PV 0
Cur PV 2
Act PV 2
VG Size 39.99 GiB
PE Size 4.00 MiB
Total PE 10238
Alloc PE / Size 0 / 0 Free PE / Size 10238 / 39.99 GiB
VG UUID KUeAMF-qMLh-XjQy-ArUo-LCQI-YF0o-pScxm1
………………省略部分输出信息………………
- 切割出一个约为 150 MB 的逻辑卷设备;
[root@linuxprobe ~]# lvcreate -n vo -l 37 storage
Logical volume "vo" created
[root@linuxprobe ~]# lvdisplay
--- Logical volume ---
LV Path /dev/storage/vo
LV Name vo
VG Name storage
LV UUID D09HYI-BHBl-iXGr-X2n4-HEzo-FAQH-HRcM2I
LV Write Access read/write
LV Creation host, time localhost.localdomain, 2017-02-01 01:22:54 -0500
LV Status available
# open 0
LV Size 148.00 MiB
Current LE 37
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:2
………………省略部分输出信息………………
- 把生成好的逻辑卷进行格式化,然后挂载使用;
Linux 系统会把 LVM 中的逻辑卷设备存放在 /dev 设备目录中,同时会以卷组的名称来建立一个目录。其中保存了逻辑卷的设备映射文件,即
/dev/卷组名称/逻辑卷名称
。
[root@linuxprobe ~]# mkfs.ext4 /dev/storage/vo
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
38000 inodes, 151552 blocks
7577 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=33816576
19 block groups
8192 blocks per group, 8192 fragments per group
2000 inodes per group
Superblock backups stored on blocks:
8193, 24577, 40961, 57345, 73729
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
[root@linuxprobe ~]# mkdir /linuxprobe
[root@linuxprobe ~]# mount /dev/storage/vo /linuxprobe
- 查看挂载状态,并写入到配置文件,使其永久生效
[root@linuxprobe ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 18G 3.0G 15G 17% /
devtmpfs 905M 0 905M 0% /dev
tmpfs 914M 140K 914M 1% /dev/shm
tmpfs 914M 8.8M 905M 1% /run
tmpfs 914M 0 914M 0% /sys/fs/cgroup
/dev/sr0 3.5G 3.5G 0 100% /media/cdrom
/dev/sda1 497M 119M 379M 24% /boot
/dev/mapper/storage-vo 145M 7.6M 138M 6% /linuxprobe
[root@linuxprobe ~]# echo "/dev/storage/vo /linuxprobe ext4 defaults 0 0" >> /
etc/fstab
扩容逻辑卷
在前面的实验中,卷组是由两块硬盘设备共同组成的。用户在使用存储设备时感知不到设备底层的架构和布局,更不用关心底层是由多少块硬盘组成的,只要卷组中有足够的资源,就可以一直为逻辑卷扩容。扩展前请一定要记得卸载设备和挂载点的关联。
[root@linuxprobe ~]# umount /linuxprobe
- 把上一个实验中的逻辑卷
vo
扩展至 290MB
[root@linuxprobe ~]# lvextend -L 290M /dev/storage/vo
Rounding size to boundary between physical extents: 292.00 MiB
Extending logical volume vo to 292.00 MiB
Logical volume vo successfully resized
- 检查硬盘完整性,并重置硬盘容量
[root@linuxprobe ~]# e2fsck -f /dev/storage/vo
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/storage/vo: 11/38000 files (0.0% non-contiguous), 10453/151552 blocks
[root@linuxprobe ~]# resize2fs /dev/storage/vo
resize2fs 1.42.9 (28-Dec-2013)
Resizing the filesystem on /dev/storage/vo to 299008 (1k) blocks.
The filesystem on /dev/storage/vo is now 299008 blocks long.
- 重新挂载硬盘设备并查看挂载状态
[root@linuxprobe ~]# mount -a
[root@linuxprobe ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 18G 3.0G 15G 17% /
devtmpfs 985M 0 985M 0% /dev
tmpfs 994M 80K 994M 1% /dev/shm
tmpfs 994M 8.8M 986M 1% /run
tmpfs 994M 0 994M 0% /sys/fs/cgroup
/dev/sr0 3.5G 3.5G 0 100% /media/cdrom
/dev/sda1 497M 119M 379M 24% /boot
/dev/mapper/storage-vo 279M 2.1M 259M 1% /linuxprobe
缩小逻辑卷
Linux系统规定,在对LVM逻辑卷进行缩容操作之前,要先检查文件系统的完整性(当然这也是为了保证我们的数据安全)。在执行缩容操作前记得先把文件系统卸载掉。
[root@linuxprobe ~]# umount /linuxprobe
- 检查文件系统的完整性
[root@linuxprobe ~]# e2fsck -f /dev/storage/vo
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/storage/vo: 11/74000 files (0.0% non-contiguous), 15507/299008 blocks
- 把逻辑卷 vo 的容量减小到 120MB
[root@linuxprobe ~]# resize2fs /dev/storage/vo 120M
resize2fs 1.42.9 (28-Dec-2013)
Resizing the filesystem on /dev/storage/vo to 122880 (1k) blocks.
The filesystem on /dev/storage/vo is now 122880 blocks long.
[root@linuxprobe ~]# lvreduce -L 120M /dev/storage/vo
WARNING: Reducing active logical volume to 120.00 MiB
THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce vo? [y/n]: y
Reducing logical volume vo to 120.00 MiB
Logical volume vo successfully resized
- 重新挂载文件系统并查看系统状态
[root@linuxprobe ~]# mount -a
[root@linuxprobe ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 18G 3.0G 15G 17% /
devtmpfs 985M 0 985M 0% /dev
tmpfs 994M 80K 994M 1% /dev/shm
tmpfs 994M 8.8M 986M 1% /run
tmpfs 994M 0 994M 0% /sys/fs/cgroup
/dev/sr0 3.5G 3.5G 0 100% /media/cdrom
/dev/sda1 497M 119M 379M 24% /boot
/dev/mapper/storage-vo 113M 1.6M 103M 2% /linuxprobe
逻辑卷快照
LVM 还具备有“快照卷”功能,该功能类似于虚拟机软件的还原时间点功能。
- 查看卷组信息
[ root@linuxprobe ~ ]# vgdisplay
--- Volume group ---
VG Name storage
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 4
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 2
Act PV 2
VG Size 39.99 GiB
PE Size 4.00 MiB
Total PE 10238
Alloc PE / Size 30 / 120.00 MiB Free PE / Size 10208 / 39.88 GiB
VG UUID CTaHAK-0TQv-Abdb-R83O-RU6V-YYkx-8o2R0e
………………省略部分输出信息………………
通过卷组的输出信息可以清晰看到,卷组中已经使用了120MB的容量,空闲容量还有39.88GB。
- 接下来用重定向往逻辑卷设备所挂载的目录中写入一个文件
[root@linuxprobe ~]# echo "Welcome to Linuxprobe.com" > /linuxprobe/readme.txt
[root@linuxprobe ~]# ls -l /linuxprobe
total 14
drwx------. 2 root root 12288 Feb 1 07:18 lost+found
-rw-r--r--. 1 root root 26 Feb 1 07:38 readme.txt
- 使用
-s
参数生成一个快照卷,使用-L
参数指定切割的大小。另外,还需要在命令后面写上是针对哪个逻辑卷执行的快照操作。
[root@linuxprobe ~]# lvcreate -L 120M -s -n SNAP /dev/storage/vo
Logical volume "SNAP" created
[root@linuxprobe ~]# lvdisplay
--- Logical volume ---
LV Path /dev/storage/SNAP
LV Name SNAP
VG Name storage
LV UUID BC7WKg-fHoK-Pc7J-yhSd-vD7d-lUnl-TihKlt
LV Write Access read/write
LV Creation host, time localhost.localdomain, 2017-02-01 07:42:31 -0500
LV snapshot status active destination for vo
LV Status available
# open 0
LV Size 120.00 MiB
Current LE 30
COW-table size 120.00 MiB
COW-table LE 30
Allocated to snapshot 0.01%
Snapshot chunk size 4.00 KiB
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:3
………………省略部分输出信息………………
- 在逻辑卷所挂载的目录中创建一个 100M 的垃圾文件,然后再查看快照卷的状态,可以发现存储空间占用量上升了
[root@linuxprobe ~]# dd if=/dev/zero of=/linuxprobe/files count=1 bs=100M
1+0 records in
1+0 records out
104857600 bytes (105 MB) copied, 3.35432 s, 31.3 MB/s
[root@linuxprobe ~]# lvdisplay
--- Logical volume ---
LV Path /dev/storage/SNAP
LV Name SNAP
VG Name storage
LV UUID BC7WKg-fHoK-Pc7J-yhSd-vD7d-lUnl-TihKlt
LV Write Access read/write
LV Creation host, time localhost.localdomain, 2017-02-01 07:42:31 -0500
LV snapshot status active destination for vo
LV Status available
# open 0
LV Size 120.00 MiB
Current LE 30
COW-table size 120.00 MiB
COW-table LE 30
Allocated to snapshot 83.71%
Snapshot chunk size 4.00 KiB
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:3
- 为了校验 SNAP 快照卷的效果,需要对逻辑卷进行快照还原操作。在此之前记得先卸载掉逻辑卷设备与目录的挂载。
[root@linuxprobe ~]# umount /linuxprobe
[root@linuxprobe ~]# lvconvert --merge /dev/storage/SNAP
Merging of volume SNAP started.
vo: Merged: 21.4%
vo: Merged: 100.0%
Merge of snapshot into logical volume vo has finished.
Logical volume "SNAP" successfully removed
- 快照卷会被自动删除掉,并且刚刚再逻辑卷设备被执行快照操作后再创建出来的 100M 的垃圾文件也被清除了。
[root@linuxprobe ~]# mount -a
[root@linuxprobe ~]# ls /linuxprobe/
lost+found readme.txt
删除逻辑卷
当生产环境中想要重新部署 LVM 或者不再需要使用 LVM 时,则需要执行 LVM 的删除操作。为此,需要提前备份好重要的数据信息,然后依次删除逻辑卷、卷组、物理卷设备,这个顺序不可颠倒。
- 取消逻辑卷与目录的挂载关联,删除配置文件中永久生效的设备参数
[root@linuxprobe ~]# umount /linuxprobe
[root@linuxprobe ~]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Fri Feb 19 22:08:59 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/rhel-root / xfs defaults 1 1
UUID=50591e35-d47a-4aeb-a0ca-1b4e8336d9b1 /boot xfs defaults 1 2
/dev/mapper /rhel-swap swap swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
- 删除逻辑卷设备,需要输入 y 来确认操作
[root@linuxprobe ~]# lvremove /dev/storage/vo
Do you really want to remove active logical volume vo? [y/n]: y
Logical volume "vo" successfully removed
- 删除卷组,此处只写卷组名称即可,不需要设备的绝对路径
[root@linuxprobe ~]# vgremove storage
Volume group "storage" successfully removed
- 删除物理卷设备
[root@linuxprobe ~]# pvremove /dev/sdb /dev/sdc
Labels on physical volume "/dev/sdb" successfully wiped
Labels on physical volume "/dev/sdc" successfully wiped
iptables
与 firewalld
防火墙
防火墙作为公网与内网之间的保护屏障,在保障数据的安全性方面起着至关重要的作用。
防火墙管理工具
在公网与企业内网之间充当保护屏障的防火墙,虽然有软件或硬件之分,但主要功能都是依据策略对穿越防火墙自身的流量进行过滤。防火墙策略可以基于流量的源目地址、端口号、协议、应用等信息来定制,然后防火墙使用预先定制的策略规则监控出入的流量,若流量与某一条策略规则相匹配,则执行相应的处理,反之则丢弃,这样一来,就可以保证仅有合法的流量在企业内网和外部公网之间的流动了。
在 RHEL 7 系统中,
firewalld
防火墙取代了iptables
防火墙。这两者都只是用来定义防火墙策略的防火墙管理工具而已。
iptables
服务会把配置好的防火墙策略交由内核层面的netfilter
网络过滤器来处理firewalld
服务则是把配置好的防火墙策略交由内核层面的nftables
包过滤框架来处理
iptables
策略和规则链
防火墙会从上至下的顺序来读取配置的策略规则,在找到匹配项后就立即结束匹配工作并去执行匹配项中定义的行为(放行或阻止)。
iptables
服务把用于处理或过滤流量的策略条目称之为规则,多条规则可以组成一个规则链,而规则链则依据数据包处理位置的不同进行分类,具体如下:
- 在进行路由选择前处理数据包(PREROUTING):在对数据包作路由选择之前,应用此链中的规则。
- 处理流入的数据包(INPUT):当接收到防火墙本机地址的数据包(入站)时,应用此链中的规则。
- 处理流出的数据包(OUTPUT):当防火墙本机向外发送数据包(出站)时,应用此链中的规则。
- 处理转发的数据包(FORWARD):当接收到需要通过防火墙发送给其他地址的数据包(转发)时,应用此链中的规则。
- 在进行路由选择后处理数据包(POSTROUTING):在对数据包作路由选择之后,应用此链中的规则。
一般来说,从内网向外网发送的流量一般都是可控且良性的,因此我们使用最多的就是 INPUT 规则链,该规则链可以增大黑客人员从外网入侵内网的难度。
但是,仅有策略规则还不能保证社区的安全,保安还应该知道采用什么样的动作来处理这些匹配的流量,比如“允许”、“拒绝”、“登记”、“不理它”。这些动作对应到 iptables
服务的术语中分别是 ACCEPT(允许流量通过)、REJECT(拒绝流量通过)、LOG(记录日志信息)、DROP(拒绝流量通过)。“允许流量通过”和“记录日志信息”都比较好理解,这里需要着重讲解的是 REJECT 和 DROP 的不同点。就 DROP 来说,它是直接将流量丢弃而且不响应;REJECT 则会在拒绝流量后再回复一条“您的信息已经收到,但是被扔掉了”信息,从而让流量发送方清晰地看到数据被拒绝的响应信息。
当把 Linux 系统中的防火墙策略设置为 REJECT 拒绝动作后,流量发送方会看到端口不可达的相应:
[root@linuxprobe ~]# ping -c 4 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
From 192.168.10.10 icmp_seq=1 Destination Port Unreachable
From 192.168.10.10 icmp_seq=2 Destination Port Unreachable
From 192.168.10.10 icmp_seq=3 Destination Port Unreachable
From 192.168.10.10 icmp_seq=4 Destination Port Unreachable
--- 192.168.10.10 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3002ms
而把 Linux 系统中的防火墙策略修改成 DROP 拒绝动作后,流量发送方会看到响应超时的提醒。但是流量发送方无法判断流量是被拒绝,还是接收方主机当前不在线:
[root@linuxprobe ~]# ping -c 4 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
--- 192.168.10.10 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3000ms
iptables
中基本的命令参数
iptables
命令可以根据流量的源地址、目的地址、传输协议、服务类型等信息进行匹配,一旦匹配成功,iptables
就会根据策略规则所预设的动作来处理这些流量。
再次提醒,防火墙策略规则的匹配顺序是从上至下的,因此要把较为严格、优先级较高的策略规则放到前面,以免发生错误。
参数 | 说明 | 示例 |
---|---|---|
-P |
设置默认策略 | iptables -P |
-F |
清空规则链 | iptables -F |
-L |
查看规则链 | iptables -L |
-A |
追加规则 | iptables -A INPUT |
-D |
删除规则 | iptables -D INPUT 1 |
-R |
修改规则 | iptable -R INPUT 1 -s 192.168.120.0 -j DROP |
-I |
在头部插入规则 | iptables -I INPUT 1 --dport 80 -j ACCEPT |
-L |
查看规则 | iptables -L INPUT |
-N |
新的规则 | iptables -N allowed |
-V |
查看 iptables 版本 | iptables -V |
-p |
协议(tcp/udp/icmp ) |
iptables -A INPUT -p tcp |
-s |
匹配原地址,加 "!" 表示除这个 IP 外 | iptables -A INPUT -s 192.168.1.1 |
-d |
匹配目的地址 | iptables -A INPUT -d 192.168.12.1 |
--sport |
匹配源端口流入的数据 | iptables -A INPUT -p tcp --sport 22 |
--dport |
匹配目的端口流出的数据 | iptables -A INPUT -p tcp --dport 22 |
-i |
匹配入口网卡流入的数据 | iptables -A INPUT -i eth0 |
-o |
匹配出口网卡流出的数据 | iptables -A FORWARD -o eth0 |
-j |
要进行的处理动作:DROP (丢弃),REJECT (拒绝),ACCEPT (接受),SANT (基于原地址的转换) | iptable -A INPUT 1 -s 192.168.120.0 -j DROP |
--to-source |
指定 SANT 转换后的地址 | iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SANT --to-source 172.16.100.1 |
-t |
表名 (raw、mangle、nat、filter ) |
iptables -t nat |
-m |
使用扩展模块来进行数据包的匹配 (multiport/tcp/state/addrtype ) |
iptables -m multiport |
在 iptables
命令后添加 -L
参数查看已有的防火墙规则链:
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
INPUT_direct all -- anywhere anywhere
INPUT_ZONES_SOURCE all -- anywhere anywhere
INPUT_ZONES all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
………………省略部分输出信息………………
在 iptables
命令后添加 -F
参数清空已有的防火墙规则链:
[root@linuxprobe ~] # iptables -F
[root@linuxprobe ~] # iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
………………省略部分输出信息………………
把 INPUT 规则链的默认策略设置为拒绝:
[root@linuxprobe ~]# iptables -P INPUT DROP
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
…………省略部分输出信息………………
前文提到,防火墙策略规则的设置有两种:通和堵。当把 INPUT 链设置为默认拒绝后,就要在防火墙策略中写入允许策略了,否则所有到来的流量都会被拒绝掉。另外,需要注意的是,规则链的默认拒绝动作只能是DROP,而不能是 REJECT。
向 INPUT 链中添加允许 ICMP 流量进入的策略规则:
在日常运维工作中,经常会使用 ping 命令来检查对方主机是否在线,而向防火墙的 INPUT 规则链中添加一条允许 ICMP 流量进入的策略规则就默认允许了 ping 命令检测行为。
ICMP 是 TCP/IP 协议簇的一个子协议,不承载数据,不是用来传输用户数据,是用来传递控制消息的,即:网络通不通、主机是否可达。
ping
命令就是基于 ICMP 的。
[root@linuxprobe ~]# iptables -I INPUT -p icmp -j ACCEPT
[root@linuxprobe ~]# ping -c 4 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=0.156 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=64 time=0.117 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=64 time=0.099 ms
64 bytes from 192.168.10.10: icmp_seq=4 ttl=64 time=0.090 ms
--- 192.168.10.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.090/0.115/0.156/0.027 ms
删除 INPUT 规则链中刚刚加入的那条策略(允许 ICMP 流量),并把默认策略设置为允许:
[root@linuxprobe ~]# iptables -D INPUT 1
[root@linuxprobe ~]# iptables -P INPUT ACCEPT
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
………………省略部分输出信息………………
将 INPUT 规则链设置为只允许指定网段的主机访问本机的 22 端口,拒绝来自其他所有主机的流量:
[root@linuxprobe ~]# iptables -I INPUT -s 192.168.10.0/24 -p tcp --dport 22 -j
ACCEPT
[root@linuxprobe ~]# iptables -A INPUT -p tcp --dport 22 -j REJECT
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 192.168.10.0/24 anywhere tcp dpt:ssh
REJECT tcp -- anywhere anywhere tcp dpt:ssh reject-with icmp-port-unreachable
………………省略部分输出信息………………
再次重申,防火墙策略规则是按照从上到下的顺序匹配的,因此一定要把允许动作放到拒绝动作前面,否则所有的流量就将被拒绝掉,从而导致任何主机都无法访问我们的服务。
在设置完上述 INPUT 规则连之后,我们使用 IP 地址在192.168.10.0/24 网段内的主机访问服务器(即前面提到的设置了 INPUT 规则链的主机)的 22 端口,效果如下:
[root@Client A ~]# ssh 192.168.10.10
The authenticity of host '192.168.10.10 (192.168.10.10)' can't be established.
ECDSA key fingerprint is 70:3b:5d:37:96:7b:2e:a5:28:0d:7e:dc:47:6a:fe:5c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.10' (ECDSA) to the list of known hosts.
root@192.168.10.10's password: 此处输入对方主机的root管理员密码
Last login: Sun Feb 12 01:50:25 2017
[root@Client A ~]#
然后,我们再使用 IP 地址在 192.168.20.0/24 网段外的主机访问服务器的22 端口,效果如下,就不会提示连接请求被拒绝了(Connection failed):
[root@Client B ~]# ssh 192.168.10.10
Connecting to 192.168.10.10:22...
Could not connect to '192.168.10.10' (port 22): Connection failed.
向 INPUT 规则链中添加拒绝所有人访问本机 12345 端口的策略规则:
[root@linuxprobe ~]# iptables -I INPUT -p tcp --dport 12345 -j REJECT
[root@linuxprobe ~]# iptables -I INPUT -p udp --dport 12345 -j REJECT
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT udp -- anywhere anywhere udp dpt:italk reject-with icmp-port-unreachable
REJECT tcp -- anywhere anywhere tcp dpt:italk reject-with icmp-port-unreachable
ACCEPT tcp -- 192.168.10.0/24 anywhere tcp dpt:ssh
REJECT tcp -- anywhere anywhere tcp dpt:ssh reject-with icmp-port-unreachable
………………省略部分输出信息………………
向 INPUT 规则链中添加拒绝 192.168.10.5 主机访问本机 80 端口(Web服务)的策略规则:
[root@linuxprobe ~] # iptables -I INPUT -p tcp -s 192.168.10.5 --dport 80 -j REJECT
[root@linuxprobe ~] # iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT tcp -- 192.168.10.5 anywhere tcp dpt:http reject-with icmp-port-unreachable
REJECT udp -- anywhere anywhere udp dpt:italk reject-with icmp-port-unreachable
REJECT tcp -- anywhere anywhere tcp dpt:italk reject-with icmp-port-unreachable
ACCEPT tcp -- 192.168.10.0/24 anywhere tcp dpt:ssh
REJECT tcp -- anywhere anywhere tcp dpt:ssh reject-with icmp-port-unreachable
………………省略部分输出信息………………
向 INPUT 规则链中添加拒绝所有主机访问本机 1000~1024 端口的策略规则:
[root@linuxprobe ~]# iptables -A INPUT -p tcp --dport 1000:1024 -j REJECT
[root@linuxprobe ~]# iptables -A INPUT -p udp --dport 1000:1024 -j REJECT
[root@linuxprobe ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT tcp -- 192.168.10.5 anywhere tcp dpt:http reject-with icmp-port-unreachable
REJECT udp -- anywhere anywhere udp dpt:italk reject-with icmp-port-unreachable
REJECT tcp -- anywhere anywhere tcp dpt:italk reject-with icmp-port-unreachable
ACCEPT tcp -- 192.168.10.0/24 anywhere tcp dpt:ssh
REJECT tcp -- anywhere anywhere tcp dpt:ssh reject-with icmp-port-unreachable
REJECT tcp -- anywhere anywhere tcp dpts:cadlock2:1024 reject-with icmp-port-
unreachable
REJECT udp -- anywhere anywhere udp dpts:cadlock2:1024 reject-with icmp-port-
unreachable
………………省略部分输出信息………………
请特别注意,使用 iptables
命令配置的防火墙规则默认会在系统下一次重启时失效,如果想让配置的防火墙策略永久生效,还要执行保存命令:
[root@linuxprobe ~]# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
firewalld
相较于传统的防火墙管理配置工具,firewalld
支持动态更新技术并加入了区域(zone)的概念。简单来说,区域就是 firewalld
预先准备了几套防火墙策略集合(策略模板),用户可以根据生产场景的不同而选择合适的策略集合,从而实现防火墙策略之间的快速切换。
当前,我们希望为这台笔记本电脑指定如下防火墙策略规则:在家中允许访问所有服务;在办公室内仅允许访问文件共享服务;在咖啡厅仅允许上网浏览。在以往,我们需要频繁地手动设置防火墙策略规则,而现在只需要预设好区域集合,然后只需轻点鼠标就可以自动切换了,从而极大地提升了防火墙策略的应用效率。
区域 | 默认规则策略 |
---|---|
trusted | 允许所有的数据包 |
home | 拒绝流入的流量,除非与流出的流量相关;而如果流量与 ssh、mdns、ipp-client、amba-client 与 dhcpv6-client 服务相关,则允许流量 |
internal | 等同于 home 区域 |
work | 拒绝流入的流量,除非与流出的流量相关;而如果流量与 ssh、ipp-client 与 dhcpv6-client 服务相关,则允许流量 |
public | 拒绝流入的流量,除非与流出的流量相关;而如果流量与 ssh、dhcpv6-client 服务相关,则允许流量 |
external | 拒绝流入的流量,除非与流出的流量相关;而如果流量与 ssh 服务相关,则允许流量 |
dmz | 拒绝流入的流量,除非与流出的流量相关;而如果流量与 ssh 服务相关,则允许流量 |
block | 拒绝流入的流量,除非与流出的流量相关 |
drop | 拒绝流入的流量,除非与流出的流量相关 |
终端管理工具
参数 | 作用 |
---|---|
--get-default-zone | 查询默认的区域名称。 |
--set-default-zone=<区域名称> | 设置默认的区域,永久生效。 |
--get-zones | 显示可用的区域。 |
--get-services | 显示预先定义的服务。 |
--get-active-zones | 显示当前正在使用的区域与网卡名称。 |
--add-source= | 将来源于此 IP 或子网的流量导向指定的区域。 |
--remove-source= | 不再将此 IP 或子网的流量导向某个指定区域。 |
--add-interface=<网卡名称> | 将来自于该网卡的所有流量都导向某个指定区域。 |
--change-interface=<网卡名称> | 将某个网卡与区域做关联。 |
--list-all | 显示当前区域的网卡配置参数,资源,端口以及服务等信息。 |
--list-all-zones | 显示所有区域的网卡配置参数,资源,端口以及服务等信息。 |
--add-service=<服务名> | 设置默认区域允许该服务的流量。 |
--add-port=<端口号 / 协议> | 允许默认区域允许该端口的流量。 |
--remove-service=<服务名> | 设置默认区域不再允许该服务的流量。 |
--remove-port=<端口号 / 协议> | 允许默认区域不再允许该端口的流量。 |
--reload | 让 “永久生效” 的配置规则立即生效,覆盖当前的。 |
与 Linux 系统中其他的防火墙策略配置工具一样,使用 firewalld
配置的防火墙策略默认为运行时(Runtime)模式,又称为当前生效模式,而且随着系统的重启会失效。如果想让配置策略一直存在,就需要使用永久(Permanent)模式了,方法就是在用 firewall-cmd
命令正常设置防火墙策略时添加 --permanent
参数,这样配置的防火墙策略就可以永久生效了。但是,永久生效模式有一个“不近人情”的特点,就是使用它设置的策略只有在系统重启之后才能自动生效。如果想让配置的策略立即生效,需要手动执行 firewall-cmd --reload
命令。
查看 firewalld
服务当前所使用的区域:
[root@linuxprobe ~]# firewall-cmd --get-default-zone
public
查询 eno16777728 网卡在 firewalld
服务中的区域:
[root@linuxprobe ~]# firewall-cmd --get-zone-of-interface=eno16777728
public
把 firewalld
服务中 eno16777728 网卡的默认区域修改为 external,并在系统重启后生效。分别查看当前与永久模式下的区域名称:
[root@linuxprobe ~]# firewall-cmd --permanent --zone=external --change-interface=
eno16777728
success
[root@linuxprobe ~]# firewall-cmd --get-zone-of-interface=eno16777728
public
[root@linuxprobe ~]# firewall-cmd --permanent --get-zone-of-interface=eno16777728
external
把 firewalld
服务的当前默认区域设置为 public:
[root@linuxprobe ~]# firewall-cmd --set-default-zone=public
success
[root@linuxprobe ~]# firewall-cmd --get-default-zone
public
启动/关闭 firewalld
防火墙服务的应急状况模式,阻断一切网络连接(当远程控制服务器时请慎用):
[root@linuxprobe ~]# firewall-cmd --panic-on
success
[root@linuxprobe ~]# firewall-cmd --panic-off
success
查询 public 区域是否允许请求 SSH 和 HTTPS 协议的流量:
[root@linuxprobe ~]# firewall-cmd --zone=public --query-service=ssh
yes
[root@linuxprobe ~]# firewall-cmd --zone=public --query-service=https
no
把 firewalld
服务中请求 HTTPS 协议的流量设置为永久允许,并立即生效:
[root@linuxprobe ~]# firewall-cmd --zone=public --add-service=https
success
[root@linuxprobe ~]# firewall-cmd --permanent --zone=public --add-service=https
success
[root@linuxprobe ~]# firewall-cmd --reload
success
把 firewalld
服务中请求 HTTP 协议的流量设置为永久拒绝,并立即生效:
[root@linuxprobe ~]# firewall-cmd --permanent --zone=public --remove-service=http
success
[root@linuxprobe ~]# firewall-cmd --reload
success
把在 firewalld
服务中访问 8080 和 8081 端口的流量策略设置为允许,但仅限当前生效:
[root@linuxprobe ~]# firewall-cmd --zone=public --add-port=8080-8081/tcp
success
[root@linuxprobe ~]# firewall-cmd --zone=public --list-ports
8080-8081/tcp
把原本访问本机 888 端口的流量转发到 22 端口,要求当前和长期均有效:
[root@linuxprobe ~]# firewall-cmd --permanent --zone=public --add-forward-port=
port=888:proto=tcp
:toport=22
:toaddr=192.168.10.10
success
[root@linuxprobe ~]# firewall-cmd --reload
success
在客户端使用 ssh
命令尝试访问 192.168.10.10 主机的 888 端口:
[root@client A ~]# ssh -p 888 192.168.10.10
The authenticity of host '[192.168.10.10]:888 ([192.168.10.10]:888)' can't
be established.
ECDSA key fingerprint is b8:25:88:89:5c:05:b6:dd:ef:76:63:ff:1a:54:02:1a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.10.10]:888' (ECDSA) to the list of known hosts.
root@192.168.10.10's password:此处输入远程root管理员的密码
Last login: Sun Jul 19 21:43:48 2017 from 192.168.10.10
firewalld
中的富规则表示更细致、更详细的防火墙策略配置,它可以针对系统服务、端口号、源地址和目标地址等诸多信息进行更有正对性的策略配置。它的优先级在所有的防火墙策略中也是最高的。比如,我们可以在 firewalld
服务中配置一条富规则,使其拒绝 192.168.10.0/24 网段的所有用户访问本机的 ssh
服务(22 端口):
[root@linuxprobe ~]# firewall-cmd --permanent --zone=public --add-rich-rule="
rule family="ipv4" source address="192.168.10.0/24" service name="ssh" reject"
success
[root@linuxprobe ~]# firewall-cmd --reload
success
在客户端使用 ssh
命令尝试访问 192.168.10.10 主机的 ssh
服务(22 端口):
[root@client A ~]# ssh 192.168.10.10
Connecting to 192.168.10.10:22...
Could not connect to '192.168.10.10' (port 22): Connection failed.
图形管理工具
TODO
服务的访问控制列表
TCP Wrappers 是RHEL 7系统中默认启用的一款流量监控程序,它能够根据来访主机的地址与本机的目标服务程序作出允许或拒绝的操作。换句话说,Linux 系统中其实有两个层面的防火墙,第一种是前面讲到的基于TCP/IP 协议的流量过滤工具,而 TCP Wrappers 服务则是能允许或禁止Linux 系统提供服务的防火墙,从而在更高层面保护了 Linux 系统的安全运行。
TCP Wrappers 服务的防火墙策略由两个控制列表文件所控制,用户可以编辑允许控制列表文件来放行对服务的请求流量,也可以编辑拒绝控制列表文件来阻止对服务的请求流量。控制列表文件修改后会立即生效,系统将会先检查允许控制列表文件(/etc/hosts.allow
),如果匹配到相应的允许策略则放行流量;如果没有匹配,则去进一步匹配拒绝控制列表文件(/etc/hosts.deny
),若找到匹配项则拒绝该流量。如果这两个文件全都没有匹配到,则默认放行流量。
编写拒绝策略规则时,填写的是服务名称,而非协议名称;建议先编写拒绝策略规则,再编写允许策略规则,以便直观地看到相应的效果。下面编写拒绝策略规则文件,禁止访问本机 sshd
服务的所有流量(无须 /etc/hosts.deny 文件中修改原有的注释信息):
[root@linuxprobe ~]# vim /etc/hosts.deny
#
# hosts.deny This file contains access rules which are used to
# deny connections to network services that either use
# the tcp_wrappers library or that have been
# started through a tcp_wrappers-enabled xinetd.
#
# The rules in this file can also be set up in
# /etc/hosts.allow with a 'deny' option instead.
#
# See 'man 5 hosts_options' and 'man 5 hosts_access'
# for information on rule syntax.
# See 'man tcpd' for information on tcp_wrappers
sshd:*
[root@linuxprobe ~]# ssh 192.168.10.10
ssh_exchange_identification: read: Connection reset by peer
接下来,在允许策略规则文件中添加一条规则,使其放行源自192.168.10.0/24
网段,访问本机 sshd
服务的所有流量。可以看到,服务器立刻就放行了访问 sshd
服务的流量,效果非常直观:
[root@linuxprobe ~]# vim /etc/hosts.allow
#
# hosts.allow This file contains access rules which are used to
# allow or deny connections to network services that
# either use the tcp_wrappers library or that have been
# started through a tcp_wrappers-enabled xinetd.
#
# See 'man 5 hosts_options' and 'man 5 hosts_access'
# for information on rule syntax.
# See 'man tcpd' for information on tcp_wrappers
sshd:192.168.10.
[root@linuxprobe ~]# ssh 192.168.10.10
The authenticity of host '192.168.10.10 (192.168.10.10)' can't be established.
ECDSA key fingerprint is 70:3b:5d:37:96:7b:2e:a5:28:0d:7e:dc:47:6a:fe:5c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.10' (ECDSA) to the list of known hosts.
root@192.168.10.10's password:
Last login: Wed May 4 07:56:29 2017
[root@linuxprobe ~]#
使用 ssh 服务管理远程主机
配置网络服务
配置网络参数
[root@linuxprobe ~]# nmtui
Edit a connect
Edit
IPv4 -> Manual
在服务器主机的网络配置信息中填写 IP 地址 192.168.10.10/24
[root@linuxprobe ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens32
TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=ens32
UUID=ec77579b-2ced-481f-9c09-f562b321e268
ONBOOT=yes
IPADDR0=192.168.10.10
HWADDR=00:0c:29:9b:fe:bb
PREFIX0=24
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
注意
HWADDR
指主机的 MAC 地址,使用ifconfig
查看
手动重启相应的服务,之后就可以看到网络畅通了:
[root@linuxprobe ~]# systemctl restart network
[root@linuxprobe ~]# ping -c 4 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=64 time=0.099 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=64 time=0.095 ms
64 bytes from 192.168.10.10: icmp_seq=4 ttl=64 time=0.095 ms
--- 192.168.10.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.056/0.086/0.099/0.018 ms
创建网络会话
RHEL 和 CentOS 系统默认使用 NetworkManager
来提供网络服务,这是一种动态管理网络配置的守护进程,能够让网络设备保持连接状态。可以使用 nmcli
命令来管理 Network Manager
服务。它可以轻松查看网络信息或网络状态:
root@linuxprobe:~ # nmcli connection show
NAME UUID TYPE DEVICE
ens32 ec77579b-2ced-481f-9c09-f562b321e268 ethernet ens32
virbr0 760a7cde-8fe7-4659-b2b9-7d1a0334dad3 bridge virbr0
root@linuxprobe:~ # nmcli con show ens32
connection.id: ens32
connection.uuid: ec77579b-2ced-481f-9c09-f562b321e268
connection.stable-id: --
connection.type: 802-3-ethernet
connection.interface-name: --
connection.autoconnect: yes
connection.autoconnect-priority: 0
connection.autoconnect-retries: -1 (default)
connection.multi-connect: 0 (default)
connection.auth-retries: -1
connection.timestamp: 1668351390
connection.read-only: no
………………省略部分输出信息………………
另外,RHEL7 系统支持网络会话功能,允许用户在多个配置文件中快速切换,如果我们在公司网络中使用笔记本电脑时需要手动指定网络的 IP 地址,而回到家中则是使用 DHCP 自动分配 IP 地址,这就需要频繁修改 IP 地址,但是使用了网络会话功能后一切就简单多了——只需在不同的使用环境中激活相应的网络会话,就可以实现网络配置信息的自动切换了。
可以使用 nmcli
命令并按照 “connection add con-name type ifname” 的格式来创建网络会话。假设将公司网络中的网络会话称之为 company,将家庭网络中的网络会话称之为 house,现在依次创建各自的网络会话。
使用 con-name
参数指定公司所使用的网络会话名称 company,然后依次用 ifname
参数指定本机的网卡名称,用 autoconnect no
参数设置该网络会话默认不被自动激活,以及用 ip4 及 gw4 参数手动指定网络的 IP地址:
[root@linuxprobe ~]# nmcli connection add con-name company ifname ens32
autoconnect no type ethernet ip4 192.168.10.10/24 gw4 192.168.10.1
Connection 'company' (86c71220-0057-419e-b615-38f4014cfdee) successfully added.
使用 con-name
参数指定家庭所使用的网络会话名称 house
。因为我们想从外部 DHCP 服务器自动获得 IP 地址,因此这里不需要进行手动指定。
[root@linuxprobe ~]# nmcli connection add con-name house type ethernet ifname ens32
Connection 'house' (44acf0a7-07e2-40b4-94ba-69ea973090fb) successfully added.
在成功创建网络会话后,可以使用 nmcli
命令查看创建的所有网络会话:
[root@linuxprobe ~]# nmcli connection show
NAME UUID TYPE DEVICE
house 44acf0a7-07e2-40b4-94ba-69ea973090fb 802-3-ethernet --
company 86c71220-0057-419e-b615-38f4014cfdee 802-3-ethernet --
eno16777736 ec77579b-2ced-481f-9c09-f562b321e268 802-3-ethernet eno16777736
使用 nmcli
命令配置过的网络会话是永久生效的,这样当我们下班回家后,顺手启用 house
网络会话,网卡就能自动通过 DHCP
获取到 IP
地址了。
[root@linuxprobe ~]# nmcli connection up house
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/
ActiveConnection/2)
[root@linuxprobe ~]# ifconfig
eno1677773628: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.100.128
netmask 255.255.255.0 broadcast 192.168.100.255
inet6 fe80::20c:29ff:fec4:a409 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:c4:a4:09 txqueuelen 1000 (Ethernet)
RX packets 42 bytes 4198 (4.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 75 bytes 10441 (10.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 0 (Local Loopback)
RX packets 518 bytes 44080 (43.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 518 bytes 44080 (43.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果大家使用的是虚拟机,请把虚拟机系统的网卡(网络适配器)切换成桥接模式,如图9-9所示。然后重启虚拟机系统即可。
绑定两块网卡
- 在虚拟机系统中再添加一块网卡设备,请确保两块网卡都处在同一个网络连接中;
- TODO
远程控制服务
配置 sshd 服务
SSH (Secure Shell) 是一种能够以安全的方式提供远程登陆的协议,也是目前远程管理 Linux 系统的首选方式。
想要使用 SSH 协议来远程管理 Linux 系统,则需要部署配置 sshd 服务程序,其可以提供两种安全验证的方法“
- 基于口令的验证——用账户和密码来验证登录
- 基于密钥的验证——需要在本地生成密钥对,然后把密钥对中的公钥上传至服务器,并与服务器中的公钥进行比较;该方式更加安全
sshd
服务的配置信息保存在 /etc/ssh/sshd_config
文件中。运维人员一般会把保存着最主要配置信息的文件称为主配置文件,而配置文件中有许多以井号开头的注释行,要想让这些配置参数生效,需要在修改参数后再去掉前面的井号。sshd
服务配置文件中包含的重要参数如表 9-1 所示。
参数 | 作用 |
---|---|
Port 22 | 默认的 sshd 服务端口 |
ListenAddress 0.0.0.0 | 设定 sshd 服务器监听的 IP 地址 |
Protocol 2 | SSH 协议的版本号 |
HostKey /tc/ssh/ssh_host_key | SSH 协议版本为 1 时,DES 私钥存放的位置 |
HostKey /etc/ssh/ssh_host_rsa_key | SSH 协议版本为 2 时,RSA 私钥存放的位置 |
HostKey /etc/ssh/ssh_host_dsa_key | SSH 协议版本为 2 时,DSA 私钥存放的位置 |
PermitRootLogin yes | 设定是否允许 root 管理员直接登录 |
StrictModes yes | 当远程用户的私钥改变时直接拒绝连接 |
MaxAuthTries 6 | 最大密码尝试次数 |
MaxSessions 10 | 最大终端数 |
PasswordAuthentication yes | 是否允许密码验证 |
PermitEmptyPasswords no | 是否允许空密码登录(很不安全) |
在 RHEL 7 系统中,已经默认安装并启用了 sshd
服务程序。接下来使用 ssh
命令进行远程连接,其格式为“ssh [参数] 主机IP地址
”。要退出登录则执行 exit
命令。
[root@linuxprobe ~]# ssh 192.168.10.20
The authenticity of host '192.168.10.20 (192.168.10.20)' can't be established.
ECDSA key fingerprint is 4f:a7:91:9e:8d:6f:b9:48:02:32:61:95:48:ed:1e:3f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.20' (ECDSA) to the list of known hosts.
root@192.168.10.20's password: 此处输入远程主机 root 管理员的密码
Last login: Wed Apr 15 15:54:21 2017 from 192.168.10.10
[root@linuxprobe ~]#
[root@linuxprobe ~]# exit
logout
Connection to 192.168.10.10 closed.
一般的服务程序并不会在配置文件修改之后立即获得最新的参数,如果想让新配置文件生效,则需要手动重启相应的服务程序,最好也将这个服务程序加入到开机启动项中,这样系统在下一次启动时,该服务程序便会自动运行,继续为用户提供服务:
[root@linuxprobe ~]# systemctl restart sshd
[root@linuxprobe ~]# systemctl enable sshd
安全密钥验证
加密是对信息进行编码和解码的技术,它通过一定的算法将原本可以直接阅读的明文信息转换成密文形式。密钥即是密文的钥匙,有私钥和公钥之分。在传输数据时,如果担心被他们监听或截获,就可以在传输前先使用公钥对数据进行加密处理,然后再进行传送。
一言以蔽之,在生产环境中使用密码进行口令验证终归存在着被暴力破解或嗅探截获的风险。如果正确配置了密钥验证方式,那么 sshd
服务程序将更加安全。我们下面进行具体的配置,其步骤如下。
- 在客户端主机中生成密钥对:
[root@linuxprobe ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):按回车键或设置密钥的存储路径
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): 直接按回车键或设置密钥的密码
Enter same passphrase again: 再次按回车键或设置密钥的密码
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
40:32:48:18:e4:ac:c0:c3:c1:ba:7c:6c:3a:a8:b5:22 root@linuxprobe.com
The key's randomart image is:
+--[ RSA 2048]----+
|+*..o . |
|*.o + |
|o* . |
|+ . . |
|o.. S |
|.. + |
|. = |
|E+ . |
|+.o |
+-----------------+
- 在客户端主机中生成的公钥文件传送至远程主机:
[root@linuxprobe ~]# ssh-copy-id 192.168.10.10
The authenticity of host '192.168.10.20 (192.168.10.10)' can't be established.
ECDSA key fingerprint is 4f:a7:91:9e:8d:6f:b9:48:02:32:61:95:48:ed:1e:3f.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter
out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are
prompted now it is to install the new keys
root@192.168.10.10's password:此处输入远程服务器密码
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '192.168.10.10'"
and check to make sure that only the key(s) you wanted were added.
- 对服务器进行设置,使其只允许密钥验证,拒绝传统的口令验证方式。记得在修改配置文件后保存并重启
sshd
服务程序:
[root@linuxprobe ~]# vim /etc/ssh/sshd_config
………………省略部分输出信息………………
74
75 # To disable tunneled clear text passwords, change to no here!
76 #PasswordAuthentication yes
77 #PermitEmptyPasswords no
78 PasswordAuthentication no
79
………………省略部分输出信息………………
[root@linuxprobe ~]# systemctl restart sshd
- 在客户端尝试登录到服务器,此时无需输入密码也可成功登录。
[root@linuxprobe ~]# ssh 192.168.10.10
Last login: Mon Apr 13 19:34:13 2017
远程传输命令
scp (secure copy)
是一个基于 SSH 协议在网络之间进行安全传输的命令,其格式为“scp [参数] 本地文件 远程帐户@远程IP地址:远程目录
”。
与 cp
命令不同,cp
命令只能在本地硬盘中进行文件复制,而 scp
不仅能够通过网络传送数据,而且所有的数据都将进行加密处理。例如,如果想把一些文件通过网络从一台主机传递到其他主机,这两台主机又恰巧是 Linux 系统,这时使用 scp 命令就可以轻松完成文件的传递了。scp 命令中可用的参数以及作用如表9-2所示。
-1:使用ssh协议版本1;
-2:使用ssh协议版本2;
-4:使用ipv4;
-6:使用ipv6;
-B:以批处理模式运行;
-C:使用压缩;
-F:指定ssh配置文件;
-i:identity_file 从指定文件中读取传输时使用的密钥文件(例如亚马逊云pem),此参数直接传递给ssh;
-l:指定宽带限制;
-o:指定使用的ssh选项;
-P:指定远程主机的端口号;
-p:保留文件的最后修改时间,最后访问时间和权限模式;
-q:不显示复制进度;
-v: 显示详细的连接进度
-r:以递归方式复制。
在使用 scp
命令把本地文件从本地复制到远程主机时,首先需要以绝对路径的形式写清本地文件的存放位置,然后写上要传送到的远程主机的 IP 地址,远程服务器便会要求进行身份验证了。当前用户名称为 root,而密码则为远程服务器的密码,如果想使用指定用户的身份进行验证,可以使用用户名@主机地址的参数格式。最后需要在远程主机的 IP 地址后面添加猫好,并在后面写上要传送到远程主机的哪个文件夹中。由于 scp
命令时基于 SSH 协议进行文件传送的,之前已经设置好了密钥验证,因此当前在传输文件时,并不需要账户和密码。
[root@linuxprobe ~]# echo "Welcome to LinuxProbe.Com" > readme.txt
[root@linuxprobe ~]# scp /root/readme.txt 192.168.10.20:/home
root@192.168.10.20's password:此处输入远程服务器中root管理员的密码
readme.txt 100% 26 0.0KB/s 00:00
此外,还可以使用 scp
命令把远程主机上的文件下载到本地主机,其命令格式为:scp [参数] 远程用户@远程IP地址:远程文件 本地目录
。例如,可以把远程主机的系统版本信息文件下载过来,这样就无须先登录远程主机,再进行文件传送了,也就省去了很多周折。
[root@linuxprobe ~]# scp 192.168.10.20:/etc/redhat-release /root
root@192.168.10.20's password:此处输入远程服务器中root管理员的密码
redhat-release 100% 52 0.1KB/s 00:00
[root@linuxprobe ~]# cat redhat-release
Red Hat Enterprise Linux Server release 7.0 (Maipo)
不间断会话服务:screen
nohup python -u main.py nohup.out
大家在学习 sshd
服务时,不知有没有注意到这样一个事情:当与远程主机的会话被关闭时,在远程主机上运行的命令也随之被中断。
screen
是一款能够实现多窗口远程控制的开源服务程序,简单来说就是为了解决网络异常中断或为了同时控制多个远程终端窗口而设计的程序。用户还可以使用 screen
服务程序同时在多个远程会话中自由切换,能够做到实现如下功能。
- 会话恢复:即便网络中断,也可让会话随时回复,确保用户不会失去对远程会话的控制。
- 多窗口:每个会话都是独立运行的,拥有各自独立的输入输出终端窗口,终端窗口内显示过的信息也将被分开隔离保存,以便下次使用时依然能看到之前的操作记录。
- 会话共享:当多个用户同时登录到远程服务器时,便可以使用会话共享功能让用户之间的输入输出信息共享。
在 RHEL 7 系统中,没有默认安装 screen
服务程序,因此需要配置 Yum
仓库来安装它。首先将虚拟机的 CD/DVD 光盘选项设置为“使用ISO镜像文件”,并选择已经下载好的系统镜像,如图9-12所示。
然后,把光盘设备中的系统镜像挂载到 /media/cdrom
目录。
[root@linuxprobe ~]# mkdir -p /media/cdrom
[root@linuxprobe ~]# mount /dev/cdrom /media/cdrom
mount: /dev/sr0 is write-protected, mounting read-only
最后,使用 Vim 文本编辑器创建 Yum 仓库的配置文件。下述命令中用到的具体参数的含义,可参考 4.1.4 小节。
[root@linuxprobe ~]# vim /etc/yum.repos.d/rhel7.repo
[rhel7]
name=rhel7
baseurl=file:///media/cdrom
enabled=1
gpgcheck=0
现在,就可以使用 Yum 仓库来安装 screen 服务程序了:
[root@linuxprobe ~]# yum install screen
Loaded plugins: langpacks, product-id, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use
subscription-manager to register.
rhel | 4.1 kB 00:00
Resolving Dependencies
--> Running transaction check
---> Package screen.x86_64 0:4.1.0-0.19.20120314git3c2946.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
===============================================================================
Package Arch Version Repository
Size
===============================================================================
Installing:
screen x86_64 4.1.0-0.19.20120314git3c2946.el7 rhel 551 k
Transaction Summary
===============================================================================
Install 1 Package
Total download size: 551 k
Installed size: 914 k
Is this ok [y/d/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : screen-4.1.0-0.19.20120314git3c2946.el7.x86_64 1/1
Verifying : screen-4.1.0-0.19.20120314git3c2946.el7.x86_64 1/1
Installed:
screen.x86_64 0:4.1.0-0.19.20120314git3c2946.el7
Complete!
管理远程会话
screen
命令能做的事情非常多:
- 可以用
-S
参数创建会话窗口; - 用
-d
参数将指定会话进行离线处理; - 用
-r
参数恢复指定会话; - 用
-x
参数一次性恢复所有的会话; - 用
-ls
参数显示当前已有的会话; - 以及用 -wipe 参数把目前无法使用的会话删除。
下面创建一个名称为 backup
的会话窗口。请各位读者留心观察,当在命令行中敲下这条命令的一瞬间,屏幕会快速闪动一下,这时就已经进入 screen 服务会话中了,在里面运行的任何操作都会被后台记录下来。
[root@linuxprobe ~]# screen -S backup
[root@linuxprobe ~]#
执行命令后会立即返回一个提示符。虽然看起来与刚才没有不同,但实际上可以查看到当前的会话正在工作中。
[root@linuxprobe ~]# screen -ls
There is a screen on:
32230.backup (Attached)
1 Socket in /var/run/screen/S-root.
要想退出一个会话也十分简单,只需在命令行中执行 exit
命令即可。
[root@linuxprobe ~]# exit
[screen is terminating]
在日常的生产环境中,其实并不是必须先创建会话,然后再开始工作。可以直接使用 screen
命令执行要运行的命令,这样在命令中的一切操作也都会被记录下来,当命令执行结束后 screen
会话也会自动结束。
[root@linuxprobe ~]# screen vim memo.txt
welcome to linuxprobe.com
为了演示 screen
不间断会话服务的强大之处,我们先来创建一个名为 linux
的会话,然后强行把窗口关闭掉(这与进行远程连接时突然断网具有相同的效果):
[root@linuxprobe ~]# screen -S linux
[root@linuxprobe ~]#
[root@linuxprobe ~]# tail -f /var/log/messages
Feb 20 11:20:01 localhost systemd: Starting Session 2 of user root.
Feb 20 11:20:01 localhost systemd: Started Session 2 of user root.
Feb 20 11:21:19 localhost dbus-daemon: dbus[1124]: [system] Activating service
name='com.redhat.SubscriptionManager' (using servicehelper)
Feb 20 11:21:19 localhost dbus[1124]: [system] Activating service name='com.
redhat.SubscriptionManager' (using servicehelper)
Feb 20 11:21:19 localhost dbus-daemon: dbus[1124]: [system] Successfully activated
service 'com.redhat.SubscriptionManager'
Feb 20 11:21:19 localhost dbus[1124]: [system] Successfully activated service 'com.
redhat.SubscriptionManager'
Feb 20 11:30:01 localhost systemd: Starting Session 3 of user root.
Feb 20 11:30:01 localhost systemd: Started Session 3 of user root.
Feb 20 11:30:43 localhost systemd: Starting Cleanup of Temporary Directories...
Feb 20 11:30:43 localhost systemd: Started Cleanup of Temporary Directories.
由于刚才关闭了会话窗口,这样的操作在传统的远程控制中一定会导致正在运行的命令也突然终止,但在 screen
不间断会话服务中则不会这样。我们只需查看一下刚刚离线的会话名称,然后尝试恢复回来就可以继续工作了:
[root@linuxprobe ~]# screen -ls
There is a screen on:
13469.linux (Detached)
1 Socket in /var/run/screen/S-root.
[root@linuxprobe ~]# screen -r linux
[root@linuxprobe ~]#
[root@linuxprobe ~]# tail -f /var/log/messages
Feb 20 11:20:01 localhost systemd: Starting Session 2 of user root.
Feb 20 11:20:01 localhost systemd: Started Session 2 of user root.
Feb 20 11:21:19 localhost dbus-daemon: dbus[1124]: [system] Activating service
name='com.redhat.SubscriptionManager' (using servicehelper)
Feb 20 11:21:19 localhost dbus[1124]: [system] Activating service name='com.
redhat.SubscriptionManager' (using servicehelper)
Feb 20 11:21:19 localhost dbus-daemon: dbus[1124]: [system] Successfully
activated service 'com.redhat.SubscriptionManager'
Feb 20 11:21:19 localhost dbus[1124]: [system] Successfully activated service
'com.redhat.SubscriptionManager'
Feb 20 11:30:01 localhost systemd: Starting Session 3 of user root.
Feb 20 11:30:01 localhost systemd: Started Session 3 of user root.
Feb 20 11:30:43 localhost systemd: Starting Cleanup of Temporary Directories...
Feb 20 11:30:43 localhost systemd: Started Cleanup of Temporary Directories.
Feb 20 11:40:01 localhost systemd: Starting Session 4 of user root.
Feb 20 11:40:01 localhost systemd: Started Session 4 of user root.
如果我们突然又想到了还有其他事情需要处理,也可以多创建几个会话窗口放在一起使用。如果这段时间内不再使用某个会话窗口,可以把它设置为临时断开(detach)模式,随后在需要时再重新连接(attach)回来即可。这段时间内,在会话窗口内运行的程序会继续执行。
会话共享功能
screen
命令不仅可以确保用户在极端情况下也不丢失对系统的远程控制,保证了生产环境中远程工作的不间断性,而且它还具有会话共享、分屏切割、会话锁定等实用的功能。其中,会话共享功能是一件很酷的事情,当多个用户同时控制主机的时候,它可以把屏幕内容共享出来,也就是说每个用户都可以看到相同的内容。
要实现会话共享功能:
- 使用
ssd
服务程序将终端 A 远程连接到服务器,并创建一个会话窗口。
[root@client A ~]# ssh 192.168.10.10
The authenticity of host '192.168.10.10 (192.168.10.10)' can't be established.
ECDSA key fingerprint is 70:3b:5d:37:96:7b:2e:a5:28:0d:7e:dc:47:6a:fe:5c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.10' (ECDSA) to the list of known hosts.
root@192.168.10.10's password: 此处输入root管理员密码
Last login: Wed May 4 07:56:29 2017
[root@client A ~]# screen -S linuxprobe
[root@client A ~]#
- 使用
ssh
服务程序将终端 B 远程连接到服务器,并执行获取远程会话的命令。接下来,两台主机就能看到相同的内容了。
[root@client B ~]# ssh 192.168.10.10
The authenticity of host '192.168.10.10 (192.168.10.10)' can't be established.
ECDSA key fingerprint is 70:3b:5d:37:96:7b:2e:a5:28:0d:7e:dc:47:6a:fe:5c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.10' (ECDSA) to the list of known hosts.
root@192.168.10.10's password: 此处输入root管理员密码
Last login: Wed Feb 22 04:55:38 2017 from 192.168.10.10
[root@client B ~]# screen -x
[root@client B ~]
使用 Apache 服务部署静态网站
使用 vsftpd 服务传输文件
Samba 或 NFS 实现文件共享
使用 BIND 提供域名解析服务
使用 DHCP 动态管理主机地址
参考资料
- 《Linux 就该这么学》