RHCSA9课堂笔记二
1 | 作者:李晓辉 |
第一章 提⾼命令⾏运⾏效率
虽然一个一个命令执行也是能完成大部分的工作,但是这效率低且非常消耗精神,借助 Bash shell 环境和脚本编写功能,您可以通过将 Linux 命令与 shell 脚本组合在⼀起,解决重复⽽困难的实际问题。
Bash shell 脚本是⼀种可执⾏的⽂件,其中包含了命令列表,⽽且可能还包含⽤于控制整体任务决策的编程逻辑,bash脚本的后缀名一般为.sh,执行bash脚本,需要给脚本加上执行权限或者用bash 命令去执行。
脚本编辑器
有些人用txt或者Windows记事本写脚本,但这种效率很低,也容易出错,选择一个高级编辑器是编写脚本的必要手段,高级编辑器提供语法检查、语法高亮等功能,比如Linux里的vim或者vscode都是不错的编辑器,注意不要选择notepad++,这个作者在官网和公网上公然反华,支持港台独立等,以下是vscode官方下载页面,打开后会自动下载便携版,不需要安装,解压即可使用
1 | https://code.visualstudio.com/docs/?dv=winzip |
指定命令解释器
脚本的第⼀⾏以符号 #! 开头,通常称为 she-bang 或 hash-bang,其源于这两个字符的名称,sharp 或 hash 以及 bang
1 |
/usr/bin/bash
是一个解释器的文件位置,这告诉系统,接下来我写的内容,由谁来负责翻译和执行
PATH 环境变量
一般来说,我们不需要特别声明PATH环境变量,只有当我们在脚本中使用的命令不在默认的PATH路径中的时候,才需要声明
管理PATH路径
以下路径以冒号隔开,如果你的脚本中,命令都放在以下位置,就不需要声明
1 | [root@lixiaohui ~]# echo $PATH |
假设我们的命令在/mnt,就需要在脚本中第二行申明新的PATH变量
1 | [root@lixiaohui ~]# PATH=$PATH:/mnt |
查询某一个在PATH变量路径中的命令位于服务器的具体位置:
1 | [root@lixiaohui ~]# which useradd |
特殊字符
部分字符和词语对 Bash shell 具有特殊含义,不能直接使用,需要使用转义或者其他引号处理
- 转义字符
\
转义字符 \ 用于在字符串中转义特殊字符,使其成为普通字符。
示例:
在这个例子中,$ 转义了 $ 符号,因此 $USER 被打印成普通字符串,而不是变量。
1 | echo "Hello, \$USER" # 输出: Hello, $USER |
- 单引号
' '
单引号内的内容会被原样处理,不会解析其中的变量或转义字符。
示例:
在这个例子中,单引号内的 $USER 被当作普通字符串,而不是变量。
1 | echo 'Hello, $USER' # 输出: Hello, $USER |
- 双引号
" "
双引号内的内容会解析变量和转义字符,但不会解析特殊字符(如空格和换行符)。
示例:
在这个例子中,双引号内的 $USER 变量会被解析并替换为实际的用户名。
1 | echo "Hello, $USER" # 输出: Hello, your_username |
- 反撇号 `` 和 $()
反撇号和 $() 用于命令替换,即在执行命令后将其输出作为字符串插入到命令中。
示例
在这个例子中,反撇号和 $() 都用于执行 date 命令,并将其输出插入到 echo 命令中。
1 | echo "Today is `date`" # 使用反撇号 |
符号总结:
1 | # 定义变量 |
脚本输出处理
正常输出内容重定向:
> filename
错误输出内容重定向:
2> errorfile
正常和错误合并输出到文件:
&> filename
正常和错误不做保留只丢弃:
&> /dev/null
循环和条件结构
在编程中,循环和条件结构是两个基本但非常重要的概念。它们帮助我们控制代码的执行流程,根据特定条件执行不同的代码块,并重复执行某些代码块。
条件结构
条件结构用于根据特定条件执行不同的代码块。在 Bash 中,常见的条件结构是 if 语句。
if 语句
语法:
1 | if [ condition ]; then |
示例:
1 | cat > if.sh <<-'EOF' |
执行看看效果
1 | [root@lixiaohui ~]# bash if.sh |
case 语句
case 语句根据变量的值匹配不同的模式,并执行相应的代码块。当一个模式匹配时,case 语句执行相应的代码块并跳出结构。
语法:
1 | case $variable in |
示例:
解释:
读取输入: 使用 read 命令读取用户输入的星期几。
模式匹配: 根据用户输入的值匹配不同的模式:
如果输入是 Mon,则输出 “今天是星期一”。
如果输入是 Tue,则输出 “今天是星期二”。
类似地,处理其他几天的输入。
如果输入是 Sat 或 Sun,则输出 “今天是周末”。
如果输入不匹配任何模式,则输出 “无效的输入”。
1 |
|
循环结构
循环结构用于重复执行一段代码。Bash 中有几种常见的循环结构,包括 for 循环、while 循环和 until 循环。
for 循环
语法:
1 | for var in list; do |
示例
1 |
|
while 循环
while 循环会在给定的条件为真(true)时执行循环体内的代码块。当条件为假(false)时,循环终止。
语法:
1 | while [ condition ]; do |
示例:
解释:
初始化: counter=1 初始化计数器变量。
条件检查: [ $counter -le 5 ] 检查计数器是否小于或等于 5。
循环体: echo “这是第 $counter 次循环” 打印当前循环次数,然后 ((counter++)) 将计数器递增。
循环结束: 当 counter 超过 5 时,条件变为假,循环终止。
1 |
|
until 循环
until 循环会在给定的条件为假(false)时执行循环体内的代码块。当条件为真(true)时,循环终止。
语法:
1 | until [ condition ]; do |
示例:
解释:
初始化: counter=1 初始化计数器变量。
条件检查: [ $counter -gt 5 ] 检查计数器是否大于 5。
循环体: echo “这是第 $counter 次循环” 打印当前循环次数,然后 ((counter++)) 将计数器递增。
循环结束: 当 counter 大于 5 时,条件变为真,循环终止。
1 |
|
Bash 脚本退出代码
Bash 脚本退出代码(Exit Codes)用于指示脚本或命令执行的结果。退出代码是一个整数,通常在命令或脚本执行完成后返回。标准惯例是,退出代码为 0 表示成功,任何非 0 的值表示失败或错误。
检查上一个命令的退出代码
在 Bash 中,可以使用内置变量 $? 检查上一个命令的退出代码:
1 |
|
设置自定义退出代码
在脚本中,可以使用 exit 命令设置自定义的退出代码:
1 |
|
常见退出代码
0
: 成功(Success)
1
: 一般错误(General error)
2
: 错误的用法(Misuse of shell builtins)
126
: 命令不可执行(Command invoked cannot execute)
127
: 命令未找到(Command not found)
128
: 无效的退出参数(Invalid argument to exit)
130
: 命令通过 Ctrl+C 被终止(Script terminated by Control-C)
255
: 退出状态码超出范围(Exit status out of range)
test 命令
test 命令用于检查某些条件是否为真,并返回相应的退出状态码。它在编写脚本时非常有用,可以用于测试字符串、文件、目录以及数值比较等。
常用表达式总结
字符串比较:
-z STRING
:字符串为空
-n STRING
:字符串非空
STRING1 = STRING2
:两个字符串相等
STRING1 != STRING2
:两个字符串不相等
文件和目录测试:
-e FILE
:文件存在
-r FILE
:文件可读
-w FILE
:文件可写
-x FILE
:文件可执行
-d FILE
:是目录
-f FILE
:是常规文件
数值比较:
NUM1 -eq NUM2
:两个数值相等
NUM1 -ne NUM2
:两个数值不相等
NUM1 -gt NUM2
:NUM1 大于 NUM2
NUM1 -lt NUM2
:NUM1 小于 NUM2
NUM1 -ge NUM2
:NUM1 大于或等于 NUM2
NUM1 -le NUM2
:NUM1 小于或等于 NUM2
语法:
1 | test EXPRESSION |
测试字符串
test 命令可以用于测试字符串的各种属性,包括字符串是否为空、两个字符串是否相等等。
示例:
测试字符串是否为空:
1 | str="" |
测试字符串是否非空:
1 | str="Hello" |
测试两个字符串是否相等:
1 | str1="Hello" |
测试目录和文件
test 命令还可以用于测试文件和目录的各种属性,例如文件是否存在、是否可读、是否为目录等。
示例:
测试文件是否存在:
1 | if [ -e "/path/to/file" ]; then |
测试文件是否可读:
1 | if [ -r "/path/to/file" ]; then |
测试路径是否为目录:
1 | if [ -d "/path/to/directory" ]; then |
测试文件是否为常规文件:
1 | if [ -f "/path/to/file" ]; then |
数值比较
test 命令可以用于比较数值,例如检查两个数值是否相等、一个数值是否大于另一个数值等。
示例:
比较两个数值是否相等:
1 | num1=5 |
比较一个数值是否大于另一个数值:
1 | num1=5 |
比较一个数值是否小于另一个数值:
1 | num1=5 |
正则表达式匹配输出
grep 是 Linux 中非常强大的命令行工具,用于搜索文本文件中的内容。它支持使用正则表达式(regular expressions)来匹配复杂的搜索模式。
grep 命令的基本语法如下:
1 | grep [选项] PATTERN [文件...] |
常用选项和正则介绍
常用选项
-i
:忽略大小写
-v
:显示不匹配的行
-r
:递归搜索目录
-n
:显示匹配行的行号
-l
:仅显示包含匹配模式的文件名
-c
:显示匹配的行数
-E
:使用扩展正则表达式(等同于 egrep)
-q
选项用于静默模式(quiet mode),它会抑制所有输出,只返回退出状态码
-A
选项用于显示匹配行之后的指定行数,格式为 -A NUM,其中 NUM 是显示的行数。
-B
选项用于显示匹配行之前的指定行数,格式为 -B NUM,其中 NUM 是显示的行数。
-e
选项用于指定多个搜索模式
常见的正则表达式符号:
.
:匹配任意单个字符
^
:匹配行的开头
$
:匹配行的结尾
*
:匹配前面的字符零次或多次
+
:匹配前面的字符一次或多次(需要使用扩展正则表达式 -E)
?
:匹配前面的字符零次或一次(需要使用扩展正则表达式 -E)
[]
:匹配括号内的任意字符
|
:表示“或”(需要使用扩展正则表达式 -E)
匹配案例
假设有一个文件 example.txt,内容如下:
1 | apple |
简单匹配:
1 | grep 'apple' example.txt |
输出
1 | apple |
忽略大小写:
1 | grep -i 'apple' example.txt |
输出
1 | apple |
显示行号:
1 | grep -n 'apple' example.txt |
输出
1 | 1:apple |
匹配行的开头:
1 | grep '^a' example.txt |
输出
1 | apple |
匹配行的结尾:
1 | grep 'e$' example.txt |
输出
1 | apple |
匹配任意字符:
1 | grep 'a.p' example.txt |
输出:
1 | apple |
匹配零次或多次:
1 | grep 'a*' example.txt |
输出:
1 | apple |
匹配一次或多次(使用扩展正则表达式 -E):
1 | grep -E 'a+' example.txt |
输出:
1 | apple |
使用“或”操作符(扩展正则表达式 -E):
1 | grep -E 'apple|orange' example.txt |
输出:
1 | apple |
静默模式
1 | [root@lixiaohui ~]# grep -q apple example.txt |
匹配行之后的指定行数
1 | [root@lixiaohui ~]# grep -A 2 apple example.txt |
匹配行之前的指定行数
1 | [root@lixiaohui ~]# grep -B 2 Apple example.txt |
指定多个搜索模式
1 | [root@lixiaohui ~]# grep -e ^a -e a$ example.txt |
不匹配指定模式的行
1 | [root@lixiaohui ~]# grep -v 'apple' example.txt |
第二章 调度未来任务
在这一章,我们主要是学习在Linux系统中,怎么调度任务,以及让任务在未来的某个时间执行
atd 服务
atd 服务用于在特定时间执行一次性任务,通常通过 at 命令进行管理。它是一个非常适合运行在未来某个时间点执行的任务的工具。此工具安排的任务会放在/var/spool/at/
先启动此服务
1 | sudo systemctl start atd |
这个命令将在当前时间后一分钟执行 echo ‘Hello World’ > /tmp/hello.txt,将结果写入 /tmp/hello.txt 文件。
1 | [root@lixiaohui ~]# echo "echo 'Hello World' > /tmp/hello.txt" | at now + 1 minute |
查询一下看看
1 | [root@lixiaohui ~]# atq |
当然,也可以用交互式完成任务安排
需要注意的是,此命令不校验你的命令输入是否正确,且退出是用的ctrl d快捷键
1 | [root@lixiaohui ~]# at 15:30 |
删除某个at任务,后面的2是任务编号
1 | atrm 2 |
crond 服务
crond 服务用于定期执行计划任务,通常通过 cron 表达式进行管理。它适用于需要周期性运行的任务。用crontab安排的命令将放在/var/spool/cron/
先启动服务
1 | sudo systemctl start crond |
周期性计划,需要了解时间的安排,以下配置文件中可以看到时间安排和时间取值范围:
1 | [root@lixiaohui ~]# cat /etc/crontab |
一般而言,超级管理员为系统安排的计划任务,有可能会放入上述配置文件,不过实际情况下,我们都是为用户安排任务,例如用root用户安排,这就是超级用户给系统安排的,所以以上配置文件中,一般不做任何修改
这段 /etc/crontab 文件显示了 cron 服务的配置文件格式,用于定义计划任务的调度。
解释 crontab 文件内容:
SHELL=/bin/bash:指定用于执行命令的 Shell。
PATH=/sbin:/bin:/usr/sbin:/usr/bin:指定执行命令时的路径。
MAILTO=root:指定任务执行的输出将发送到 root 用户的邮箱。如果为空,则不会发送邮件。
时间顺序可以当口诀背诵:分时日月周
时间格式的表达:
调度规范 | 描述 |
---|---|
0 0 * * * | 每天午夜运行指定的任务 |
0 0 * * 7 | 每周日运行指定的任务 |
0 * * * * | 每小时运行指定的任务 |
*/4 * * * * | 每四分钟运行指定的任务 |
为自己添加一个cron周期性任务
1 | crontab -e |
查看用户的 crontab 任务:
1 | crontab -l |
为user1添加一个cron周期性任务
为被人安排任务,需要有特权才可以
1 | crontab -e -u user1 |
查询user1名下的cron任务
1 | crontab -l -u user1 |
管理临时⽂件
systemd-tmpfiles-setup 服务是 systemd 套件的一部分,主要用于创建和清理临时文件和目录。这些临时文件和目录的管理规则定义在 /etc/tmpfiles.d/ 目录和 /etc/systemd/tmpfiles.d/ 目录中。它在系统启动时运行,以确保系统中的临时文件和目录按照配置文件中的规则被正确创建、清理或管理。
systemd-tmpfiles-setup 服务的主要功能
创建临时文件和目录:根据配置文件中的规则,创建系统运行所需的临时文件和目录。
清理临时文件和目录:按照预定义的时间和条件,删除不再需要的临时文件和目录,防止磁盘空间被不必要的文件占用。
设置文件权限和属性:配置文件中可以定义文件和目录的权限、所有者、群组等属性,确保安全性和正确性。
配置文件通常位于以下几个目录中:
/etc/tmpfiles.d/ # 管理员最常用
/run/tmpfiles.d/
/usr/lib/tmpfiles.d/
配置文件的格式通常如下:
1 | #Type Path Mode UID GID Age Argument |
各字段的含义如下:
Type
:操作类型,如创建目录(d),创建文件(f),清理目录(r),设置权限(a)等。
Path
:文件或目录路径。
Mode
:权限模式,如 0755。
UID
:所有者的用户 ID。
GID
:所有者的组 ID。
Age
:文件或目录的最大存在时间,超时则被删除。
Argument
:额外的参数,根据操作类型不同而不同。
假设我们要创建一个名为 myapp 的临时目录,并设置适当的权限,可以创建如下配置文件:
创建配置文件
1 | cat > /etc/tmpfiles.d/myapp.conf <<-EOF |
启用服务
1 | [root@lixiaohui ~]# systemctl enable systemd-tmpfiles-setup systemd-tmpfiles-clean --now |
默认情况下,文件的创建和清理,会根据你的配置文件自动执行,如需手工触发,可以这么做
1 | systemd-tmpfiles --create /etc/tmpfiles.d/myapp.conf |
第三章 分析和存储⽇志
操作系统内核和其他进程为系统运⾏时发⽣的事件记录⽇志。这些⽇志⽤于系统审核和问题的故障排除,红帽企业 Linux 使⽤基于 syslog 协议的标准⽇志记录系统来记录系统消息。许多程序使⽤⽇志系统来记录事件,并将它们整理到⽇志⽂件中。systemd-journald 和 rsyslog 服务处理红帽企业 Linux 9 中的 syslog 消息。
systemd-journald 服务是操作系统事件⽇志架构的核⼼。systemd-journald 服务从许多来
源收集事件消息:
- 系统内核
- 启动过程早期阶段的输出
- 守护进程的标准输出和标准错误
- 系统⽇志事件
systemd-journald 服务将⽇志重构为⼀种标准格式,并写进带有索引的结构化系统⽇志中。默认情况下,该⽇志存储在系统重启后不保留的⽂件系统上。
rsyslog 服务对 syslog 消息进⾏排序,并将它们写⼊到 /var/log ⽬录下的⽇志⽂件中。
日志文件 | 所存储消息的类型 |
---|---|
/var/log/messages | 大多数系统日志消息记录在此处。例外包括与身份验证、电子邮件处理和调度作业执行相关的消息,以及纯粹与调试相关的消息。 |
/var/log/secure | 与安全性和身份验证事件相关的 syslog 消息。 |
/var/log/maillog | 与邮件服务器相关的 syslog 消息。 |
/var/log/cron | 与调度作业执行相关的 syslog 消息。 |
/var/log/boot.log | 与系统启动相关的非 syslog 控制台消息。 |
查看 Syslog ⽂件
许多程序使⽤ syslog 协议将事件记录到系统。以下为消息来源表格
代码 | 设备 | 设备描述 |
---|---|---|
0 | kern | 内核消息 |
1 | user | 用户级消息 |
2 | 邮件系统消息 | |
3 | daemon | 系统守护进程消息 |
4 | auth | 身份验证和安全消息 |
5 | syslog | 内部 syslog 消息 |
6 | lpr | 打印机消息 |
7 | 新闻 | 网络新闻消息 |
8 | uucp | UUCP 协议消息 |
9 | cron | 时钟守护进程消息 |
10 | authpriv | 非系统授权消息 |
11 | ftp | FTP 协议消息 |
16-23 | local0 到 local7 | 自定义本地消息 |
下表列出了标准的 syslog 优先级,以降序排序:
代码 | 优先级 | 优先级描述 |
---|---|---|
0 | emerg | 系统不可用 |
1 | alert | 必须立即采取措施 |
2 | crit | 临界情况 |
3 | err | 非严重错误状况 |
4 | warning | 警告情况 |
5 | notice | 正常但重要的事件 |
6 | info | 信息性事件 |
7 | debug | 调试级别消息 |
rsyslog
服务使用日志消息的来源和优先级来确定如何进行处理。规则在 /etc/rsyslog.conf
文件和 /etc/rsyslog.d
目录中具有 .conf
扩展名的任何文件中。
1 | [root@lixiaohui ~]# cat /etc/rsyslog.conf |
⽇志⽂件轮转
logrotate 命令会轮转⽇志⽂件,以防⽌它们在 /var/log ⽬录中占⽤太多空间
假设我们有一个应用程序日志文件位于/var/log/messages,配置一个 logrotate 规则。通过这个规则,我们将管理 messages 日志文件,以防止它占用过多的磁盘空间。
创建 logrotate 配置文件
我们在 /etc/logrotate.d/ 目录下创建一个名为 messages 的配置文件:
1 | cat > /etc/logrotate.d/messages <<-EOF |
这种服务不需要我们手工启动,不过我们可以手工测试一下配置文件是否正确
1 | logrotate /etc/logrotate.d/messages |
看看效果
1 | [root@lixiaohui ~]# ls -lh /var/log/messages* |
分析 Syslog 条⽬
tail 命令是一个非常有用的工具,用于查看文件的末尾部分。它通常用于分析日志文件,因为日志文件会不断增长,而我们通常只需要查看最新的日志条目。
查看文件的最后10行
1 | tail /var/log/messages |
显示文件的最后n行
1 | tail -n 20 /var/log/messages |
持续监控文件(实时输出)
1 | tail -f /var/log/messages |
跟踪多个文件
1 | tail -f /var/log/messages /var/log/syslog |
⼿动发送 Syslog 消息
logger 命令可将消息发送到 rsyslog 服务
1 | logger -p user.info "This is an informational message" |
看看日志
1 | [root@lixiaohui ~]# tail /var/log/messages |
systemd-journald 服务
systemd-journald 服务将⽇志数据存储在带有索引的结构化⼆进制⽂件中,在红帽企业 Linux 中,默认情况下使⽤基于内存的 /run/log ⽬录来存储系统⽇志。系统关机时,/run/log ⽬录的内容将丢失。
journalctl 命令是一个强大的工具,用于从 systemd 日志中检索和查看日志消息。它可以过滤、格式化和查看由 systemd 管理的各种日志条目。
查看系统启动以来的日志
1 | journalctl -b |
按时间过滤日志
1 | journalctl --since "today" |
查看特定服务的日志
1 | journalctl -u sshd.service |
实时输出日志
1 | journalctl -f |
按优先级过滤日志
1 | journalctl -p err |
以 JSON 格式输出日志
1 | journalctl -u sshd.service -p info --since "today" -o json-pretty |
持久化日志
systemd-journald 服务默认情况下使⽤基于内存的 /run/log ⽬录来存储系统⽇志。系统关机时,/run/log ⽬录的内容将丢失,这对于日志而言,默认没有持久化,我们来看看怎么持久化。
按照以下步骤操作:
- 打开日志配置文件:编辑 /etc/systemd/journald.conf 文件。
1 | vim /etc/systemd/journald.conf |
- 修改持久化设置:找到 Storage= 选项,将其设置为 persistent。
1 | [Journal] |
- 创建持久化存储路径:/var/log/journal/。
1 | mkdir /var/log/journal |
- 重启 systemd-journald:运行 sudo systemctl restart systemd-journald 以使更改生效。
1 | systemctl restart systemd-journald |
重启服务后,你就会在目录里看到它自动创建了它自己的索引目录
要实在看不到,重启一下机器
1 | [root@lixiaohui ~]# ls /var/log/journal/ |
维护准确的时间
在日志中,时间是一个很重要的东西,尤其是管理了多个机器时,维护时间的统一是必要的,不然无法分析故障,我们先来看看时间的设置
显示时间
1 | [root@lixiaohui ~]# timedatectl |
关闭NTP同步
1 | [root@lixiaohui ~]# timedatectl set-ntp 0 |
设置时间
1 | [root@lixiaohui ~]# timedatectl set-time '2025-01-01 02:00:00' |
列出并设置时区
1 | [root@lixiaohui ~]# timedatectl list-timezones | grep -i shanghai |
chronyd 是 Chrony 项目中的一个守护进程,用于同步系统时钟。它是一个替代 ntpd 的 NTP 客户端和服务器,具有更好的精度和灵活性,尤其适用于频繁断开网络连接或存在高抖动的环境。
chronyd 的主要配置文件是 /etc/chrony.conf。你可以编辑这个文件来配置时间同步源和选项。
启动 chronyd 服务:
1 | systemctl enable chronyd --now |
管理/etc/chrony.conf 配置文件
以下为从阿里云同步时间的案例
1 | [root@lixiaohui ~]# vim /etc/chrony.conf |
以下为向特定网段授时的案例
1 | [root@lixiaohui ~]# vim /etc/chrony.conf |
启用并启动 chronyd 服务:
每次修改了配置文件,都重启一下这个服务
1 | systemctl restart chronyd |
启用 NTP 并设置时区:
1 | timedatectl set-ntp true |
查看时间同步状态:
1 | [root@lixiaohui ~]# chronyc tracking |
第四章 归档和传输⽂件
管理压缩的 tar 存档
tar 命令是 Linux 系统中常用的归档工具,用于创建和操作归档文件(通常称为 tarball)。tar 命令非常强大,可以用于备份数据、传输文件、解压缩文件等多种场景。
常见使用场景
创建归档文件
:将多个文件或目录打包成一个归档文件。
解压归档文件
:从归档文件中提取文件和目录。
查看归档内容
:列出归档文件的内容。
添加文件到归档
:向现有的归档文件中添加文件。
压缩和解压
:与压缩工具(如 gzip 或 bzip2)结合使用,创建压缩归档文件或解压它们。
常见选项
-c
:创建一个新的归档文件。
-x
:从归档文件中提取文件。
-t
:列出归档文件的内容。
-f
:指定归档文件的文件名。
-v
:显示详细信息(verbose)。
-z
:通过 gzip 压缩归档文件。
-j
:通过 bzip2 压缩归档文件。
-J
: 通过 xz 压缩归档文件。
-C
:切换到指定目录。这是大写的C
创建归档文件
将 /etc/ 目录打包成 documents.tar 文件:
1 | tar -cvf documents.tar /etc |
创建压缩归档文件
使用 gzip 压缩 /etc 目录,生成 documents.tar.gz 文件:
1 | tar -czvf documents.tar.gz /etc |
解压归档文件
解压 documents.tar 到当前目录:
1 | tar -xvf documents.tar |
将 documents.tar 解压到 /tmp 目录:
1 | tar -xvf documents.tar -C /tmp |
在系统之间安全地传输⽂件
在系统之间安全地传输文件是日常运维和开发工作中非常常见的需求。以下是三种常用的安全文件传输工具:scp、sftp 和 rsync,以及每种工具的使用案例。
scp(Secure Copy)
scp 是用于在本地和远程主机之间安全地复制文件的命令。它使用 SSH 协议来加密传输,确保数据的安全性。
从本地主机复制文件到远程主机:
1 | scp /etc/fstab root@serverb:/tmp/ |
从远程主机复制文件到本地主机:
1 | scp root@serverb:/etc/hostname /tmp/ |
复制目录: 使用 -r 选项递归地复制整个目录:
1 | scp -r root@serverb:/etc/ /tmp/ |
sftp(Secure File Transfer Protocol)
sftp 是一种与 FTP 类似,但使用 SSH 协议进行加密的文件传输协议。它提供了一个交互式的命令行界面用于管理文件传输。
连接到远程服务器:
1 | sftp root@serverb |
ls 列出目录内容
put localfile /remotepath/remotefile
get /remotepath/remotefile /localpath/localfile
exit
rsync
rsync 是一个快速且通用的文件复制工具,适用于本地和远程文件同步。它可以增量传输文件,只传输更改过的部分,从而提高效率。rsync 也支持 SSH 协议进行加密传输。
常见选项
-a
:归档模式,递归复制目录,并保留符号链接、文件权限、用户和组所有权、时间戳等属性。等同于 -rlptgoD。
-r
:递归复制目录及其内容(已包含在 -a 中)。
-l
:保留符号链接(已包含在 -a 中)。
-p
:保留文件权限(已包含在 -a 中)。
-t
:保留时间戳(已包含在 -a 中)。
-g
:保留文件所属组(已包含在 -a 中)。
-o
:保留文件所有者(需 root 权限,已包含在 -a 中)。
-D
:保留设备文件和特殊文件(已包含在 -a 中)。
同步本地和远程目录:
1 | rsync -avz /path/to/localdir user@remotehost:/path/to/remotedir |
从远程服务器同步到本地目录:
1 | rsync -avz user@remotehost:/path/to/remotedir /path/to/localdir |
第五章 调优系统性能
命令行调整调优配置集
tuned 是一个用于动态调整系统性能的工具,它可以根据不同的工作负载自动调整系统设置。
静态调优会对配置集中由tuned 守护进程在启动时应⽤的预定义 kernel 参数进⾏配置。对于静态调优⽽⾔,tuned 守护进程针对整体性能预期来设置内核参数,不随活跃度变化⽽调整这些参数。
对于动态调优⽽⾔,tuned 守护进程会监视系统活动,并根据运⾏时⾏为变化来调整设置。动态调优会从选定调优配置集的初始设置开始,不断调整调优设置以适应当前⼯作负载。
我们的课程中涉及到的是静态调优方法,静态调优的方法是调整预期的配置文件并使其生效
安装tuned
1 | dnf install tuned -y |
查看配置文件
tuned 应⽤将调优配置集存储在 /usr/lib/tuned 和 /etc/tuned ⽬录下。每个配置集都有⼀个
单独的⽬录,⽬录中包含 tuned.conf 主配置⽂件以及其他可选⽂件。
1 | [root@lixiaohui ~]# ls /usr/lib/tuned/ |
看看配置文件参数
1 | [root@lixiaohui ~]# grep -v -e ^$ -e ^# /usr/lib/tuned/balanced/tuned.conf |
看看都有哪些配置文件
1 | [root@lixiaohui ~]# tuned-adm list |
看看当前激活的配置文件
1 | [root@lixiaohui ~]# tuned-adm active |
切换至balanced
1 | [root@lixiaohui ~]# tuned-adm profile balanced |
tuned-adm recommend 命令可以为系统推荐调优配置集
1 | [root@lixiaohui ~]# tuned-adm recommend |
使⽤tuned-adm off 命令来关闭 tuned 应⽤调优活动
1 | [root@lixiaohui ~]# tuned-adm off |
如果还想开,就profile一个新的就行
通过 Web 控制台管理配置集
先启动cockpit,并用root登录
1 | [root@lixiaohui ~]# echo "" > /etc/cockpit/disallowed-users |
http://你的服务器ip
登录后,点击性能集这里
选择好执行,点击change即可
影响进程调度
在 Linux 系统中,进程优先级决定了调度程序为某个进程分配 CPU 时间的优先级高低。优先级越高,进程被调度执行的机会就越大,反之亦然。
进程优先级
Linux 使用一个称为 niceness 的值来表示进程的优先级。niceness 值范围从 -20(最高优先级)到 19(最低优先级),默认值为 0。值越低,优先级越高。
负值(如 -10):提高优先级,使进程获得更多的 CPU 时间。
零值(0):默认优先级。
正值(如 10):降低优先级,使进程获得较少的 CPU 时间。
nice 命令
nice 命令用于启动一个进程并指定其初始 niceness 值。
示例
启动一个sleep 1000的进程,并将其 niceness 值设为 10,这将启动sleep 1000,并指定其初始 niceness 值为 10(较低优先级)。
1 | nice -n 10 sleep 1000 |
上面的命令是不是卡住啦,正常的,因为要sleep 1000秒,直接ctrl c取消,放后台去执行看看
可以看到,我们的经常以10的优先级在运行中
1 | [root@lixiaohui ~]# nice -n 10 sleep 1000 & |
renice 命令
renice 命令用于修改一个已经在运行的进程的 niceness 值。
示例
刚才有一个进程 ID 为 11487 的正在运行的进程。你可以使用 renice 命令将其 niceness 值改为 -5(较高优先级):
1 | [root@lixiaohui ~]# renice -n -5 -p 11487 |
不过需要注意的是,只有root用户可以提高优先级,对于普通用户而言,只能降低优先级,而不能提高,普通用户最高优先级就是0
第六章 管理 SELinux 安全性
SELinux 基本概念
SELinux(Security-Enhanced Linux)是一个 Linux 内核模块和一套用户空间工具,旨在提供强制访问控制(MAC)安全机制。它最初由美国国家安全局(NSA)开发,后被集成到 Linux 内核中,用于增强系统的安全性。
如果一个应用想要加载某个文件或端口号,必须要经过SELinux的同意,不让应用将无法加载文件或端口号,而这个同意则是指:应用加载的文件或端口在应用兼容的标签列表中,举例来说
Web 服务器apache进程标有 httpd_t 类型的上下⽂。/var/www/html/ ⽬录和其他位置上的Web 服务器⽂件和⽬录标有 httpd_sys_content_t 类型上下⽂。/tmp 和 /var/tmp ⽬录中的临时⽂件具有 tmp_t 类型上下⽂作为标签。Web 服务器的端⼝具有 http_port_t 类型上下⽂作为标签。
当apache去加载/var/www/html/目录中的文件时,SELinux会检查,此目录所拥有的标签,是否和SELinux数据库中记录的apache允许加载的标签列表一致,一致则允许加载,不一致则拒绝加载
SELinux的安全上下文
安全上下文有时候也被称为标签,每个文件、进程和资源都有一个安全上下文(security context),该上下文包括用户、角色、类型和级别。SELinux 策略根据这些上下文来决定是否允许访问。
这里的unconfined_u:object_r:admin_home_t:s0
就是我们说的安全上下文,不过在我们的课程中,我们只关注倒数第二列,也就是admin_home_t
这部分,我们把这部分称为类型
1 | [root@lixiaohui ~]# touch filetest |
SELinux的模式
SELinux 有三种运行模式:
强制(Enforcing)
:这是最严格的模式,在这种模式下,SELinux 会强制执行其安全策略,阻止所有不符合策略的访问,并记录审计日志。
许可(Permissive)
:在这种模式下,SELinux 不会实际阻止访问,而是会记录所有不符合策略的访问尝试。此模式常用于调试和策略开发。
禁用(Disabled)
:完全禁用 SELinux,不进行任何访问控制检查或记录。
查看现在的模式
1 | [root@lixiaohui ~]# getenforce |
切换 SELinux 模式
需要注意的是,这种setenforce不管是0还是1,只是临时生效,重启后,就没了,想要永久生效,还得看下面的配置文件
1 | [root@lixiaohui ~]# setenforce 0 |
SELinux的配置
修改了配置文件后,将不会立刻生效,需要重启服务器后,才会生效
SELinux 配置文件位于 /etc/selinux/config,你可以通过编辑该文件来设置 SELinux 的模式和策略:
1 | vim /etc/selinux/config |
在这个文件中,一共就两行生效,我们关注的是第一行SELINUX=
,我们只需要将第一行修改即可
1 | SELINUX=enforcing |
请格外注意
⾃红帽企业 Linux 9 起,只能通过在启动时使⽤ selinux=0 内核参数来完全禁⽤ SELinux。RHEL 不再⽀持在 /etc/selinux/config ⽂件中设置SELINUX=disabled 选项。
⾃ RHEL 9 起,在 /etc/selinux/config ⽂件中禁⽤ SELinux 会导致 SELinux 启动并执⾏主动实施,但不会加载任何策略。由于策略规则定义了允许的操作,因此如果未加载任何策略,则所有操作都会被拒绝。此⾏为是有意为之,旨在拦截试图绕过SELinux 保护的恶意⾏为。
控制 SELinux ⽂件上下⽂
新创建文件的上下文
SELinux 使用目录的默认上下文来决定新创建文件的上下文。这意味着在某个目录中创建的新文件会继承该目录的安全上下文类型。例如,在 /var/www/html 目录中创建的文件会继承 httpd_sys_content_t 类型,因为这个目录的默认上下文通常是为 Web 服务器内容设置的。
cp 和 mv 对文件上下文的影响
- cp 命令
使用 cp 命令复制文件时,新文件会根据目标目录的默认上下文类型分配新的安全上下文。
例如,假设你将一个文件从一个目录复制到另一个目录:
发现复制过来的上下文,最终是目标地的默认上下文
1 | [root@lixiaohui ~]# cp /etc/fstab /root |
当然,你可以使用额外的选项来保留其原来的标签
1 | [root@lixiaohui ~]# cp --preserve=context /etc/fstab /tmp/fstab |
- mv命令
使用 mv 命令移动文件时,文件的安全上下文通常保持不变,因为 mv 实际上只是改变了文件的路径而不是重新创建文件。例如:
1 | [root@lixiaohui ~]# ll -Z /tmp/fstab |
恢复文件默认上下文
这个默认上下文是指已经记录到selinux数据库里的上下文,比如上面的/root和/tmp,数据库就有记录的
我们发现,filea的标签有点不对
1 | [root@lixiaohui ~]# ll -Z |
来,将它恢复成数据库中此路径记录的样子
1 | [root@lixiaohui ~]# restorecon -RvF /root/ |
更改 SELinux 上下⽂
在 Linux 中,修改 SELinux 上下文是确保安全策略适用于文件和目录的重要步骤。这里介绍两个常用命令 chcon 和 semanage,并展示它们的用法和区别。
chcon 命令
chcon 命令用于临时更改文件或目录的 SELinux 上下文。这个更改不会永久保留,系统重启或运行 restorecon 时会恢复为默认上下文。
基本用法
1 | chcon [选项] <新的上下文> <文件或目录> |
更改文件上下文类型:
假设你有一个文件夹 /mnt,你想将其上下文类型更改为 tmp_t:
1 | [root@lixiaohui ~]# ll -Zd /mnt/ |
更改目录及其内容的上下文类型:
递归更改目录 /mnt 及其内容的上下文类型:
1 | chcon -R -t tmp_t /mnt |
semanage 命令
semanage 命令用于管理 SELinux 策略,包括定义文件的默认上下文。这些更改是永久性的,在系统重启或运行 restorecon 后仍然有效。
基本用法
1 | semanage fcontext -a -t <新的上下文> <文件或目录的路径正则表达式> |
为目录添加默认上下文:
假设你希望 /custom/web 目录及其内容的默认上下文类型为 httpd_sys_content_t:
1 | [root@lixiaohui ~]# mkdir -p /custom/web |
我们发现,命令设置后,好像没有生效,那是因为semanage是向数据库注册条目,并不是给文件真的赋予,真的赋予需用restorecon命令从数据库读出条目并应用
1 | [root@lixiaohui ~]# restorecon -RvF /custom/web |
SELinux 常用的选项
以下是 semanage fcontext 命令的常用选项及其简要解释:
-a (add)
:添加新的文件上下文规则。
-d (delete)
:删除现有的文件上下文规则。
-m (modify)
:修改现有的文件上下文规则。
-l (list)
:列出当前的文件上下文规则。
chcon 和 semanage 的区别
chcon
:用于临时更改文件或目录的上下文。适用于需要立即生效但不需要持久化的场景。系统重启或运行 restorecon 后更改会丢失。
semanage
:用于永久更改文件或目录的默认上下文。适用于需要持久化的更改,系统重启或运行 restorecon 后仍然有效。
查询selinux数据库里记录的条目
最常⻅的扩展正则表达式是 (/.*)?
此语法描述为“⼀个以斜杠开头并后跟任意数量的字符的字符集,该集合可以存在或不存在”。更简单地说,此语法匹配⽬录本⾝,即使为空,也会匹配该⽬录中创建的⼏乎任何⽂件名。
1 | [root@lixiaohui ~]# semanage fcontext -l |
使⽤布尔值调整 SELinux 策略
在管理 SELinux 策略时,布尔值和上下文的应用场景不同,它们各自有特定的用途和优势。以下是它们的区别和应用场景:
什么时候用布尔值
布尔值用于动态调整 SELinux 策略的特性,主要在以下场景中使用:
启用或禁用特定服务功能:布尔值可以控制某些服务的特定功能。例如,允许或禁止 HTTP 服务器发起网络连接 (
httpd_can_network_connect
)。动态调整安全策略:布尔值可以在运行时进行调整,而无需重新编译或重新加载 SELinux 策略。例如,允许或禁止 FTP 服务器写入匿名用户文件 (
ftpd_anon_write
)。便于测试和调试:在开发和测试环境中,可以临时启用或禁用某些策略特性,观察其影响。例如,启用系统管理员通过 SSH 登录 (
ssh_sysadm_login
)。
什么时候用上下文
上下文用于定义文件、目录和进程的安全属性,主要在以下场景中使用:
设置文件和目录的访问控制:通过上下文定义文件和目录的安全属性,确保只有特定进程或用户可以访问。例如,设置 Web 服务器内容的上下文为
httpd_sys_content_t
。持久性策略:上下文设置是持久性的,适用于需要长期生效的安全策略。例如,配置某个目录及其子目录的默认上下文类型。
精细化控制:上下文提供了更精细的访问控制,可以针对不同类型的文件和进程进行细粒度的策略配置。例如,设置数据库文件的上下文为
mysqld_db_t
。
获取所有可用的布尔值
1 | [root@lixiaohui ~]# getsebool -a | more |
设置布尔值
使用 setsebool 命令可以设置一个布尔值的状态。setsebool 支持临时和永久两种设置方法。
临时设置:仅在当前系统运行期间生效,系统重启后将恢复默认值。
1 | [root@lixiaohui ~]# getsebool httpd_enable_cgi |
临时设置后,就和数据库中记录的不一样了,我们可以用以下方式来查看现有的状态和默认的状态
可以看到,我们的状态是off,默认是on
1 | [root@lixiaohui ~]# semanage boolean -l |
永久设置:使用 -P 选项可以将设置的布尔值永久生效,系统重启后仍然有效。
1 | [root@lixiaohui ~]# getsebool httpd_enable_cgi |
调查和解决 SELinux 问题
监控 SELinux 违规
setroubleshoot-server 软件包中的 SELinux 故障排除服务提供了诊断 SELinux 问题的⼯具。当 SELinux 拒绝某⼀操作时,会在 /var/log/audit/audit.log 安全⽇志⽂件中记录⼀条
Access Vector Cache (AVC) 消息。SELinux 故障排除服务会监控 AVC 事件,并将事件摘要发送到 /var/log/messages ⽂件。
排查SELinux违规通常来说,会用到sealert,排查后,用semanage命令更正上下文即可,至于ausearch命令,用的并不多
调查SELinux问题的案例
我们先来模拟一个故障现场
搭建一个网站,然后放一个SELinux不允许加载的文件到网站根目录,用这个例子来调查问题并解决问题
1 | [root@lixiaohui ~]# cd /root |
由于httpd服务没有正常加载index.html,所以无法出席预期的字符串: hello lxh index
,这种情况下httpd用了测试页面给我们做了替代
现在这个网站无法正常工作,你可以重启服务看看,也许是服务本身异常?如果重启后还是不好使,那就得看看日志了
1 | [root@lixiaohui ~]# systemctl restart httpd |
重启后还是访问不了,那就看看日志吧
1 | [root@lixiaohui ~]# sealert -a /var/log/audit/audit.log |
好家伙,真找到了证据
SELinux is preventing /usr/sbin/httpd from getattr access on the file /lixiaohui/index.html.
而且在下面也给我们提供了可能的解决方案:
具体来说,我们需要让httpd加载的文件,具有标签
1 | If you want to allow httpd to have getattr access on the index.html file |
根据他的提示,我们来试试
1 | [root@lixiaohui ~]# semanage fcontext -a -t httpd_sys_content_t '/lixiaohui/index.html' |
问题解决,成功访问到我们的网站
第七章 管理基本存储
添加分区、文件系统和持久挂载
磁盘分区将一个硬盘驱动器划分为多个逻辑存储分区。可以根据不同的要求使用分区来划分存储,而硬盘分区的时候,又需要先给硬盘一个分区表,也就是说要决定分区的方案是什么,目前有MBR和GPT两种,而GPT更为主流
MBR 分区方案
主引导记录(MBR,Master Boot Record)是传统的硬盘分区方式之一,但它存在一些限制,特别是在面对现代存储需求时。以下是 MBR 分区的主要限制:
分区数量限制
最多支持 4 个主分区:MBR 只允许创建最多 4 个主分区。如果需要更多的分区,可以将最后一个主分区转换为扩展分区,再在扩展分区内创建逻辑分区。
逻辑分区限制:在扩展分区内最多可以创建 23 个逻辑分区,加上 3 个主分区,总共最多可以有 26 个分区。
硬盘容量限制
- 最大支持 2TB 硬盘:MBR 使用 32 位来表示分区大小和位置,因此单个分区的最大支持容量为 2TB。对于大于 2TB 的硬盘,需要使用 GUID 分区表(GPT)来管理。
分区启动限制
- 只能标记一个活动分区:MBR 只能标记一个活动分区用于引导操作系统。因此,只能从一个特定的分区引导系统。
安全性和冗余
缺乏冗余:MBR 分区表和引导代码位于硬盘的第一个扇区,如果这个扇区损坏,整个分区表和引导信息都可能丢失。
缺乏校验机制:MBR 没有内置的校验机制来验证分区表的完整性和正确性。
其他限制
不支持现代特性:MBR 不支持许多现代硬盘管理特性,如分区标签、分区 UUID 等。
兼容性问题:虽然 MBR 兼容性好,但在某些新型固态硬盘和 NVMe 驱动器上可能不再推荐使用。
综合来看,由于这些限制,MBR 已经逐渐被更先进的 GUID 分区表(GPT)所取代。GPT 没有上述限制,支持更大容量的硬盘和更多的分区,提供冗余和校验机制,是现代存储设备的首选分区方式。
GPT 分区方案
GPT(GUID Partition Table,GUID 分区表)是一种用于磁盘分区的标准,是传统 MBR(Master Boot Record,主引导记录)的现代替代方案。GPT 是 UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口)标准的一部分,提供了一种更加灵活和可靠的分区方法。以下是 GPT 的一些关键特性和优点:
GPT的关键特性
支持更大容量的磁盘:
GPT 使用 64 位地址来表示分区大小和位置,因此可以支持非常大的磁盘,最大可达 18 EB(Exabytes),远超 MBR 的 2 TB 限制。更多的分区:
GPT 不像 MBR 那样受到 4 个主分区的限制,默认情况下 GPT 支持多达 128 个分区(具体数量取决于操作系统的实现)。冗余和恢复能力:
GPT 在磁盘的开头和结尾都存储了分区表的副本,这样可以在主分区表损坏时进行恢复。校验和保护:
GPT 使用 CRC32 校验和来验证分区表的完整性,能够检测到数据损坏。唯一标识符:
每个分区都有一个全球唯一标识符(GUID),确保每个分区的唯一性和可识别性。
GPT分区表结构
GPT 分区表主要由以下几部分组成:
保护性 MBR(Protective MBR):
虽然 GPT 替代了 MBR,但仍保留一个保护性 MBR,以确保使用旧工具的系统能够识别并防止误认为磁盘未分区。主 GPT 头(Primary GPT Header):
位于磁盘的开头,包含分区表的位置和其他关键信息。分区条目阵列(Partition Entry Array):
紧随主 GPT 头,包含每个分区的详细信息,包括其 GUID、起始和结束位置等。备份 GPT 头(Backup GPT Header)和分区条目阵列:
位于磁盘的结尾,作为主 GPT 头和分区条目阵列的备份。
GPT 优点
高可靠性:通过冗余存储和校验机制,GPT 提供了更高的数据可靠性和安全性。
灵活性:支持更多和更大的分区,适用于现代大容量存储需求。
兼容性:保护性 MBR 确保旧系统能够识别 GPT 磁盘,避免误操作。
应用场景
大容量硬盘:适用于超过 2 TB 的大容量硬盘分区。
多分区需求:适用于需要多个分区的系统,如服务器和多操作系统环境。
现代固态硬盘(SSD)和 NVMe 驱动器:通常使用 GPT 分区表以充分发挥其性能和容量。
创建MBR分区
传统创建分区的命令是fdisk,在很久以前,fdisk只能划分MBR分区,而现在经过升级后,fdisk同时能划分包括MBR、GPT在内的多种分区,在我们的课程中,重点介绍了parted命令,需要注意的是parted默认是10进制,也就是说1G=1000M
fdisk 案例
先看看系统上有那些硬盘
发现有/dev/vdb和/dev/vdc、/dev/vdd是空闲的
1 | [root@lixiaohui ~]# lsblk |
划分一个主分区,进来后,输入m先看看帮助,看看怎么用
1 | [root@lixiaohui ~]# fdisk /dev/vdb |
根据提示,输入n
完成分区创建
1 | Command (m for help): n # 输入n |
这个分区类型有很多,要和我们后期格式化的格式相呼应
分区类型标识符有助于操作系统和工具正确地识别和处理分区。具体来说:
标识文件系统类型:
分区类型标识符指示分区中使用的文件系统类型。例如,类型代码83
表示 Linux 本地分区,通常用于 ext4、xfs 等文件系统。这样操作系统在挂载分区时,就能知道使用什么文件系统驱动程序来访问数据。分区管理:
帮助分区管理工具识别和管理不同类型的分区。例如,当你使用fdisk
或parted
等工具时,它们可以根据类型代码显示分区信息,并执行相应的操作。引导加载器支持:
某些分区类型与引导加载器的工作方式有关。例如,类型代码7
表示 HPFS/NTFS/exFAT 分区,用于 Windows 操作系统的引导分区。
常见分区类型代码
83
:Linux 本地分区,用于 ext2/ext3/ext4/xfs 等文件系统。82
:Linux 交换分区(swap),用于虚拟内存交换分区。7
:HPFS/NTFS/exFAT 分区,主要用于 Windows 操作系统。b
:W95 FAT32 分区,适用于较早的 FAT32 文件系统。c
:W95 FAT32(LBA)分区,支持较大硬盘的 FAT32 文件系统。8e
:Linux LVM 分区,用于逻辑卷管理(LVM)。
我们看看如何更改类型
1 | Command (m for help): t # 这是更改类型的代码 |
列出所有的分区,看看我们刚才做的分区是否符合预期
1 | Command (m for help): p # 输入p是print的意思 |
看到我们有一个1G大小的/dev/vdb1分区,且代码为83
保存并退出
1 | Command (m for help): w # 保存write |
以下是 fdisk
命令的常用选项及其简要解释:
d
:删除一个分区。m
:显示帮助菜单。n
:添加一个新的分区。p
:显示分区表。q
:退出fdisk
而不保存更改。t
:更改分区的系统 ID。w
:将分区表写入磁盘并退出。
parted 案例
parted分为交互式和非交互式两种,非交互式可用于脚本自动分区
交互式
启动 parted: 打开 parted 交互式会话:
看看帮助先
1 | [root@lixiaohui ~]# parted /dev/vdc |
1 | [root@lixiaohui ~]# parted /dev/vdc |
一般来说,下面这个命令和partprobe起到的实际作用差不多
1 | udevadm settle |
非交互式分区
先摧毁现有/dev/vdc上的所有数据,因为我们要做一个一样的分区
1 | [root@lixiaohui ~]# wipefs -a /dev/vdc |
自动分区
先设置一个分区表
1 | [root@lixiaohui ~]# parted /dev/vdc mklabel msdos |
分区
1 | [root@lixiaohui ~]# parted /dev/vdc mkpart primary ext4 2048s 1G |
查看分区结果
删除可以用下面演示的rm加分区号
1 | [root@lixiaohui ~]# parted /dev/vdc print |
创建GPT分区
GPT才是工作中的主流分区方案
fdisk 分区
先摧毁现有/dev/vdc上的所有数据,因为我们要复用这个盘
1 | [root@lixiaohui ~]# wipefs -a /dev/vdc |
1 | [root@lixiaohui ~]# fdisk /dev/vdc |
1 | [root@lixiaohui ~]# partprobe # 刷新分区表 |
parted 分区
交互式分区
先摧毁现有/dev/vdc上的所有数据,因为我们要复用这个盘
1 | [root@lixiaohui ~]# wipefs -a /dev/vdc |
1 | [root@lixiaohui ~]# parted /dev/vdc |
1 | [root@lixiaohui ~]# udevadm settle # 刷新分区表 |
非交互式分区
先摧毁现有/dev/vdc上的所有数据,因为我们要复用这个盘
1 | [root@lixiaohui ~]# wipefs -a /dev/vdc |
分配GPT分区表
1 | [root@lixiaohui ~]# parted /dev/vdc mklabel gpt |
分区并查看
1 | [root@lixiaohui ~]# parted /dev/vdc mkpart lxhpart ext4 2048s 1G |
1 | [root@lixiaohui ~]# udevadm settle # 刷新分区表 |
创建⽂件系统
分好区之后,需要格式化才能被系统正常识别和使用,格式化的过程就是赋予分区文件系统的过程
看看系统默认都支持那些格式,也就是说看看系统都支持哪些文件系统
输入mkfs.之后,快速按两次TAB键
1 | [root@lixiaohui ~]# mkfs. |
以 root ⽤⼾⾝份,使⽤ mkfs.xfs 命令为/dev/vdc1应⽤ XFS ⽂件系统
1 | [root@lixiaohui ~]# mkfs.xfs /dev/vdc1 |
验证vdc1是否有了文件系统
下面的筛选中,有TYPE=”XFS”,就说明已经经过了格式化
1 | [root@lixiaohui ~]# blkid | grep vdc1 |
临时挂载⽂件系统
添加⽂件系统后,最后⼀步是将⽂件系统挂载到⽬录上。这个目录就是挂载点,向这个挂载点写入数据,就是写到了我们的分区中
需要注意的是,mount命令挂载的效果,在umount或者重启服务器后,会解除挂载,需要手工重新挂载
将我们的/dev/vdc1挂载到/lxh
1 | [root@lixiaohui ~]# mkdir /lxh |
验证一下看看
1 | [root@lixiaohui ~]# df -h |
1 | [root@lixiaohui ~]# mount | grep vdc1 |
持久挂载⽂件系统
⼿动挂载⽂件系统是⼀种验证已格式化的设备是否可访问以及是否按预期⽅式⼯作的好⽅法。但是,当服务器重新启动时,系统不会再次⾃动挂载⽂件系统。要确保系统在启动时⾃动挂载⽂件系统,请在 /etc/fstab ⽂件中添加⼀个条⽬,系统启动期间,会自动执行这些条目来完成挂载
/etc/fstab 是⼀个以空格分隔的⽂件,每⾏具有六个字段。如果想知道每个字段的含义,可以执行man fstab命令获取,不过需要注意的是,/etc/fstab 中存在错误的条⽬可能会导致计算机⽆法启动,你可以用mount -a命令或者findmnt –verify来验证有没有语法问题
由于我们已经用临时的方式挂载好了,所以我们先临时卸载一下
1 | umount /dev/vdc1 |
将我们的vdc1持久性挂载到/lxh
现在在fstab中,推荐用uuid,而非类似于/dev/vdc1这种写法,所以我们来查一下vdc1的uuid是多少
1 | [root@lixiaohui ~]# blkid | grep vdc1 |
查到后写到fstab
注意,你要追加一行,而不要动里面原有的内容
1 | vim /etc/fstab |
各列解释
UUID:
作用:唯一标识设备。
内容:
"c00d8aa1-4f3c-4185-b2a3-21fc33e928df"
是一个唯一标识符,用于识别要挂载的设备或分区。这确保即使设备名称(如/dev/vdc1
)发生变化,系统也能正确找到并挂载设备。
挂载点:
作用:指定文件系统将被挂载到系统中的哪个位置。
内容:
/lxh
是文件系统的挂载点,表示这个设备将挂载到/lxh
目录。
文件系统类型:
作用:指定文件系统的类型。
内容:
xfs
指定了文件系统类型为 XFS,这是一个高性能的文件系统,常用于大容量存储。
挂载选项:
作用:指定文件系统挂载时使用的选项。
内容:
defaults
是一组默认挂载选项,通常包括rw
(读写)、suid
(允许设置用户 ID)、dev
(解释字符或块设备)、exec
(允许执行二进制文件)、auto
(自动挂载)、nouser
(非用户挂载)和async
(异步挂载)。
dump 选项:
作用:指定文件系统是否需要被
dump
备份。内容:
0
表示不需要备份。dump
是一个备份工具,该字段用于决定dump
是否应该备份这个文件系统。
fsck 选项:
作用:指定文件系统在启动时是否进行检查。
内容:
0
表示不需要在启动时进行文件系统检查。fsck
是一个文件系统检查和修复工具,该字段用于决定是否在系统启动时检查这个文件系统。
在 /etc/fstab ⽂件中添加或删除条⽬时,请运⾏ systemctl daemon-reload 命令或重启服务器,以确保 systemd 守护进程加载并使⽤新配置。
1 | [root@lixiaohui ~]# systemctl daemon-reload |
验证一下看看
1 | [root@lixiaohui ~]# df -h |
管理交换空间
在 Linux 系统中,交换空间(Swap Space)是用于虚拟内存的一部分,当物理内存不足时,系统可以使用交换空间临时存储不常用的数据。这样可以保证系统在内存耗尽时仍能继续运行,但由于交换空间在硬盘上,速度比物理内存要慢得多,因此经常访问交换空间可能会影响系统性能。
以下是如何使用 parted 在 /dev/vdc 上划分一个新的交换分区(第二个分区),并将其格式化为交换空间的具体步骤:
先分区出来
1 | [root@lixiaohui ~]# parted /dev/vdc print |
上一个分区结束的地方是1000M,那我们的新分区就从1000开始
成功划分一个swap空间,大小也是1000M
1 | [root@lixiaohui ~]# parted /dev/vdc mkpart swaptest linux-swap 1000M 2000M |
格式化swap分区,需要注意命令和普通分区不一样
1 | [root@lixiaohui ~]# mkswap /dev/vdc2 |
查看现有swap分区激活情况,并激活我们的swap分区
可以看到本来swap是0,激活了我们的之后,就有了数值,如果你想关闭所有的swap分区,可以用swapoff命令
1 | [root@lixiaohui ~]# free -m |
持久激活交换空间是必要的,因为swapon是临时的,重启就没了,和刚才一样,写入fstab就行
先看看uuid
1 | [root@lixiaohui ~]# blkid | grep vdc2 |
持久挂载
不要动里面原有的内容
1 | vim /etc/fstab |
不过需要注意的是,如果你有多个交换空间的话,要注意优先级,默认情况下,系统按照优先级顺序使⽤交换空间。内核使⽤最⾼优先级的交换空间,直到其填满,然后开始使⽤低优先级的交换空间。当交换空间具有相同的优先级时,内核会以轮循⽅式向其中写⼊。
要设置优先级,请在 /etc/fstab ⽂件中使⽤ pri 选项。内核会⾸先使⽤优先级最⾼的交换空间。默认优先级为 -2,数字越大,优先级越高。
以下仅为举例
1 | vim /etc/fstab |
第八章 管理存储堆栈
创建和扩展逻辑卷
逻辑卷概念
逻辑卷管理(LVM,Logical Volume Management)是 Linux 操作系统中的一种存储管理技术,它提供了比传统分区更灵活和强大的磁盘管理功能。LVM 允许你在多个物理存储设备上创建逻辑卷,并动态调整其大小。LVM 的三个基本概念是物理卷(PV,Physical Volume)、卷组(VG,Volume Group)和逻辑卷(LV,Logical Volume)。
物理卷(PV,Physical Volume)
物理卷是 LVM 的基础单元,通常是一个物理硬盘分区或者整个硬盘。每个物理卷都有一个唯一的标识符,可以加入到卷组中。物理卷是创建卷组和逻辑卷的基础。
卷组(VG,Volume Group)
卷组是由一个或多个物理卷组成的逻辑容器。卷组将多个物理存储设备组合成一个单一的逻辑存储池,提供统一的存储空间。可以在卷组上创建一个或多个逻辑卷,并动态分配和调整存储空间。
物理扩展(PE)是卷组中分配空间的基本单位。每个物理卷(PV)被分割成多个大小相等的物理扩展,这些物理扩展在卷组中进行管理和分配。当你创建或扩展逻辑卷(LV)时,实际上是分配和使用物理扩展。
逻辑卷(LV,Logical Volume)
逻辑卷是在卷组上创建的可管理单元,类似于传统的磁盘分区。逻辑卷可以像普通分区一样格式化和挂载,但它们可以动态调整大小,而不需要卸载和重新分区。逻辑卷提供了更大的灵活性,可以根据需要分配和调整存储空间。
LVM 的优点
灵活性:可以动态调整逻辑卷的大小,添加或移除物理卷,不需要重启系统。
快照:可以创建逻辑卷的快照,用于备份和恢复。
聚合存储:可以将多个物理存储设备组合成一个单一的逻辑存储池,提高存储利用率。
性能优化:支持条带化(striping)和镜像(mirroring),提高存储性能和可靠性。
逻辑卷使用的基本步骤
创建物理卷(PV):
- 使用
pvcreate
初始化物理磁盘或分区。
- 使用
创建卷组(VG):
- 使用
vgcreate
将物理卷合并到卷组中。
- 使用
查看卷组(VG)信息:
- 使用
vgdisplay
查看卷组信息。
- 使用
创建逻辑卷(LV):
- 使用
lvcreate
在卷组中创建逻辑卷。
- 使用
查看逻辑卷(LV)信息:
- 使用
lvdisplay
查看逻辑卷信息。
- 使用
格式化逻辑卷:
- 使用
mkfs
将逻辑卷格式化为所需的文件系统类型。
- 使用
挂载逻辑卷:
- 使用
mount
将逻辑卷挂载到文件系统。
- 使用
更新
/etc/fstab
文件:- 将逻辑卷添加到
/etc/fstab
文件中,实现自动挂载。
- 将逻辑卷添加到
扩展逻辑卷(可选):
- 使用
lvextend
扩展逻辑卷,然后扩展文件系统。
- 使用
扩展卷组(VG):
- 使用 vgextend 将新的物理卷加入到已有的卷组中。
准备物理设备
如果你用的是红帽的培训环境,可以在foundation上,执行一下命令,重置servera,确保servera上的硬盘都是空闲,等servera起来后,用ssh的方式登录即可
1 | [root@foundation0 ~]# rht-vmctl fullreset servera -q |
确认硬盘的空闲情况
没有任何分区的了,都是空闲的
1 | [root@lixiaohui ~]# lsblk |
创建物理卷(PV)
实际上,绝大部分的时候,我们的每一个硬盘都是一个PV,很少情况下才需要分区,然后把分区转化成PV
这里我们用vdb来创建一个pv
1 | [root@lixiaohui ~]# pvcreate /dev/vdb |
实际上,如果是整个硬盘用于pv,pv不需要手工创建,在创建vg的时候,会自动创建出pv
创建后也可以用pvs显示缩略信息
创建卷组(VG)
用vdb创建了一个名为lxhvg的VG,并使其默认一次性分配的空间为10M,也就是说物理块(PE)为10M,它默认是4M,如果你没有特别的要求,就忽略-s 10M这个参数,我这里只是用于告诉你有这个参数可以指定一次对外分配的空间数值
1 | [root@lixiaohui ~]# vgcreate lxhvg /dev/vdb -s 10M |
看卷组(VG)信息
也可以用vgs显示缩略信息
1 | [root@lixiaohui ~]# vgdisplay lxhvg |
卷组(VG)信息解析
VG Name:卷组名称,为
lxhvg
。System ID:系统 ID,未指定。
Format:卷组的格式,为
lvm2
。Metadata Areas:元数据区域数量,为 1。
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:当前物理卷数量,为 1。
Act PV:当前活动的物理卷数量,为 1。
VG Size:卷组大小,为 4.99 GiB。
PE Size:物理扩展(PE)的大小,为 10.00 MiB。
Total PE:总物理扩展数量,为 511。
Alloc PE / Size:已分配的物理扩展数量/大小,为 0 / 0。
Free PE / Size:未分配的物理扩展数量/大小,为 511 / 4.99 GiB。
VG UUID:卷组的唯一标识符,为
gej7fh-BtpP-vzfM-ULI9-FwmW-uWX1-fdt7qS
。
创建逻辑卷(LV)
-L 100M:指定逻辑卷的大小为 100MB。
-l 100:指定逻辑卷使用 100 个物理扩展(PE)。
1 | [root@lixiaohui ~]# lvcreate -n lxhlv -L 100M lxhvg |
查看逻辑卷(LV)信息
1 | [root@lixiaohui ~]# lvs |
逻辑卷(LV)信息解析
LV Path:逻辑卷路径,为
/dev/lxhvg/lxhlv-1
。LV Name:逻辑卷名称,为
lxhlv-1
。VG Name:卷组名称,为
lxhvg
。LV UUID:逻辑卷的唯一标识符,为
ERrb2W-LOvq-mgrl-l37l-wF7w-8X03-bn7aCT
。LV Write Access:逻辑卷的写入权限,为读写(read/write)。
LV Creation host, time:逻辑卷创建主机和时间,为
lixiaohui
,创建时间为2024-12-24 02:14:42 -0500
。LV Status:逻辑卷状态,为可用(available)。
# open:当前打开的次数,为 0。
LV Size:逻辑卷大小,为
1000.00 MiB
。Current LE:当前逻辑扩展(LE)数量,为 100。
Segments:段数量,为 1。
Allocation:分配策略,为继承(inherit)。
Read ahead sectors:预读扇区数,为自动(auto)。
Block device:块设备编号,为
253:1
。
格式化逻辑卷
1 | [root@lixiaohui ~]# mkfs.xfs /dev/lxhvg/lxhlv |
挂载逻辑卷
1 | [root@lixiaohui ~]# blkid | grep lxhlv |
挂到/mnt去
临时挂载
1 | [root@lixiaohui ~]# mount /dev/lxhvg/lxhlv /mnt |
永久挂载
1 | [root@lixiaohui ~]# vim /etc/fstab |
看看挂载成功没
1 | [root@lixiaohui ~]# df -h |
扩展卷组
新买了硬盘后,可以把硬盘加入到卷组中,以便于lv可以申请更大的空间
1 | [root@lixiaohui ~]# vgextend lxhvg /dev/vdc |
扩展逻辑卷
给lxhlv这个逻辑卷扩容1G过来
1 | [root@lixiaohui ~]# lvextend /dev/lxhvg/lxhlv -L +1G |
接着我们就发现有点不对劲,怎么lv扩大了之后,文件系统没有扩大,还是只有100M可用?
1 | [root@lixiaohui ~]# df -h |
这是因为扩容要分两步走,第一步是扩容lv,第二步是扩容文件系统,不同的文件系统扩容命令不同
- extX格式的
1 | resize2fs /dev/lxhvg/lxhlv |
- xfs格式的
1 | xfs_growfs /mnt |
这个太麻烦了,要想不麻烦,在扩容lv的时候加一个-r参数,我们再加1G
一步就搞定了lv大小和文件系统大小
1 | [root@lixiaohui ~]# lvextend /dev/lxhvg/lxhlv -L +1G -r |
缩容卷组VG
把pv从卷组中移出去之前,需要用下面的命令将卷组的数据,移动到别的pv去
1 | [root@lixiaohui ~]# pvmove /dev/vdb |
将pv从卷组中移走
1 | [root@lixiaohui ~]# vgreduce lxhvg /dev/vdb |
删除逻辑卷LV
别忘了从fstab去掉
1 | [root@lixiaohui ~]# umount /mnt |
删除卷组
1 | [root@lixiaohui ~]# vgremove lxhvg |
删除物理卷PV
1 | [root@lixiaohui ~]# pvremove /dev/vdb |
Stratis 存储管理
Stratis ⽬前作为技术预览提供
Stratis 利⽤精简配置的概念,从磁盘设备共享池构建⽂件系统。Stratis 不会在您创建⽂件系统时⽴即为其分配物理存储空间,⽽是在⽂件系统存储更多数据时动态地从池中分配该空间。因此,⽂件系统的⼤⼩可能会显⽰为 1 TiB,但从池中分配给它的实际存储空间可能仅有 100 GiB。
安装和启⽤ Stratis
1 | [root@lixiaohui ~]# dnf install stratis-cli stratisd -y |
创建 Stratis 池
1 | [root@lixiaohui ~]# stratis pool create pool1 /dev/vdb |
扩容 Stratis 池
1 | [root@lixiaohui ~]# stratis pool list |
创建 Stratis ⽂件系统
使⽤ stratis filesystem create 命令从池中创建⽂件系统。Stratis ⽂件系统的链接位于 /dev/stratis/pool1 ⽬录中
1 | [root@lixiaohui ~]# stratis filesystem create pool1 fs1 |
临时挂载使用 Stratis ⽂件系统
发现默认1TB,我发现在新版本中,这个1TB的默认值在创建文件系统的时候也可以改,比如改成100TB
1 | [root@lixiaohui ~]# df -h | grep mnt |
写点东西进去
1 | [root@lixiaohui ~]# touch /mnt/file{1..10} |
永久挂载 Stratis ⽂件系统
这个fstab要注意defaults后面的参数,x-systemd.requires=stratisd.service
,如果未在 /etc/fstab ⽂件中为每个 Stratis ⽂件系统包含 x-systemd.requires=stratisd.service 挂载选项,则计算机将⽆法正常启动
看着长,其实不要紧,用这个方法可以查到man systemd.mount
1 | vim /etc/fstab |
创建 Stratis ⽂件系统快照
这个快照是独立于源文件系统的,你可以看成独立的文件系统,所以可以看成备份
1 | [root@lixiaohui ~]# stratis filesystem snapshot pool1 fs1 snapshot1 |
恢复 Stratis ⽂件系统
假设数据丢了,可以把快照挂过来复制数据
1 | [root@lixiaohui ~]# mount /dev/stratis/pool1/snapshot1 /opt |
第九章 访问⽹络附加存储
通过 NFS 管理⽹络附加存储
网络文件系统(NFS)是一种允许不同计算机系统在网络上共享文件和目录的协议。NFS 最初由 Sun Microsystems 开发,现已成为 Unix 和类 Unix 系统(如 Linux)的标准文件系统共享方法。通过 NFS,共享的文件和目录可以像本地磁盘一样在远程计算机上进行访问。
NFS 的主要特点
跨网络共享文件:
NFS 允许在网络中的不同计算机之间共享文件和目录,实现数据的集中存储和管理。透明访问:
用户可以像访问本地文件一样访问远程文件,无需了解底层网络细节。权限管理:
通过文件权限和访问控制列表(ACL),可以对 NFS 共享进行细粒度的访问控制。兼容性强:
支持多种操作系统,包括 Unix、Linux 和 Windows,使得异构系统之间的数据共享变得容易。
NFS 共享的典型应用场景
家庭网络:
在家庭网络中,NFS 可用于共享多媒体文件、文档和备份。企业环境:
在企业环境中,NFS 用于集中存储和管理用户的文件,提高数据的可用性和安全性。开发和测试环境:
开发团队可以使用 NFS 共享项目文件,方便协同工作和版本控制。
安装NFS服务器
服务器端这部分不属于课程内容
不管是服务器还是客户端,都必须安装nfs-utils
1 | [root@lixiaohui ~]# dnf install nfs-utils -y |
准备资源
1 | [root@lixiaohui ~]# mkdir /nfs |
将资源以读写方法共享给所有人
1 | [root@lixiaohui ~]# vim /etc/exports.d/mynfs.exports |
启动NFS服务
1 | [root@lixiaohui ~]# systemctl enable nfs-server.service --now |
开通相应的防火墙规则
1 | [root@lixiaohui ~]# firewall-cmd --add-service=nfs --add-service=rpc-bind --add-service=mountd --permanent |
管理NFS客户端
不管是服务器还是客户端,都必须安装nfs-utils
1 | [root@lixiaohui ~]# dnf install nfs-utils -y |
检查服务器给我们共享了什么
在nfsv3协议中,需要用showmount -e SERVER的格式看
在nfsv4协议中,用showmount -e SERVER的格式查看的时候,不会有任何返回,你直接mount它的根到本地ls看就行
此处假设我们的服务器名为servera
1 | [root@serverb ~]# showmount -e servera |
将服务器的内容,挂载到我们的/mnt上
1 | [root@serverb ~]# mount servera:/nfs /mnt |
永久挂载
1 | [root@serverb ~]# vim /etc/fstab |
⾃动挂载⽹络附加存储
autofs 基本概念
autofs
是一种动态管理挂载文件系统的工具,通过配置文件自动挂载和卸载文件系统。autofs
根据访问需求挂载文件系统,并在不再使用时自动卸载,从而提高系统性能和资源利用率。
autofs
的主要特点
按需挂载:只有在需要访问时才挂载文件系统,不占用资源。
自动卸载:在文件系统不使用时自动卸载,释放资源。
配置灵活:支持通过多个配置文件和映射文件来管理不同的挂载点。
兼容性强:支持 NFS、CIFS(SMB)、本地文件系统等多种文件系统类型。
autofs
的工作流程
安装和配置:通过安装
autofs
软件包并配置主自动挂载文件和映射文件来启用自动挂载功能。触发挂载:当访问配置的挂载点时,
autofs
自动挂载相应的文件系统。自动卸载:在挂载点一段时间不被访问时,
autofs
自动卸载文件系统。
使用 autofs
与配置 /etc/fstab
的比较
特性 | autofs | /etc/fstab |
---|---|---|
挂载方式 | 按需挂载,访问时自动挂载 | 开机时自动挂载 |
卸载方式 | 不使用时自动卸载,释放资源 | 需要手动卸载,始终占用资源 |
配置文件 | /etc/auto.master 和映射文件 | /etc/fstab |
性能 | 提高性能和资源利用率 | 可能占用不必要的系统资源 |
复杂度 | 配置较复杂,但更灵活 | 配置较简单,适用于固定挂载需求 |
适用场景 | 动态挂载需求,如频繁访问的网络存储 | 固定挂载需求,如系统启动时的必要挂载 |
选择使用场景
autofs
:适用于动态挂载需求,特别是访问频率不高或需要提高系统性能和资源利用率的场景。
/etc/fstab
:适用于固定挂载需求,如系统启动时必须挂载的文件系统。
安装autofs
autofs作为客户端这一边的自动挂载器,需要安装才能使用,我们把serverb当作客户端,因为我们刚才的servera安装了nfs服务器
1 | [root@serverb ~]# dnf install autofs -y |
主配置文件是:/etc/auto.master
辅助配置文件可以是:/etc/auto.master.d/xxx.autofs
直接挂载和间接挂载
在自动挂载文件系统时,autofs
提供了直接挂载和间接挂载两种方式。以下是这两种挂载方式的详细描述:
直接挂载与间接挂载的对比
特性 | 直接挂载(Direct Mounts) | 间接挂载(Indirect Mounts) |
---|---|---|
配置路径 | 在 /etc/auto.master 中使用 /- 前缀 | 在 /etc/auto.master 中使用目录前缀 |
挂载点 | 固定路径,访问时挂载到指定路径 | 位于目录下的子目录,管理多个挂载点 |
适用场景 | 需要精确控制挂载位置时 | 管理多个挂载点,提供灵活性和简化配置 |
配置示例 | /mnt/nfs_share /etc/auto.direct | /mnt /etc/auto.indirect |
直接挂载(Direct Mounts)
直接挂载是指在自动挂载配置中,挂载点路径是固定的,访问时自动挂载到指定的路径。直接挂载通常用于需要精确控制挂载位置的场景。
直接挂载的配置示例
在 /etc/auto.master
中配置直接挂载:
1 | [root@serverb ~]# vim /etc/auto.master |
在 /etc/auto.direct
文件中定义具体的挂载点和挂载参数,规则文件内容如下:
这种规则如果不会写,可以参考/etc/auto.misc文件格式
1 | [root@serverb ~]# vim /etc/auto.direct |
重启服务
1 | [root@serverb ~]# systemctl restart autofs |
切入到目录时,自动完成了挂载
1 | [root@serverb ~]# cd /mnt/nfs_share/ |
间接挂载(Indirect Mounts)
间接挂载是指在自动挂载配置中,挂载点是一个目录,而实际的挂载点位于这个目录下的子目录中。间接挂载通常用于管理多个挂载点,提供更灵活的管理方式。
间接挂载的配置示例
我们希望,当我们进入到/opt/abc的时候,自动将servera的共享挂过来
在 /etc/auto.master
中配置间接挂载:
1 | [root@serverb ~]# vim /etc/auto.master |
规则文件内容如下:
这种规则如果不会写,可以参考/etc/auto.misc文件格式
1 | [root@serverb ~]# vim /etc/auto.indirect |
重启服务
1 | [root@serverb ~]# systemctl restart autofs |
切入到/opt/abc时,自动挂载
1 | [root@serverb nfs_share]# cd /opt/abc |
通配符挂载
在间接挂载中,可以用通配符来表示将来用户要切换的具体目录,并同时挂载服务器上和用户需求同名的目录挂载到用户需求的目录上
我们先在servera上准备一下,创建几个目录
1 | [root@lixiaohui ~]# mkdir /nfs/lixiaohui |
我们希望在客户端serverb上,当用户切换到/opt/lixiaohui的时候,自动将servera的/nfs/lixiaohui挂载到/opt/lixiaohui,当用户切换到/opt/zhangsan的时候,自动将servera的/nfs/zhangsan挂载到/opt/zhangsan
当然,你可能认为,这就是创建两条条目的问题,但是不能这么想,假设这是20000条呢,维护麻烦,所以规则文件要写成以下模样:
1 | [root@serverb abc]# vim /etc/auto.indirect |
重启服务
1 | [root@serverb ~]# systemctl restart autofs |
切入到/opt/zhangsan或lixiaohui时,自动挂载
非常的智能化,不再需要维护太多的条目
1 | [root@serverb abc]# cd /opt/lixiaohui |
systemd自动挂载
在 Linux 系统中,systemd 可以通过在 /etc/fstab 文件中添加 x-systemd.automount 选项来自动创建和管理挂载点的单元文件。单元文件的名称规则基于挂载点路径。这种方式可以简化挂载配置,并且只在需要访问时挂载,提高系统性能和资源利用率。
systemd.automount 单元仅可⽀持绝对路径挂载点,类似于 autofs 直接映射
编辑 /etc/fstab 文件: 在 /etc/fstab 文件中添加或修改挂载条目,加入 x-systemd.automount 选项。
1 | [root@serverb ~]# vim /etc/fstab |
加载配置
1 | [root@serverb ~]# systemctl daemon-reload |
测试效果
看看是否创建了基于挂载点名称的服务,并启动
1 | [root@serverb ~]# systemctl cat tmp.automount |
1 | [root@serverb ~]# systemctl start tmp.automount |
文件都在了
1 | [root@serverb ~]# ls /tmp/ |
1 | [root@serverb ~]# df | grep /tmp |
第十章 控制启动过程
选择启动⽬标
红帽企业 Linux 9 的启动过程
接通电源:
- 系统固件(现代 UEFI 或 BIOS)运行开机自检 (POST),并初始化硬件。
配置 BIOS 或 UEFI:
- 启动过程早期可以按特定组合键(例如 F2)配置系统 BIOS 或 UEFI。
UEFI 启动固件:
- 通过搜索或配置磁盘上的主启动记录 (MBR) 来找到可启动设备。
读取启动加载器:
- 系统固件从磁盘读取启动加载器,并将控制权交给启动加载器。在 RHEL 9 系统中,启动加载器为 GRUB2。
安装 GRUB2:
grub2-install
命令用于安装 GRUB2 作为 BIOS 系统的启动加载器。不要直接使用grub2-install
安装 UEFI 启动加载器,RHEL 9 提供了包含必要签名的预构建文件/boot/efi/EFI/redhat/grubx64.efi
。
加载 GRUB2 配置:
- GRUB2 从
/boot/grub2/grub.cfg
文件 (BIOS) 或/boot/efi/EFI/redhat/grub.cfg
文件 (UEFI) 加载配置,并显示菜单以选择要启动的内核。
- GRUB2 从
GRUB2 配置:
- 使用
/etc/grub.d/
目录和/etc/default/grub
文件进行配置,通过grub2-mkconfig
命令生成配置文件。
- 使用
加载内核和 initramfs:
- 选择内核或超时后,启动加载器从磁盘加载内核和 initramfs 并放入内存。initramfs 镜像包含启动所需的内核模块和初始化脚本。
配置 initramfs:
- 使用
/etc/dracut.conf.d/
目录、dracut
命令和lsinitrd
命令配置和检查 initramfs 文件。
- 使用
控制权交给内核:
- 启动加载器将控制权交给内核,并传递命令行选项和 initramfs 镜像位置。
执行 initramfs 中的 init 脚本:
- 内核初始化硬件后,从 initramfs 镜像执行
/sbin/init
脚本。在 RHEL 9 中,该脚本是指向 systemd 的链接。
- 内核初始化硬件后,从 initramfs 镜像执行
执行 systemd 单元:
- initramfs 中的 systemd 单元执行
initrd.target
目标的所有单元,包括将根文件系统挂载到/sysroot
。
- initramfs 中的 systemd 单元执行
配置 root 文件系统:
- 使用
/etc/fstab
文件进行配置。
- 使用
切换根文件系统:
- 内核将根文件系统切换到
/sysroot
目录中的根文件系统,systemd 单元重新执行自身。
- 内核将根文件系统切换到
启动目标单元:
- systemd 查找默认目标并启动或停止单元以符合目标配置,自动解决依赖关系。
配置 systemd:
- 使用
/etc/systemd/system/default.target
文件和/etc/systemd/system/
目录进行配置。
- 使用
关机或重启
systemctl poweroff 命令会停止所有运行的服务,卸载所有文件系统(或者在文件系统无法卸载时以只读形式将其重新挂载),然后关闭系统。
systemctl reboot 命令会停止所有运行的服务,卸载所有文件系统,然后重新启动系统。
systemd
目标是一组系统必须启动以达到预期状态的 systemd
单元。下表列出了最重要的目标:
目标 | 用途 |
---|---|
graphical.target | 该目标支持多用户,并提供基于图形和基于文本的登录。 |
multi-user.target | 该目标支持多用户,并仅提供基于文本的登录。 |
rescue.target | 该目标提供了一个单用户系统,以支持修复您的系统。 |
emergency.target | 当 rescue.target 单元无法启动时,该目标将启动最小的系统以修复您的系统。 |
除了这些还有一些,可以用下面的方法查看
1 | [root@lixiaohui ~]# systemctl list-units --type target |
设置默认目标
系统启动时,systemd 单元会激活 default.target 目标。通常,/etc/systemd/system/ 目录中的默认目标是指向 graphical.target 或 multi-user.target 目标的符号链接。
查询系统下次启动时的target是哪个
1 | [root@lixiaohui ~]# systemctl get-default |
将默认目标改一下
1 | [root@lixiaohui ~]# systemctl set-default graphical.target |
不过以上的更改来说,需要提供已经能启动的情况下才能有效,如果已经起不来了,或者在启动时需要进入特定的target,就需要按照下面的步骤来
启动或重新启动系统。
按任意键(Enter 除外,它用于执行正常启动)中断启动加载器菜单倒计时。
将光标移至要启动的内核条目。
按 e 编辑当前条目。
将光标移到以
linux
开头的行,这是内核命令行。附加
systemd.unit=xx.target
,例如systemd.unit=emergency.target
。按 Ctrl+x 使用这些更改进行启动。
重置 root 密码
忘了密码这种事,想都可以想到,尤其是有些时候,也没人给我们交接密码,我们就得按照以下步骤尝试重置root口令
从红帽企业 Linux 9 开始,如果从 DVD 安装系统,则默认的内核在尝试进入维护模式时会要求输入 root
密码。因此,如需重置丢失的 root
密码,必须使用救援内核。
按照以下步骤操作重置密码:
重新启动系统。
按任意键(Enter 除外)中断启动加载器倒计时。
将光标移到要启动的救援内核条目(名称中带有 rescue 一词的条目)。
按 e 编辑选定的条目。
将光标移到内核命令行(以
linux
开头的行)。附加
rd.break console=tty0
。利用该选项,就在系统从initramfs
镜像向实际系统移交控制权前,系统将会中断。按 Ctrl+x 使用这些更改来启动。如果无法正常看到shell提示符,请在上一步去掉
console=tty0
再重试提示时,按 Enter 执行维护。
以读写方式重新挂载/sysroot,因为硬盘被只读挂在这里
1 | mount -o remount,rw /sysroot |
- chroot切换根目录到硬盘中
1 | chroot /sysroot |
- 设置新
root
密码
1 | passwd root |
- 重新标记SELinux
1 | touch /.autorelabel |
- 多次exit使得服务器正常启动,在启动中,你将看到SELinux重新标记,并自动重启
第一个exit将退出 chroot 存放位置,第二个exit将退出 initramfs 调试 shell。
1 | exit |
修复在启动时出现的⽂件系统问题
常见文件系统挂载问题
文件系统损坏:
描述:文件系统损坏可能导致无法挂载。
处理:
systemd
服务会尝试修复文件系统。如果问题无法自动修复,系统会打开紧急 shell。
设备/UUID 不存在:
描述:指定的设备或 UUID 在启动时未检测到或不存在。
处理:
systemd
服务在等待设备变为可用时超时。如果设备不响应,系统会打开紧急 shell。
故障处理
紧急 shell:
当systemd
无法自动解决挂载问题时,系统会进入紧急 shell 模式,用户需要输入 root 用户密码进行手动故障排除和修复。检查
/etc/fstab
配置:
确保/etc/fstab
文件中的条目和语法正确,设备或 UUID 配置准确。修复文件系统:
在紧急 shell 中使用工具(如fsck
)手动检查和修复文件系统。
具体来说,你需要掌握主动进入紧急shell的能力,这用的是上一个小节的内容,在Linux后追加emgergency.target
第十一章 管理⽹络安全
管理服务器防⽕墙
在红帽企业 Linux 9 中,nftables 框架是系统防⽕墙核⼼,取代了已弃⽤的 iptables 框架。
firewalld 服务
firewalld 服务是⼀种动态防⽕墙管理器,也是 nftables 框架的推荐前端。firewalld 服务将所有⽹络流量分为多个区域,从⽽简化防⽕墙管理。通常⽽⾔,如果流量不与允许的端⼝和协议或服务匹配,则流量会被拒绝。trusted 区域默认情况下允许所有流量,它是⼀个例外。
列出所有的区域
以下我删除了规则,只保留了名称,可以看成,我们的public处于活动状态,意思是public中的规则正在影响我们的流量
1 | [root@lixiaohui ~]# firewall-cmd --list-all-zones |
列出特定区域中的规则
那我们就看看public里面有什么
可以看到public区域中,关联了eth0这个网卡,并允许了一些常规服务,比如ssh什么的,而且public这个默认区域不需要指定–zone参数,而且后期服务区新增的网卡,默认也会加到public区域中
1 | [root@lixiaohui ~]# firewall-cmd --list-all --zone=public |
配置 firewalld
配置防火墙有以下几种办法
安装firewall-config图形化,并用图形化配置
启用cockpit,用cockpit网页版配置
用命令行配置,这是最推荐的方法
不管你用哪种方法,一定要记得把规则放入到permanent模式中,runtime模式中的规则,重新加载规则或重启服务器后,会失效
运行时模式(runtime)
定义:运行时模式中的规则只在当前会话有效,重新加载规则或重启系统后这些规则会失效。
应用场景:适用于临时测试或短期需要的规则,方便在不影响永久配置的情况下进行临时调整。
案例:
允许http流量和2000/tcp端口通过
1 | [root@lixiaohui ~]# firewall-cmd --add-service=http |
你去测试会发现马上就生效了,我们来列出防火墙规则看看
1 | [root@lixiaohui ~]# firewall-cmd --list-all |
重新加载一下规则看看
刚才配置的规则已丢失
1 | [root@lixiaohui ~]# firewall-cmd --reload |
永久模式(permanent)
定义:永久模式中的规则会被保存在配置文件中,即使系统重新启动或 firewalld 服务重新加载后,这些规则仍然存在。
应用场景:适用于需要长期生效的规则,确保在重启或重新加载服务后仍然有效。
案例:
允许http流量和2000/tcp端口通过
我们注意到,每条命令后面都有一个--permanent
1 | [root@lixiaohui ~]# firewall-cmd --add-service=http --permanent |
重新加载规则后,我们配置的规则还在,说明是持久性的
1 | [root@lixiaohui ~]# firewall-cmd --reload |
以上两条持久性规则,想要删除,只需要把add换成remove即可
1 | [root@lixiaohui ~]# firewall-cmd --remove-service=http --permanent |
控制 SELinux 端⼝标记
除了⽂件上下⽂和进程类型标记外,SELinux 还使⽤ SELinux 上下⽂来标记⽹络端⼝。SELinux 通过标记⽹络端⼝并将规则包含在服务的⽬标策略中来控制⽹络访问。当⽬标进程尝试打开端⼝进⾏侦听时,SELinux 会验证策略是否包含⽀持该进程与上下⽂绑定的条⽬。然后,SElinux 可以阻⽌恶意服务控制本应由其他合法⽹络服务使⽤的端⼝。
列出特定的端口标记
在-l后面用grep筛选即可,不筛选,默认输出所有selinux运行的标签和端口绑定列表
1 | [root@lixiaohui ~]# semanage port -l | grep http |
如果需要修改标签和端口的绑定关系,以下是语法
1 | semanage port -a -t port_label -p tcp|udp PORTNUMBER |
删除语法:
1 | semanage port -d -t port_label -p tcp|udp PORTNUMBER |
修改语法:
1 | semanage port -m -t port_label -p tcp|udp PORTNUMBER |
我们来做一个案例
安装一个httpd网站服务,然后修改网站服务配置文件端口,从80改成20000,然后解决SELinux允许httpd服务加载20000的问题
1 | [root@lixiaohui ~]# dnf install httpd -y |
将监听端口改为20000
1 | [root@lixiaohui ~]# sed -i 's/Listen 80/Listen 20000/' /etc/httpd/conf/httpd.conf |
启动服务看看
发现不管怎么重启,都起不来了
1 | [root@lixiaohui ~]# systemctl enable httpd --now |
根据提示,看看错在哪里
1 | [root@lixiaohui ~]# systemctl status httpd.service -l |
清晰的看到无法绑定到20000端口才失败的
那我们看看都运行绑定哪些端口
明显没有看到20000
1 | [root@lixiaohui ~]# semanage port -l | grep http |
看看selinux告警怎么说
真是个好心人,连命令都告诉我们了
1 | [root@lixiaohui ~]# sealert -a /var/log/audit/audit.log |
添加一下20000端口的运行策略
1 | [root@lixiaohui ~]# semanage port -a -t http_port_t -p tcp 20000 |
这回能看到20000了,重启服务看看
1 | [root@lixiaohui ~]# systemctl restart httpd |
一切都好起来了,服务成功启动
第十二章 安装红帽企业 Linux
本章另见PXE部署指南
不再赘述
第十三章 运行容器
容器简介
容器技术是一种轻量级虚拟化方法,通过在共享操作系统内核的基础上,将应用及其依赖项封装在独立的环境中运行。它提供了高度的可移植性和一致性,使应用能够在不同的计算环境之间无缝转移。常见的容器技术包括 Docker 和 podman等。
容器会使⽤ Linux 内核功能,如 namespaces、控制组(cgroups)、SELinux 和安全计算模式(seccomp)
容器与虚拟机对⽐
容器的作⽤通常与 虚拟机(VM)类似,在虚拟机中,应⽤驻留在独⽴的环境中,并通过虚拟化⽹络进⾏通信。虽然该⽤例乍⼀看是⼀样的,但容器的占⽤空间更⼩,启动和停⽌⽐虚拟机更快。在内存和磁盘使⽤量⽅⾯,虚拟机通常以 GB 为单位,⽽容器以 MB 为单位。
虚拟机 vs. 容器
方面 | 虚拟机 | 容器 |
---|---|---|
计算机功能 | Hypervisor(虚拟机监控器) | 容器引擎 |
管理 | 虚拟机管理界面 | 容器引擎或编排软件 |
虚拟化级别 | 完全虚拟化环境 | 仅相关部分 |
体积 | 以GB为单位 | 以MB字节为单位 |
可移植性 | 通常只在同一虚拟机监控器上 | 任何符合 OCI 标准的引擎 |
比较说明
虚拟机提供一个完整的虚拟化环境,包括完整的操作系统,由虚拟机监控器管理。这使得它们更重,通常以GB为单位,并且它们的可移植性常局限于同一个虚拟机监控器环境。
另一方面,容器只虚拟化运行应用所需的必要组件,使其更加轻量化和高效,通常以MB为单位。容器由容器引擎或编排软件管理,提供更高的移植性,因为它们可以在任何符合 OCI 标准的引擎上运行。
Podman 简介
Podman 是⼀个开源⼯具,可⽤于在本地管理容器。借助 Podman,可以查找、运⾏、构建或部署 OCI(开放容器计划)容器和容器镜像。Podman 默认⽆守护进程。其他⼀些容器⼯具使⽤守护进程来代理请求,由此带来了单点故障。此外,守护进程可能需要提升特权,这就存在安全问题。Podman 直接与容器、镜像和镜像仓库交互,⽆需守护进程。
安装容器管理工具
这个安装过程可能较长,请等待
1 | [root@lixiaohui ~]# dnf install container-tools -y |
看看安装的版本,如果能出现版本,就是安装好了
1 | [root@lixiaohui ~]# podman -v |
容器镜像与仓库
容器镜像(Container Image)是一个轻量级、独立的可执行软件包,其中包含了运行应用程序所需的一切,包括代码、运行时、库和配置文件。它是创建和部署容器的基础。容器镜像包含应⽤的打包版本,以及运⾏应⽤所需的所有依赖项。镜像可以脱离容器存在,但容器必须依赖镜像存在,因为容器需使⽤容器镜像来构建执⾏应⽤的运⾏时环境。
容器镜像的特点
自包含性:
- 容器镜像包含了应用程序及其所有依赖项,确保在任何环境中都可以一致地运行。
层次结构:
- 容器镜像由多个只读层组成,每一层都基于前一层。修改镜像时,会创建一个新的层,并将更改保存到该层。这种设计提高了存储和传输效率。
可移植性:
- 容器镜像可以在不同的操作系统和云平台之间无缝迁移,因为它们包含了运行应用所需的一切。
版本控制:
- 通过镜像标签(tags)和唯一标识符(SHA256 哈希值),可以对镜像进行版本管理,确保可以回滚到之前的版本。
轻量级:
- 容器镜像相比虚拟机镜像更加轻量,因为它们共享操作系统内核,并且只包含运行应用所需的最小依赖项。
容器镜像的命名规范
容器镜像的名称通常由三个部分组成:仓库名、镜像名 和 标签,案例如下:
1 | registry.lab.example.com/ubi9/ubi |
容器镜像仓库
容器镜像仓库(Container Registry)是用于存储和分发容器镜像的中央存储库。它允许开发者将容器镜像上传、管理和分享,使得在不同环境之间部署应用变得更加方便和一致。
常见的容器镜像仓库
Docker Hub:
- 官方的公共容器镜像仓库,提供免费的公共镜像存储和付费的私有镜像存储。
Harbor:
- 一个开源的企业级容器镜像仓库,提供高级的安全性和管理功能。
Quay:
- 一个开源的企业级容器镜像仓库,提供高级的安全性和管理功能,课程中已内置,这个仓库是RedHat的一部分。
redhat:
管理podman软件的容器镜像仓库
容器注册表的默认配置文件是 /etc/containers/registries.conf
文件,如果 $HOME/.config/containers
目录中也有一个registries.conf
,参数就以家目录里的为准
1 | [root@lixiaohui ~]# grep -v ^# /etc/containers/registries.conf |
unqualified-search-registries
这里定义了从哪里下载镜像,你可以把你的私有仓库按照格式写进去
课程中的仓库地址为:registry.lab.example.com
,所以我写一个案例
1 | [root@lixiaohui ~]# grep -v ^# /etc/containers/registries.conf |
我不止添加了域名,还添加了insecure = true
来解决https不受信任的问题
以下是写在自己家目录中的一个样例:
1 | mkdir -p /home/contsvc/.config/containers |
登陆一下仓库看看
账号:admin
密码: redhat321
1 | [root@lixiaohui ~]# podman login registry.lab.example.com --tls-verify=false |
搜索一下仓库看看都有哪些镜像
1 | [root@lixiaohui ~]# podman search registry.lab.example.com/ --tls-verify=false |
从仓库下载一个看看
1 | [root@lixiaohui ~]# podman pull registry.lab.example.com/rhel9/httpd-24 --tls-verify=false |
看看本地已经下载好的镜像
1 | [root@lixiaohui ~]# podman images |
看看本地的容器镜像都有哪些元数据信息可以给我们看
1 | [root@lixiaohui ~]# podman inspect registry.lab.example.com/rhel9/httpd-24:latest | more |
使⽤ Skopeo 管理镜像仓库
Skopeo 可以在不使⽤本地存储的情况下检查远程镜像或在镜像仓库之间传输镜像。
比如不下载的情况下,看看远程镜像的信息
1 | [root@lixiaohui ~]# skopeo inspect docker://registry.lab.example.com/rhel9/php-82 --tls-verify=false |
使⽤ skopeo copy 命令在镜像仓库之间复制镜像
1 | [root@lixiaohui ~]# skopeo copy docker://registry.lab.example.com/rhel9/php-82 docker://registry.lab.example.com/rhel9/lixiaohui --tls-verify=false |
创建一个容器
我们运行一个mariadb的数据库容器看看
先下载一下镜像
1 | [root@lixiaohui ~]# podman pull registry.lab.example.com/rhel9/mariadb-105 --tls-verify=false |
然后来创建一个名为lxhdb的容器看看
1 | podman run -d \ |
参数解释
-d
:解释:以守护进程模式运行容器。
作用:使容器在后台运行,而不占用当前终端会话。
-p 3306:3306
:解释:将主机的3306端口映射到容器的3306端口。
作用:允许外部访问容器内的MySQL服务,3306端口是MySQL的默认端口。
-v /mnt:/var/lib/mysql:Z
:解释:将主机的
/mnt
目录挂载到容器的/var/lib/mysql
目录,并设置SELinux安全上下文选项:Z
。作用:持久化MySQL的数据存储到主机的
/mnt
目录中,即使容器被删除,数据也不会丢失。Z
选项确保SELinux为挂载的卷设置正确的安全上下文,以允许容器访问该卷。
-e MYSQL_ROOT_PASSWORD=ABCabc123
:解释:设置环境变量
MYSQL_ROOT_PASSWORD
,指定MySQL root用户的密码。作用:为MySQL的root用户配置初始密码,确保数据库的安全性。
registry.lab.example.com/rhel9/mariadb-105
:解释:指定要运行的容器镜像。
作用:从注册表
registry.lab.example.com
中拉取rhel9/mariadb-105
镜像并运行。
运行后,用podman ps看看后台是否运行
1 | [root@lixiaohui ~]# podman ps |
???发生了什么,为什么没有运行中的容器,那就看看有没有已经停止的容器?
1 | [root@lixiaohui ~]# podman ps -a |
它为什么停止了?没有运行?看看日志
1 | [root@lixiaohui ~]# podman logs lxhdb |
日志上说它没有/mnt的权限,好的,那我们给/mnt权限就行
1 | [root@lixiaohui ~]# ls -dZ /mnt/ |
再启动一下容器看看,成功启动
1 | [root@lixiaohui ~]# podman start lxhdb |
试试mysql好用不,我们测试一下密码,也就是我们的变量
1 | [root@lixiaohui ~]# dnf install mysql -y |
进入容器的方法:
进入容器看,我们的变量也是ok的
1 | [root@lixiaohui ~]# podman exec -it lxhdb /bin/bash |
Podman Desktop
Podman Desktop 是⼀个图形⽤⼾界⾯,可⽤于管理本地环境中的容器并与之交互。 它默认使⽤Podman 引擎,也⽀持其他容器引擎,如 Docker。
以下是多平台的下载链接,在课程中,已经内置在workstation机器上
1 | https://podman-desktop.io/downloads |
容器和镜像的⽣命周期
常⽤于更改容器和镜像状态的 Podman ⼦命令:
管理容器的 Podman 命令
podman run
- 启动一个新的容器。
podman start
- 启动一个已经停止的容器。
podman stop
- 停止一个正在运行的容器。
podman restart
- 重启一个正在运行或已经停止的容器。
podman kill
- 立即终止一个正在运行的容器。
podman rm
- 删除一个已经停止的容器。
podman ps
- 列出所有正在运行的容器。
podman inspect
- 显示容器的详细信息。
podman logs
- 查看容器的日志输出。
podman exec
- 在一个正在运行的容器内执行命令。
podman attach
- 连接到一个正在运行的容器。
podman stats
- 显示一个或多个容器的实时统计信息。
podman top
- 显示一个正在运行的容器中的进程信息。
podman pause
- 暂停一个或多个正在运行的容器。
podman unpause
- 恢复一个或多个暂停的容器。
常⽤于查询容器和镜像信息的⼦命令:
管理镜像生命周期的 Podman 命令
podman pull
- 从镜像仓库拉取容器镜像。
podman push
- 将本地容器镜像推送到镜像仓库。
podman build
- 根据 Dockerfile 构建容器镜像。
podman commit
- 从一个容器的变化中创建一个新的镜像。
podman images
- 列出所有本地存储的容器镜像。
podman rmi
- 删除一个或多个本地存储的容器镜像。
podman tag
- 给一个镜像打标签或重新标记。
podman history
- 显示镜像的历史信息。
RootLess与systemd服务
使用 RootLess与systemd 服务管理容器不仅提高了系统的稳定性和安全性,还简化了容器的管理和维护过程,而且可以让systemd来控制容器在开机时容器自动运行,不再需要管理员手工start,而且可以给普通用户安排容器来提高安全性。
普通用户运行 Podman 容器
权限限制:
普通用户只能访问和修改他们自己创建的容器和镜像,而无法影响系统或其他用户的资源。
增强了系统的安全性,因为普通用户的操作权限受到限制,不会对系统级资源造成影响。
隔离性:
容器运行在用户命名空间内,进一步隔离了容器和主机系统的资源。
这种隔离确保即使容器中的应用被攻破,攻击者也无法提升权限并控制整个系统。
配置灵活性:
普通用户可以在自己的主目录中配置容器和镜像的存储位置,提供更大的灵活性和定制化。
这使得多用户环境下,每个用户都可以独立管理自己的容器和镜像。
Root 用户运行 Podman 容器
完全权限:
Root 用户具有系统级权限,可以访问和修改所有容器和镜像。
可以对系统进行全面控制,包括配置网络、挂载系统文件、管理系统服务等。
更高的风险:
由于 root 用户具有完全权限,容器中的应用如果被攻破,攻击者可能会获取系统级权限,控制整个主机。
因此,root 用户运行容器时需要更加谨慎,避免不必要的风险。
系统资源管理:
Root 用户可以直接配置和管理系统资源,例如全局的网络配置和存储挂载。
可以设置更加细粒度的资源限制,确保系统资源的合理分配和使用。
RootLess容器管理
RootLess容器管理中,用户必须用ssh、控制台登录,不能用su命令切换到普通用户的方式去工作,因为su命令无法为podman提供完整的登录会话。
我们来创建一个普通用户,让这个普通用户创建一个rootless容器,并使用systemd来守护此容器,实现开机自启动
先创建出此用户
1 | [root@lixiaohui ~]# useradd lxhuser1 |
用ssh的方式切换到lxhuser1用户,只有ssh才能提供完整登录会话,所以不能su
1 | [root@lixiaohui ~]# ssh lxhuser1@localhost |
下载一下镜像
1 | [lxhuser1@lixiaohui ~]$ podman login -u admin -p redhat321 registry.lab.example.com --tls-verify=false |
为容器准备持久性存储
这里有一个知识点是podman unshare 命令
podman unshare 命令用于创建一个新的用户命名空间(User Namespace)并在其中运行一个指定的命令或启动一个新的 shell。这在需要以普通用户的身份执行一些通常需要 root 权限的操作时非常有用。podman unshare 命令为用户提供了在用户命名空间内运行命令或脚本的能力,这样可以在不提升到 root 权限的情况下执行高权限操作,从而增强系统的安全性和灵活性。
创建出数据库存储的位置
1 | [lxhuser1@lixiaohui ~]$ mkdir db_files |
运行一个容器看看
1 | [lxhuser1@lixiaohui ~]$ podman run -d \ |
后台发现容器没起来,看看日志是权限不足
1 | [lxhuser1@lixiaohui ~]$ podman ps |
经过测试,发现容器内的用户 ID 0(通常是 root)映射到主机上的用户 ID 1003,映射范围为 1 个 UID。
容器内的用户 ID 1 到 65536 映射到主机上的用户 ID 296608 开始的 65536 个 UID
1 后的每个 UID 和 GID以 1 增量递增
1 | [lxhuser1@lixiaohui ~]$ podman unshare cat /proc/self/uid_map |
我们试试授权给mariadb程序的用户看看,先去看看这个容器中的uid是多少,然后将本地的文件,授予给这个uid
运行一个临时容器,看看/etc/passwd里的用户
1 | [lxhuser1@lixiaohui ~]$ podman run -it registry.lab.example.com/rhel8/mariadb-103 /bin/bash |
明白了,容器内的mysql用户uid为27,我们将本地文件授予给27就行
1 | [lxhuser1@lixiaohui ~]$ podman unshare chown -R 27:27 db_files |
再启动容器看看
成功启动
1 | [lxhuser1@lixiaohui ~]$ podman start lxhdb |
根据映射关系,容器内的 UID 27 对应主机上的 UID 是:296608 + 27 - 1 = 296634,减1是因为原始值是1,要考虑偏移量
UID也是映射之后的,原来的1号用户uid为296608,加了26之后,正好就是296634
1 | [lxhuser1@lixiaohui ~]$ ls -l db_files/ |
容器已经成功运行了,不过这种手工运行的容器,机器重启后,它不会自动启动,接下来,我们试试生成systemd服务,把控制权由命令行交给systemd服务
1 | [lxhuser1@lixiaohui ~]$ podman stop lxhdb |
对于普通用户而言,服务文件需要放在~/.config/systemd/user/
这个位置,如果忘记了,可以看看man systemd.unit
1 | [lxhuser1@lixiaohui ~]$ mkdir -p ~/.config/systemd/user/ |
对于rootless的容器而言,所有的systemctl命令要加–user
我们来启用并启动我们的容器服务
如果在daemon-reload的时候报告找不到服务文件,而你确定又生成了的时候,那就是你没有用ssh方式登录,选择了su就会这样
1 | [lxhuser1@lixiaohui user]$ systemctl --user daemon-reload |
做到现在,我们的容器服务已经可以在用户登录时自动启动了,但是并不能在服务器重启后自动启动,是的,只有你登录的时候它才能启动,为了自动无需人工干预启动,还得这么做
需要确保最后一行的Linger=yes
1 | [lxhuser1@lixiaohui user]$ loginctl enable-linger lxhuser1 |
此时,你重启服务器,它就会自动启动了