1. tar 压缩选项速查
| 选项 | 压缩格式 | 文件后缀 | 解压命令 |
|---|---|---|---|
-czf | gzip | .tar.gz / .tgz | -xzf |
-cjf | bzip2 | .tar.bz2 | -xjf |
-cJf | xz | .tar.xz | -xJf |
-caf | 自动检测 | 任意 | -xaf |
常用示例:
# 压缩
tar -czf archive.tar.gz /path/to/dir # gzip
tar -cjf archive.tar.bz2 /path/to/dir # bzip2
tar -cJf archive.tar.xz /path/to/dir # xz
# 解压
tar -xzf archive.tar.gz
tar -xjf archive.tar.bz2
tar -xJf archive.tar.xz
tar -xaf archive.tar.gz # 自动检测格式gzip 与 bzip2 格式对比:
| gzip | bzip2 | |
|---|---|---|
| 魔数 (Magic) | 1f 8b | 42 5a ("BZ") |
| 头部结构 | 10 字节固定头 | 4 字节魔数 + 1 字节版本 |
| 压缩算法 | DEFLATE (LZ77 + Huffman) | Burrows-Wheeler + Huffman |
| 尾部 | CRC32 + 原始大小 (各 4 字节) | CRC + 原始大小 |
⚠️ 两者格式完全不同,不能互相替换或混合使用。
2. 容器管理完整指南
镜像与容器的关系
Containerfile/Dockerfile ← 配方(怎么装软件、配什么环境)
↓ podman build
镜像 (Image) ← 打包好的成品(只读,不动)
↓ podman run
容器 (Container) ← 跑起来的实例(活的,占内存)| 概念 | 类比 |
|---|---|
| Containerfile | 菜谱(写清楚要什么材料、怎么做) |
| 镜像 (Image) | 做好的菜,放冰箱里不动,随时能端出来 |
| 容器 (Container) | 餐桌上正在吃的那盘菜(可以吃、可以加调料) |
- 镜像:只读模板,包含操作系统基础层 + 软件 + 配置文件,存在本地磁盘上,一个镜像可以同时跑多个容器
- 容器:镜像跑起来的实例,在镜像基础上加了一个可写层,占用 CPU 和内存
完整操作流程
准备工作(root 用户)
# 1. 创建用户并设置密码
useradd sashat
echo "redhat" | passwd --stdin sashat
# 2. 安装 podman
yum install podman -y
# 3. 配置镜像仓库
vim /etc/containers/registries.confunqualified-search-registries = ["registry.lab.example.com"]
[[registry]]
location = "registry.lab.example.com"
insecure = true
blocked = false| 参数 | 含义 |
|---|---|
unqualified-search-registries | 不带域名前缀时默认搜索的仓库 |
insecure = true | 允许 HTTP 连接(考试内网无证书) |
blocked = false | 不阻止该仓库 |
构建镜像流程(sashat 用户)
# 1. 切换用户
ssh sashat@servera
# 2. 下载 Containerfile
wget http://content.example.com/Containerfile
# 3. 登录镜像仓库
podman login registry.lab.example.com
# Username: admin / Password: 321
# 4. 构建镜像
podman build -t modify_file:latest .
# ^ 点不能忘!
# 5. 查看构建结果
podman images⚠️ podman build -t name:tag . 最后的 . 表示当前目录作为构建上下文,漏掉会报错。
导入/推送镜像流程
# 1. 从 tar 包导入镜像
podman load < rsyslog.tar
# 2. 打标签(镜像名必须匹配仓库地址)
podman image tag localhost/rsyslog:latest registry.lab.example.com/library/rsyslog:latest
# 3. 登录仓库
podman login registry.lab.example.com
# 4. 推送到仓库
podman push registry.lab.example.com/library/rsyslog:latest⚠️ podman load 用 < 重定向读取,不能直接跟文件名。
运行容器
# 创建挂载目录
mkdir /home/sashat/syslog
# 运行容器
podman run -d --privileged \
-v /home/sashat/syslog:/var/log:Z \
--name logserver \
registry.lab.example.com/library/rsyslog:latest
# 进入容器执行命令
podman exec -it logserver /bin/bash
logger "This is a rhcsa exam"
# 验证
grep rhcsa /home/sashat/syslog/messages
skopeo inspect docker://registry.lab.example.com/library/rsyslog:latest| 参数 | 含义 |
|---|---|
-d | 后台运行(detach) |
--privileged | 特权模式,允许容器访问宿主机设备 |
-v 宿主机:容器:Z | 挂载目录,:Z 为 SELinux 标签 |
--name | 给容器命名 |
-it | 交互模式 + 伪终端 |
rm vs rmi
| 命令 | 用途 | 删除对象 |
|---|---|---|
podman rm | 删除容器 | 运行中/已停止的容器 |
podman rmi | 删除镜像 | 镜像(i = image) |
podman rmi localhost/rsyslog:latest
podman rmi --all # 删除所有镜像⚠️ 用 podman images 确认镜像已删除。
Podman 容器 systemd 开机自启
为什么需要先运行临时容器再生成服务文件?
podman generate systemd 需要读取一个已存在的容器配置来生成 .service 文件。正确流程:
run 临时容器(配好所有参数) → generate systemd 生成服务文件 → 删除临时容器 → systemd 接管完整操作流程
# 1. 准备挂载目录(root)
mkdir /opt/txt.pdf
chown sashat:sashat /opt/txt.pdf
# 2. 切换到用户
ssh sashat@servera
# 3. 运行临时容器
podman run -d --name txt2pdf \
-v /opt/txt/:/opt/txt:Z \
-v /opt/pdf:/opt/pdf:Z \
localhost/modify_file:latest
# 4. 生成 systemd 服务文件
mkdir -p ~/.config/systemd/user
cd ~/.config/systemd/user
podman generate systemd txt2pdf --files --name new
# 5. 启用开机自启
systemctl --user daemon-reload
systemctl --user enable container-txt2pdf.service
# 6. 清理临时容器并重启服务
podman rm -f txt2pdf
systemctl --user restart container-txt2pdf.service
# 7. 验证
podman ps| 命令 | 含义 |
|---|---|
podman generate systemd txt2pdf --files --name new | 根据容器配置自动生成 .service 文件 |
systemctl --user daemon-reload | 重新加载 systemd 用户级服务 |
systemctl --user enable | 设置用户级开机自启 |
⚠️ rootless 容器必须用用户级 systemd(--user),不能用系统级。
Podman 删除远程 Registry 中的错误镜像
问题: tag 错了本地镜像,push 到了远程 registry,需要删除
解决方法:
# 方法1:skopeo 删除
skopeo delete --force docker://registry.lab.example.com/library/rsyslog:latest
# 方法2:curl 调 API 删除
DIGEST=$(skopeo inspect docker://registry.lab.example.com/library/rsyslog:latest | python3 -c "import json,sys; print(json.load(sys.stdin)['Digest'])")
curl -X DELETE -k https://registry.lab.example.com/v2/library/rsyslog/manifests/$DIGEST前提条件: Registry 需要开启 delete 功能(storage.delete.enabled: true),否则返回 405
本地清理: podman rmi -f <image> 可以本地取消 tag
Docker 临时容器执行命令
场景: 用 Docker 运行一次性容器执行某个操作,容器自动删除。
# 生成 UUID(以 sing-box 代理工具为例)
docker run --rm ghcr.io/sagernet/sing-box:latest generate uuid| 参数 | 含义 |
|---|---|
--rm | 容器执行完后自动删除,不留垃圾 |
ghcr.io/sagernet/sing-box:latest | Docker 镜像地址(GitHub Container Registry) |
generate uuid | 容器内执行的命令 |
原理: Docker 拉取镜像 → 启动容器 → 执行 generate uuid → 输出 UUID 字符串 → 容器自动销毁。
⚠️ --rm 和 -d 不能同时用:--rm 会在容器退出时删除,-d 是后台运行。
Docker 端口映射 -p 主机端口:容器端口
命令示例:
docker run --name nginx_container_test -d -p 8080:80 nginx| 参数 | 含义 |
|---|---|
docker run | 运行一个新容器 |
--name nginx_container_test | 给容器起个名字 |
-d | 后台运行(detached),不占终端 |
-p 8080:80 | 端口映射(核心) |
nginx | 用 nginx 镜像(默认 nginx:latest) |
-p 主机端口:容器端口 核心原理:
宿主机(你的电脑) 容器(隔离的小盒子)
8080 ←————— 映射 —————→ 80
↑ ↑
外部访问入口 Nginx 内部监听端口- 8080 = 宿主机端口,外部能访问
- 80 = 容器内部端口,外部访问不到
- Docker 做中转:访问宿主机 8080 → 自动转到容器的 80
为什么不直接用 80? 容器是网络隔离的,容器内的 80 端口外面访问不到,必须通过 -p 暴露出来。 还能避免端口冲突:
- 容器 A:
-p 8080:80 - 容器 B:
-p 8081:80 - 两个 Nginx 同机跑,互不打架
实测访问: http://localhost:8080(浏览器应看到 Nginx 欢迎页)
常用端口参数:
-p 8080:80 # 指定映射(最常用)
-p 127.0.0.1:8080:80 # 只允许本机访问(绑定指定 IP,更安全)
-P # 大写P:随机映射端口(自动选空闲端口)查看实际映射:
docker port nginx_container_test
# 输出:80/tcp -> 0.0.0.0:8080一句话总结: 主机端口:容器端口 = 外面的人怎么敲门进哪个房间。8080 是大门铃,80 是屋里 Nginx 的房间号。
3. 用户与权限管理
语法公式
用户/组 主机=(目标用户) NOPASSWD:命令示例
%admins ALL=(root) NOPASSWD:ALL
① ② ③ ④| 字段 | 值 | 含义 |
|---|---|---|
① %admins | % = 组,admins = 组名 | admins 组所有成员 |
② ALL | 主机名 | 在任何主机上生效 |
(root) | 目标用户 | 可切换到 root |
③ NOPASSWD | 无需密码 | 执行 sudo 不需要输密码 |
④ ALL | 命令范围 | 可执行任何命令 |
常见写法速查
# 用户 harry 可 sudo,需要密码
harry ALL=(root) ALL
# 用户 harry 可 sudo,不需要密码
harry ALL=(root) NOPASSWD:ALL
# wheel 组可 sudo(RHEL 默认)
%wheel ALL=(ALL) ALL
# 用户 bob 只能重启 httpd
bob ALL=(root) /usr/bin/systemctl restart httpd
# users 组可 sudo,不需要密码
%users ALL=(root) NOPASSWD:ALL配置文件位置
/etc/sudoers ← 主配置文件(一般不动)
/etc/sudoers.d/admins ← 额外配置文件(推荐在这里写)⚠️ /etc/sudoers.d/ 下的文件名不要有 .(如 admin.conf),否则可能不被加载。
验证
su - harry
sudo id
# uid=0(root) gid=0(root) groups=0(root) ← sudo 提权成功密码策略 + chage 命令
全局默认策略:/etc/login.defs
vim /etc/login.defs| 参数 | 含义 | 默认值 |
|---|---|---|
PASS_MAX_DAYS | 密码最长有效天数(过期时间) | 99999 |
PASS_MIN_DAYS | 密码最短修改间隔(天) | 0 |
PASS_MIN_LEN | 密码最小长度(会被 PAM 覆盖) | 5 |
PASS_WARN_AGE | 密码到期前警告天数 | 7 |
考试常考:修改 PASS_MAX_DAYS 20 表示新用户密码 20 天后过期。
⚠️ /etc/login.defs 只对新创建的用户生效,已存在的用户不受影响。
验证新用户策略
useradd user1
chage -l user1
# Maximum number of days between password change : 20 ← 确认生效chage 命令:精确控制单个用户
chage [选项] 用户名| 参数 | 含义 | 示例 |
|---|---|---|
-l | 列出用户的密码策略信息 | chage -l harry |
-M | 设置密码最大有效期(天) | chage -M 90 harry |
-m | 设置密码最短修改间隔(天) | chage -m 7 harry |
-W | 设置密码到期提前警告天数 | chage -W 14 harry |
-I | 密码过期后强制停用天数 | chage -I 30 harry |
-E | 设置账户过期日期 | chage -E 2026-12-31 harry |
-d | 设置上次改密码日期 | chage -d 2026-01-01 harry |
常用场景:
chage -M 90 harry # 密码 90 天过期
chage -I 3 harry # 过期后 3 天不改就锁定
chage -E 2026-12-31 intern1 # 账户 2026-12-31 过期
chage -d 0 harry # 强制下次登录必须改密码chage -l 输出解读
Last password change : Jan 01, 2026
Password expires : Mar 02, 2026
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 90 ← 关键字段
Number of days of warning before password expires : 7login.defs vs chage 区别
/etc/login.defs | chage | |
|---|---|---|
| 作用范围 | 全局默认,只影响新用户 | 单个用户,精确控制 |
| 生效时机 | 创建用户时读取 | 立即生效 |
| 适合场景 | 改默认策略 | 改已有用户 |
useradd -g 与 -G 的区别
-g(小写)= 主组(primary group)
- 指定用户登录时的默认组
- 用户只能有一个主组
- 示例:
useradd -g admins harry→ harry 的主组是 admins
-G(大写)= 附加组(supplementary groups)
- 指定用户额外属于的组,可以有多个(逗号分隔)
- 示例:
useradd -G admins harry→ harry 主组是默认的 harry 组,admins 是附加组
记忆技巧: 小 g = group(一个),大 G = Groups(多个)
验证: id harry 可以看到 gid(主组)和 groups(所有组)
umask 详解(user file-creation mask)
一句话
umask = 「新创建的文件/目录默认要扣掉的权限」,进程级别,全称 user file-creation mask。
核心算式
最终权限 = 基权限 - umask(按位减,更准确地说:& ~umask)| 类型 | 基权限 | 八进制 |
|---|---|---|
| 文件(无 x) | rw-rw-rw- | 666 |
| 目录(含 x) | rwxrwxrwx | 777 |
为什么文件默认没 x?避免刚建的文件能被意外执行,是历史约定。
umask 常见值对照
| umask | 文件 | 目录 | 场景 |
|---|---|---|---|
| 022(默认) | 644 rw-r--r-- | 755 rwxr-xr-x | 普通文件 |
| 027 | 640 rw-r----- | 750 rwxr-x--- | 严格组权限 |
| 077 | 600 rw------- | 700 rwx------ | 私钥 / 密码文件 |
| 002 | 664 rw-rw-r-- | 775 rwxrwxr-x | 团队共享 |
算式(umask=077):
文件:666 & ~077 = 110 110 110 & 111 000 111 = 600(-rw-------)
目录:777 & ~077 = 700(drwx------)老大的命令拆解
(umask 077; openssl genrsa -out devman.key 2048)| 部分 | 含义 |
|---|---|
( ... ) | 子 shell:括号里是新 shell,不影响当前 shell 的 umask |
umask 077 | 子 shell 里临时设 umask 为 077 |
openssl genrsa -out devman.key 2048 | 生成 2048 位 RSA 私钥到 devman.key |
| 效果 | 生成的私钥自动是 600(只有 owner 读写) |
为什么必须用子 shell ( )? 直接 umask 077 会污染当前 shell;{ } 是同 shell;( ) 退出后自动还原,是一次性改 umask 的标准安全写法。
为什么私钥一定要 600?
# 默认 umask 022 + 生成私钥:
$ umask # 系统默认 022
$ openssl genrsa -out bad.key 2048
$ ls -l bad.key
-rw-r--r-- ... bad.key # 其他用户可读!危险
# 用子 shell 加 umask 077:
$ (umask 077; openssl genrsa -out good.key 2048)
$ ls -l good.key
-rw------- ... good.key # 只有 owner 读写私钥泄露 = 任何能读这文件的用户都能解密/伪装身份。私钥几乎一定要 600,是行业铁规。
相关实用命令
umask # 当前 umask(数字)
umask -S # 当前 umask(符号格式)
umask 077 # 设为 077(影响当前 shell 及后续子进程)
stat -c '%a %n' file # 看文件八进制权限:600 devman.key
stat -c '%A %n' file # 看文件符号权限:-rw------- devman.key
chmod 600 file # 手动改,不依赖 umask易踩坑清单
- 子 shell
( )vs 命令组{ ; }:( )真子 shell、退出环境还原;{ ; }同 shell、大括号右侧需空格 openssl genrsa默认不锁权限:跟 umask 强依赖,不主动 chmod 就会按默认 umask 走- SSH 私钥要求 600:否则
ssh直接报错Permissions 0644 for 'xxx' are too open - root 创建文件默认也是 644:root 不自动 600,同样依赖 umask
- umask 只决定新文件默认权限:已存在文件改动用 chmod,不跟 umask 走
- umask 不能加可执行位:就算
umask 000,文件也是 666,想可执行必须显式chmod +x - Docker / k8s 容器内 umask 跟宿主机可能不同:跨环境生成文件要醒一下
- 台子里
umask 027很常见:很多发行版在/etc/profile设过,影响所有交互登录 - 一些系统命令(比如
install)有自己的 mode 覆盖:不会顺着 umask
4. 磁盘与存储管理
LVM 三层架构
物理硬盘/分区 → 物理卷(PV) → 卷组(VG) → 逻辑卷(LV) → 格式化 → 挂载
/dev/vdb pvcreate vgcreate lvcreate mkfs mount| 层级 | 命令 | 含义 |
|---|---|---|
| 物理卷 (PV) | pvcreate | 把硬盘/分区注册进 LVM |
| 卷组 (VG) | vgcreate | 把 PV 合成一个大存储池 |
| 逻辑卷 (LV) | lvcreate | 从 VG 里切出一块空间 |
| 格式化 | mkfs | 创建文件系统 |
| 挂载 | mount | 接到目录树上 |
扩容逻辑卷
lvextend -r -L 512M /dev/exam/rhel| 参数 | 含义 |
|---|---|
lvextend | 扩展逻辑卷大小 |
-r | 同时调整文件系统大小(自动 resize) |
-L 512M | 目标大小(绝对大小) |
⚠️ 传统方式需两步:先 lvextend 再 resize2fs(ext4)或 xfs_growfs(xfs)。加 -r 一步搞定。
创建逻辑卷(含 PE 大小设置)
题目要求: 卷组 myvg,逻辑卷 mylv,PE 大小 16M,LV 大小 50 个 PE(= 800M),文件系统 ext3,挂载 /mnt/mydata
# 1. 创建分区
fdisk /dev/vdb
# n → p → 默认分区号 → +1G
# 2. 设置分区类型为 LVM
# t → 分区号 → 8e
# 3. 保存
# w
# 4. 创建卷组,PE 大小 16M(关键!)
vgcreate -s 16M myvg /dev/vdb3
# 5. 创建逻辑卷(50 个 PE)
lvcreate -l 50 -n mylv myvg
# 6. 格式化为 ext3
mkfs.ext3 /dev/myvg/mylv
# 7. 创建挂载点并永久挂载
mkdir /mnt/mydata
echo '/dev/myvg/mylv /mnt/mydata ext3 defaults 0 0' >> /etc/fstab
mount -a
# 8. 验证
df -Th /mnt/mydata/-L vs -l 区别
| 参数 | 含义 | 示例 |
|---|---|---|
-L(大写) | 指定绝对大小 | -L 800M |
-l(小写) | 指定PE 数量 | -l 50 |
PE (Physical Extent) 说明
- PE 是 LVM 最小的存储分配单位,默认 4M
- 逻辑卷大小必须是 PE 大小的整数倍
- 用
vgcreate -s 16M可以修改 PE 大小
易错点
| 易错点 | 正确做法 |
|---|---|
| PE 大小忘了改 | vgcreate -s 16M,不是默认 4M |
用 -L 而不是 -l | -l 50(PE 数量),不是 -L 50M |
| 格式化用 ext4 | 题目要求 ext3 |
| 缩容顺序反了 | 必须先缩文件系统,再缩 LV(扩容顺序相反) |
⚠️ 扩缩容顺序相反: 扩容先扩 LV 再扩文件系统;缩容先缩文件系统再缩 LV。xfs 文件系统不能缩容。
Swap 交换区配置
完整流程
# 1. 创建分区
fdisk /dev/vdb
# n → p → 2 → +512M
# 2. 设置分区类型为 swap
# t → 2 → 82
# 3. 保存
# w
# 4. 格式化为 swap
mkswap /dev/vdb2
# 5. 临时启用
swapon /dev/vdb2
# 6. 写入 fstab 永久生效
echo '/dev/vdb2 swap swap defaults 0 0' >> /etc/fstab
# 7. 验证 fstab
swapoff -a
mount -a
swapon -a
# 8. 确认生效
free -mSwap 是什么?
物理内存 (RAM) 不够用时,把不活跃的数据暂时放到硬盘上,这块硬盘空间就是 Swap。
为什么需要 Swap?
- 当物理内存不足时,系统把不活跃的数据从内存搬到磁盘上的 swap 空间,腾出内存给当前需要的进程
- 好处:防止 OOM (Out of Memory) killer 杀进程
- 坏处:磁盘比内存慢几十倍,swap 频繁使用会导致系统变慢
两种创建 swap 的方式:
# 方式一:用文件创建(简单,推荐小容量)
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
# 方式二:用分区创建(正式环境,已在上方详述)
# fdisk → t → 82 → mkswap → swapon → fstab⚠️ fallocate 方式不支持 ZFS 和某些旧内核。创建后记得 chmod 600,否则 swap 可能不生效。
关键参数说明
| 步骤 | 命令 | 含义 |
|---|---|---|
| 格式化 | mkswap /dev/vdb2 | 把分区格式化为 swap 格式 |
| 临时启用 | swapon /dev/vdb2 | 告诉内核开始使用这个 swap |
| 永久生效 | fstab 中 swap swap defaults 0 0 | 开机自动启用 |
| 停用 | swapoff -a | 停用所有 swap |
fstab 中 swap 条目格式
设备文件 挂载目录 格式 选项 备份 自检
/dev/vdb2 swap swap defaults 0 0free -h vs free -m
| 参数 | 输出格式 | 示例 |
|---|---|---|
free -h | 人类可读(G/M/K) | Mem: 3.7Gi 1.2Gi 2.1Gi ... |
free -m | 以 MB 为单位 | Mem: 3812 1234 2156 ... |
free -g | 以 GB 为单位 | Mem: 3 1 2 ... |
推荐: 日常使用 free -h 最直观,脚本中用 free -m 方便解析。
free -h
# total used free shared buff/cache available
# Mem: 3.7Gi 1.2Gi 2.1Gi 128Mi 400Mi 2.3Gi
# Swap: 2.0Gi 0.0Gi 2.0Gi输出字段含义:
| 字段 | 含义 |
|---|---|
total | 总物理内存 |
used | 已用内存(包含 buffer/cache) |
free | 完全空闲的内存 |
shared | 多进程共享的内存 |
buff/cache | 缓冲区/缓存(可回收) |
available | 可用内存(free + 可回收的 cache) |
⚠️ 看内存够不够用,看 available 而不是 free。
free -m 输出解读
total used free
Swap: 511 0 511 ← 看这行,511M ≈ 512M易错点
| 易错点 | 正确做法 |
|---|---|
| 分区号选错 | vdb1 已被 LVM 用,swap 用 vdb2 |
| 没改分区类型 | 必须 t → 82 设为 swap 类型 |
| 只 swapon 没写 fstab | 必须写 fstab 否则重启失效 |
| 忘了验证 fstab | 写完用 swapoff -a && swapon -a 测试 |
fdisk Partition number 默认值
Partition number (1, 2, default 2):中默认是 2 的原因:/dev/vdb1已被占用- MBR 分区表的分区号从 1 开始编号,fdisk 检测到 1 号已被使用,所以默认给出第一个空闲号 2
- 如果磁盘是全新的,默认就是 1
- MBR 最多 4 个主分区(编号 1-4)
分区类型(Partition Type)与修改方法
分区类型是什么: 只是一个标签,告诉系统这个分区的用途,不影响实际功能
常见类型:
- 83 = Linux(普通分区)
- 82 = Linux swap
- 8e = Linux LVM
- fd = Linux RAID
- ef = EFI System
修改方法:
fdisk /dev/sdb→ 按t→ 输入类型编号gdisk /dev/sdb→ 按t→ 输入 GUID 代码parted /dev/sdb set 1 lvm on(非交互式)sfdisk /dev/sdb <<< ',8e'(脚本化)
RHCSA 考试流程(创建 LVM):
- fdisk 创建分区 → t → 改为 8e(LVM)
- pvcreate /dev/sdb1
- vgcreate vg0 /dev/sdb1
- lvcreate -n lv0 -L 500M vg0
注意: 改类型只是改标签,不丢数据;但 pvcreate 会写入 LVM 元数据,会清掉原有数据
MBR vs GPT 分区表类型
MBR(Master Boot Record):
- 最大 2TB 磁盘
- 最多 4 个主分区(或 3主+1扩展,扩展里分逻辑分区)
- BIOS 启动用
- 工具:fdisk、parted(默认 MBR)
GPT(GUID Partition Table):
- 支持超 2TB 磁盘
- 最多 128 个主分区
- UEFI 启动用
- 工具:gdisk、parted
查看分区表类型:
lsblk -fparted /dev/sdb print(看 Label:msdos=MBR,gpt=GPT)fdisk -l /dev/sdb(看 disklabel type)
创建分区表:
fdisk /dev/sdb→ 默认 MBRparted /dev/sdb mklabel msdos→ MBRparted /dev/sdb mklabel gpt→ GPT
RHCSA 考试: 一般用 MBR + fdisk,简单直接
5. Cron 计划任务完整指南
| cron 写法 | 含义 | 执行时间 |
|---|---|---|
*/2 | 每隔 2 分钟 | 0, 2, 4, 6, 8, ... |
2 | 每小时的第 2 分钟 | x:02:00 |
原理:* 表示"所有值",*/2 = "所有值中每隔 2 个取一个",即 0, 2, 4, 6...
常见例子:
*/5→ 每 5 分钟*/10→ 每 10 分钟*/15→ 每 15 分钟
一句话:*/数字 = 每隔 N 分钟,单独写数字 = 每小时的第 N 分钟
Cron 计划任务相关命令总结
一、Linux 系统 cron 命令
| 命令 | 含义 |
|---|---|
crontab -l | 查看当前用户的计划任务 |
crontab -l -u natasha | 查看指定用户的计划任务 |
crontab -e | 编辑当前用户的计划任务(交互式) |
crontab -r | 删除当前用户的所有计划任务 |
crontab mycron.txt | 从文件导入计划任务 |
cron 时间格式
┌────── 分钟 (0-59)
│ ┌──── 小时 (0-23)
│ │ ┌── 日 (1-31)
│ │ │ ┌ 月 (1-12)
│ │ │ │ ┌ 星期 (0-7, 0和7都是周日)
│ │ │ │ │
*/2 * * * * echo hello特殊符号
| 符号 | 含义 | 示例 |
|---|---|---|
* | 每 | * * * * * 每分钟 |
*/n | 每隔 n | */5 * * * * 每5分钟 |
, | 列举 | 1,3,5 * * * * 第1、3、5分钟 |
- | 范围 | 1-5 * * * * 第1到5分钟 |
常见 cron 示例
- 每天凌晨2点:
0 2 * * * /scripts/backup.sh - 每周一早上8点:
0 8 * * 1 /scripts/report.sh - 每5分钟:
*/5 * * * * /scripts/check.sh
二、Ansible cron 模块
| 参数 | 含义 |
|---|---|
name | 任务描述(标识,用于删除) |
minute | 分钟 |
hour | 小时 |
day | 日 |
month | 月 |
weekday | 星期 |
job | 执行的命令 |
user | 执行用户 |
state | present(创建) / absent(删除) |
创建:cron: name="任务描述" minute="*/2" user=natasha job="echo hello" 删除:cron: name="任务描述" state=absent(用 name 匹配精确删除)
三、系统 crontab vs Ansible cron
| 项目 | 系统 crontab | Ansible cron 模块 |
|---|---|---|
| 编辑方式 | crontab -e 交互式 | Playbook 声明式 |
| 删除任务 | 手动删行或 crontab -r 清空 | state: absent 按 name 精确删除 |
| 标识 | 无 | name 字段(Ansible 自动加注释) |
6. 系统监控脚本
脚本内容
#!/bin/bash
ps -xao user,pid,vsz,rss,%cpu --sort=%cpups 参数拆解
ps -xao user,pid,vsz,rss,%cpu --sort=%cpu
① ② ③ ④| 参数 | 含义 |
|---|---|
-x | 显示所有用户的进程,包括不依附终端的 |
-a | 显示所有终端(tty)上的进程 |
-o | 自定义输出格式(字段用逗号隔开) |
--sort=%cpu | 按 CPU 使用率升序排列 |
输出字段说明
| 字段 | 含义 |
|---|---|
user | 进程的所有者 |
pid | 进程 ID |
vsz | 虚拟内存大小(KB) |
rss | 实际占用的物理内存(KB) |
%cpu | CPU 使用率 |
创建和运行
# 1. 创建脚本
vim /usr/local/bin/exam_sysinfo
# 2. 加执行权限
chmod +x /usr/local/bin/exam_sysinfo
# 3. 运行
exam_sysinfops 其他常用参数
| 参数 | 含义 |
|---|---|
-ef | 显示所有进程 + 完整命令 |
-aux | BSD 风格,显示所有进程 |
--sort=-%cpu | 降序排列(CPU 最高的在前面) |
--sort=-%mem | 按内存降序排列 |
⚠️ 脚本放在 /usr/local/bin/ 可以直接用名字运行,不用写全路径。
top 与 htop 实时监控
top 基本用法
top常用快捷键:
| 按键 | 功能 |
|---|---|
Shift+M | 按内存 (MEM%) 降序排列 |
Shift+P | 按 CPU 降序排列 |
Shift+N | 按 PID 降序排列 |
1 | 展开每个 CPU 核心 |
k | 杀死进程(输入 PID) |
q | 退出 top |
htop(增强版 top)
# 安装
yum install -y htop # RHEL/CentOS
apt install -y htop # Debian/Ubuntu
# 运行
htophtop 优势:
- 鼠标可点击,无需记快捷键
- 彩色显示,更直观
- 支持树状视图(按
F5) - 搜索进程(按
F3)
⚠️ htop 需要额外安装,top 系统自带。
6.1 lsof 详解(查进程 / 文件 / 端口 / 网络资源)
查进程“三件套”
| 需求 | 命令 | 说明 |
|---|---|---|
| 进程快照 | ps aux | 最常用,一次列出所有进程 |
| 实时监控 | top / htop | 动态刷新(htop 更友好) |
| 查 PID | pidof nginx / pgrep -f 关键字 | 按名字/命令行反查 PID |
ps aux 输出字段:USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND STAT 常见值:R 运行、S 睡眠、Z 僵尸(有害)、T 停止、s 会话首进程。
lsof 是什么
全名:LiSt Open Files —— 列出打开的文件 核心思想:Linux 一切皆文件(普通文件、目录、socket、管道、设备),所以 lsof 能查所有打开的资源。
最常用的 7 个用法
① 端口被占,谁在监听?
lsof -i :80
# COMMAND PID USER FD TYPE DEVICE NAME
# nginx 1234 root 6u IPv4 ... TCP *:http (LISTEN)② 文件被占,删不掉?
rm /var/log/nginx/access.log # Device or resource busy
lsof /var/log/nginx/access.log # 查谁在用③ 进程打开了哪些东西?
lsof -p 1234 # 进程 1234 所有打开的资源
lsof -p 1234 -i # 进程 1234 的网络连接④ 谁在用某个目录?
lsof +D /var/log/nginx/ # 递归查目录(慢)
lsof +d /var/log/nginx # 不递归⑤ 指定用户的进程
lsof -u root -i # root 的网络连接⑥ 协议过滤
lsof -i tcp:22 # 只看 22 端口 TCP⑦ 反向查连接
lsof -p 1234 -i -a | grep ESTABLISHED实战场景速查
| 场景 | 命令 |
|---|---|
| 端口被占 | lsof -i :端口 |
| 文件删不掉 | lsof <文件> |
| 查进程在干啥 | lsof -p <PID> |
| 查进程网络连接 | lsof -p <PID> -i |
| 查谁在写日志 | lsof +D /var/log/ |
lsof vs ss vs netstat
| 命令 | 特点 | 用途 |
|---|---|---|
lsof | 文件级精确(进程+FD+文件) | 文件/端口/网络全能查 |
ss -tlnp | 快(读内核),netstat 替代品 | 仅查端口监听 |
netstat -tlnp | 老工具,慢 | 同上(逐渐淘汰) |
推荐:查端口用 ss -tlnp(快),查具体进程占文件用 lsof(精)。
一句话速记: lsof = LiSt Open Files,Linux 一切皆文件,所以能查进程、文件、端口、socket、目录的所有打开状态。最常用三招:端口占用 lsof -i :端口、文件被占 lsof <文件>、进程资源 lsof -p <PID>。
7. find 命令综合题
脚本内容
#!/bin/bash
find /usr -size +30k -size -50k -perm -4000 -type f > /root/myfile参数拆解
| 参数 | 含义 |
|---|---|
/usr | 从 /usr 目录开始搜索 |
-size +30k | 大于 30KB |
-size -50k | 小于 50KB |
-perm -4000 | 包含 SUID 权限位 |
-type f | 只找普通文件 |
> /root/myfile | 结果写入文件 |
两个 -size 同时使用是 AND 关系:30k < 文件 < 50k
特殊权限位
| 权限位 | 数字 | 含义 |
|---|---|---|
| SUID | 4000 | 执行时以文件所有者身份运行 |
| SGID | 2000 | 执行时以文件所属组身份运行 |
| SBIT | 1000 | 粘滞位(如 /tmp) |
创建和运行
vim /usr/local/bin/mysearch
chmod a+x /usr/local/bin/mysearch
/usr/local/bin/mysearch
cat /root/myfile脚本命名说明
Linux 里文件扩展名不影响执行。系统只关心:
- 文件有没有执行权限(
chmod +x) - 文件开头有没有 shebang(
#!/bin/bash)
.sh 后缀只是给人看的,考试/规范推荐不加后缀(像系统命令 ls、grep 一样)。
8. chattr -i 锁定文件属性
chattr +i /etc/resolv.conf # 加 immutable 属性,文件不可改/删/重命名(root 也不行)
chattr -i /etc/resolv.conf # 去掉 immutable 属性,恢复可编辑用途:RHEL 7+ 的 /etc/resolv.conf 被 NetworkManager 管理,手动改 DNS 后用 chattr +i 锁死防止被覆盖;需要再改时先 chattr -i 解锁。
考试常考:改 DNS 配置前先解锁,改完再锁上。
9. free -m vs df -Th vs lsblk 三者对比
| free -m | df -Th | lsblk | |
|---|---|---|---|
| 看什么 | 内存 + swap | 文件系统空间 | 块设备结构 |
| 层级 | RAM 层 | 文件系统层 | 磁盘/分区层 |
| swap 相关 | ✅ 显示 swap 总量和使用 | ❌ 不显示 | ⚠️ 只标 [SWAP] 标记 |
| 能看到设备关系 | ❌ | ❌ | ✅ 树状展示 |
| 能看到可用空间 | ✅ 内存可用 | ✅ 磁盘可用 | ❌ 只有大小 |
为什么验证 swap 用 free -m 而不是 df -Th? swap 分区没有文件系统,df -Th 根本看不到它。
10. sed 替换命令详解
sed -i "s/^Listen 80/Listen 82/g"参数拆解
| 参数 | 含义 |
|---|---|
sed | Stream Editor,流编辑器 |
-i | 原地编辑(in-place),直接修改文件 |
s/ | 替换命令(substitute) |
^Listen 80 | 匹配内容(^ = 行首锚定) |
Listen 82 | 替换内容 |
g | 全局替换(一行中多个匹配全换) |
正则说明
^行首锚定:只匹配行开头的,不匹配行中间的- 没有
^:一行中任何位置出现都替换 - 有
g:一行中所有匹配都替换 - 没有
g:只替换每行第一个匹配
常见用法
# 替换并备份原文件
sed -i.bak "s/old/new/g" file.conf
# 只输出不改文件(不加 -i)
sed "s/old/new/g" file.conf
# 删除空行
sed -i '/^$/d' file.conf
# 删除行首空格
sed -i 's/^[[:space:]]*//' file.conf11. Bash 单引号与双引号的区别
无变量时两者等价:
logger 'This is a rhcsa exam'和logger "This is a rhcsa exam"效果相同
有变量时不同:
- 单引号:所见即所得,不解析变量 →
echo '$VAR'输出$VAR - 双引号:解析变量和命令替换 →
echo "$VAR"输出变量值
记忆: 字符串里有 $ 才需要考虑用哪种引号,纯文本随便用
12. Samba 共享配置详解
配置示例
[share]
path = /media/bbben/disk/share
browseable = yes
writable = yes
valid users = @bbben
create mask = 0660
directory mask = 2770逐项说明
- [share]:共享名,客户端连接时显示的名字(如
\\IP\share) - path:共享目录的物理路径
- browseable = yes:在网络浏览中可见(no 则隐藏共享)
- writable = yes:允许写入(no 则只读)
- valid users = @bbben:
@表示用户组,只有 bbben 组内用户可访问(不带@是用户名) - create mask = 0660:新建文件权限 rw-rw----(属主6+同组6+其他0)
- directory mask = 2770:新建目录权限 rwxrws---(770 + setgid位2,子文件自动继承父目录组)
部署注意
- 确保系统有 bbben 组,用户已加入
- Samba 密码独立设置:
smbpasswd -a 用户名 - 目录权限:
chown root:bbben /media/... && chmod 2770 /media/... - 改完配置先
testparm检查语法,再systemctl restart smbd
查看连接与日志
sudo smbstatus:查看当前活跃的 SMB 连接- 日志目录:
/var/log/samba/log.smbd:核心日志log.nmbd:名称解析日志log.<hostname>:按客户端主机名分文件
smb.conf 完整结构
[global] # 全局配置(workgroup、security、hosts allow、log level)
[homes] # 用户家目录共享(%S 自动指向当前用户目录)
[共享名] # 自定义共享(path、writable、valid users、create mask)关键配置项
security = user:推荐模式,每个连接都要认证hosts allow:建议只放行需要的网段- 常用变量:
%m=客户端主机名,%M=客户端IP,%S=当前用户名
13. 终端传文件到服务器的方式
1. scp(最常用)
核心语法:
# 本地 → 远程
scp /本地/文件 用户@主机:/远程路径
# 远程 → 本地
scp 用户@主机:/远程/文件 /本地路径
# 路径格式必须是 用户@主机:/路径,冒号不能漏常用选项:
| 选项 | 作用 | 注意 |
|---|---|---|
-r | 递归传目录 | 传目录必须加 |
-P 端口 | SSH 端口 | 大写 P |
-p | 保留文件属性(时间、权限) | 小写 p |
-C | 启用压缩 | 慢网络有用 |
-i 密钥 | 指定私钥 | 密钥登录时 |
-v | 详细输出 | 调试用 |
-l 限速 | 限速 KB/s | 大文件避免占带宽 |
实战例子:
scp nginx.conf root@server:/etc/nginx/ # 传配置
scp -r ./myapp/ root@server:/opt/ # 传项目目录
scp -i ~/.ssh/id_rsa test.txt root@server:/root/ # 密钥登录
scp -P 2222 test.txt root@server:/root/ # 改 SSH 端口常见坑:
- 远程目录必须存在,scp 不会自动创建
- 冒号别漏(漏了就成本地路径,报错找不到)
- 大写
-P是端口,小写-p是保留属性,别混 - 第一次连接要确认 fingerprint(输入 yes)
基于 SSH,简单直接,无断点续传(大文件用 rsync)。
2. rsync(推荐,增量同步)
rsync -avz 本地目录/ 用户名@IP:/远程路径/支持断点续传、增量同步,适合大文件和目录同步。
3. sftp(交互式)
sftp 用户名@IP
# put/get/lcd/cd 等交互命令适合不确定路径时慢慢操作。
4. cat + ssh(管道流,小文件)
cat 本地文件 | ssh 用户名@IP "cat > /远程路径/文件"适合传配置文件等小内容。
5. ssh + tar(大批量传输)
tar czf - /本地目录 | ssh 用户名@IP "tar xzf - -C /远程路径/"打包压缩传输,一次性大量文件。
6. lrzsz(rz/sz,终端内传)
rz # 上传(弹文件选择框)
sz 文件 # 下载需服务器安装 lrzsz,适合小文件,无断点续传。
日常推荐
- 小文件 → scp
- 目录同步 → rsync
- 覆盖 90% 场景
14. macOS 与 Linux 服务管理体系对比
macOS 服务管理
1. launchd(核心机制)
- 系统级:
/Library/LaunchDaemons/(后台守护)、/Library/LaunchAgents/(登录启动) - 用户级:
~/Library/LaunchAgents/ - 管理命令:
launchctl list、launchctl load/unload - 配置文件:plist 格式
2. Homebrew Services(第三方,推荐)
brew services list/start/stop/restart- 简化了 launchd 的操作
3. 应用目录
/Applications/(系统级)、~/Applications/(用户级)
Linux 服务管理
systemd(核心)
- 服务文件:
/lib/systemd/system/ - 自定义服务:
/etc/systemd/system/ - 用户服务:
~/.config/systemd/user/ - 管理命令:
systemctl list-units --type=service、systemctl status/start/stop/enable/disable
关键区别
| 维度 | macOS | Linux |
|---|---|---|
| 服务管理 | launchd + brew services(两层) | systemd(一个管所有) |
| 服务配置 | plist 文件 | service 文件 |
| 查看端口 | `lsof -i -P | grep LISTEN` |
| 包管理 | brew | apt/yum/dnf |
15. 运维学习路线与概念梳理
脚本、服务、容器的关系
脚本(shell/python)
↓ 注册为 systemd 服务 → systemctl 管理
↓ 打包为 Docker 镜像 → docker/podman 管理
↓ 镜像运行 → 容器(轻量隔离的"服务")systemd 服务 vs Docker 容器
| 维度 | systemd 服务 | Docker 容器 |
|---|---|---|
| 管理工具 | systemctl | docker / podman |
| 隔离性 | 共享宿主机环境,无隔离 | 独立文件系统/网络/进程,强隔离 |
| 启动方式 | systemctl start xxx | docker run xxx |
| 资源占用 | 轻,直接跑在宿主机 | 稍重(但比虚拟机轻很多) |
| 部署方式 | 手动装依赖、写 service 文件 | Dockerfile 一键构建 |
| 可移植性 | 换台机器要重新装环境 | 镜像在哪都能跑 |
| 适合场景 | 单机、简单服务 | 微服务、多环境、团队协作 |
systemd 服务示例
# /etc/systemd/system/my-app.service
[Unit]
Description=My App
[Service]
ExecStart=/usr/bin/python3 /opt/my-app/main.py
Restart=always
[Install]
WantedBy=multi-user.targetDocker 镜像示例
FROM python:3.11
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "main.py"]学习路线
第一阶段(基础巩固):
- systemd 服务管理 ✅
- Nginx 反向代理 ✅
- 进程管理、文件权限
第二阶段(自动化运维):
- Shell 脚本(变量、条件、循环、函数、正则)
- Crontab 定时任务
- 日志管理(journalctl、logrotate)
- 网络排查(curl、dig、ss、tcpdump、iptables)
第三阶段(容器化):
- Docker 基础(镜像、容器、Dockerfile、docker-compose)
- Docker 网络和数据卷
- docker-compose 多容器编排
第四阶段(进阶方向):
- 云原生/K8s(大规模容器编排)
- CI/CD(GitHub Actions、Jenkins)
- 监控告警(Prometheus + Grafana)
- 安全加固(服务器安全)
建议下一步
- 写实用脚本练手(健康检查、备份、日志清理)
- 把知识库做成 Docker 镜像(练 Docker 基础)
- 考完 RHCSA/RHCE 后进入 Docker 阶段
核心:Shell 脚本 + Docker = 运维入门
16. apt update 与 apt upgrade 的区别
apt update:更新软件源索引(本地缓存的包列表),不安装任何软件apt upgrade:根据最新索引,实际升级已安装的软件包
为什么要先 update?
- apt install/upgrade 查的是本地缓存的索引,不会实时访问远程服务器
- 不 update → 本地索引过期 → 可能装不上或装旧版本
- 类比:先去超市拿最新价目表,再按价格买东西
标准流程:sudo apt update && sudo apt upgrade -y
17. Alias 别名配置
配置文件:
- Linux bash:
~/.bashrc - Linux zsh / macOS zsh:
~/.zshrc - 全局:
/etc/bash.bashrc或/etc/profile.d/
用法:
- 临时生效:
alias python=python3 - 永久生效:写入
~/.zshrc或~/.bashrc,然后source加载 - 查看所有别名:
alias - 删除别名:
unalias python
python3 vs python:很多 Linux 发行版默认只有 python3,没有 python,用 alias python=python3 即可解决
注意:python3 和 pip3 本身就是标准命令,不需要起别名。需要 alias 的是 python 和 pip(让它们指向 python3/pip3)。在 venv 虚拟环境里 python/pip 自动可用,不需要 alias。
18. HTTPS 反向代理配置(Nginx + Let's Encrypt)
核心概念:
- HTTPS = HTTP + TLS 加密,防止窃听、篡改、伪装
- Nginx 作为反向代理终止 TLS,解密后转发 HTTP 到后端应用
- Let's Encrypt 提供免费 TLS 证书,90 天有效期,自动续期
操作步骤:
- 安装 Nginx + Certbot:
apt install nginx certbot python3-certbot-nginx - 确保域名 DNS 解析到服务器 IP
- 配置 Nginx 反向代理(先只配 HTTP 80 端口)
certbot --nginx -d 域名1 -d 域名2一键申请+配置- 确认自动续期:
systemctl status certbot.timer+certbot renew --dry-run - 防火墙放行 80 和 443 端口
常见坑:
- 没配 HTTPS 时浏览器自动尝试 443 端口超时导致页面加载慢
- Nginx 以 www-data 用户运行,无法读 /root/ 目录下的文件(Permission denied → 500)
19. Nginx gzip 压缩配置
- 在
/etc/nginx/nginx.conf的http {}块中添加 gzip 配置 - 关键参数:
gzip on; gzip_vary on; gzip_comp_level 5; gzip_min_length 1024; - gzip_types 覆盖 text/css/js/json/xml/svg 等
- 验证:
curl -sI -H "Accept-Encoding: gzip" https://域名 | grep content-encoding - 效果:HTML/CSS/JS 压缩 60-80%,页面加载明显变快
20. Nginx 500 错误排查命令
命令:awk '$9 == 500 {print $4, $7, $1}' /var/log/nginx/access.log | head -20
拆解:
- awk 默认分隔符:空格(包括连续多个空格、Tab),行首行尾空格自动忽略
$9 == 500:Nginx combined 日志格式中$9是 HTTP 状态码,匹配 500 错误{print $4, $7, $1}:打印请求时间$4、URI 路径$7、客户端 IP$1head -20:只看前 20 条- 自定义分隔符:用
-F参数,如awk -F',' '{print $1}' file.csv - 注意:
==是精确匹配,不是正则匹配(正则用~)
用途:排查服务器 500 错误时,快速找出出错的请求时间、路径和来源 IP
21. Git 本地修改与远程同步(合并冲突实战)
本地修改后远程更新,本地修改会不会丢?
核心答案:本地修改不会丢,但取决于操作方式:
1. 同一目录用 git pull(正确做法)
git pull origin main会保留本地修改,尝试自动合并- 无冲突:本地修改 + 远程更新都在
- 有冲突:Git 提示,手动解决
2. 在新目录重新 clone
- 旧目录不动,新目录是干净版本
- 两个目录互不影响
3. ⚠️ 千万别这么干
- 在已有仓库目录再
git clone→ 报错 "destination path already exists" - 用
rm -rf清空再 clone → 修改全丢 - 绝对不要用删除旧目录的方式"重新 clone"
关键概念:
git clone是一次性的,把远程完整复制到本地- 本地仓库建立后,后续同步用
git pull(=git fetch+git merge) - 本地修改只要不删本地目录,永远都在
最佳实践:
git add . # 暂存
git commit -m "..." # 先提交本地修改(无需 push)
git pull # 再拉远程更新先 commit 再 pull,保证不丢任何东西。
pull 时遇到 CONFLICT(合并冲突实战)
报错解读:
Auto-merging KVM虚拟化/KVM虚拟化技术.md ← Git 试图自动合并
CONFLICT (content): Merge conflict in ... ← 但失败了:本地和远程改了同一段
Automatic merge failed; fix conflicts and then commit the result.
← 需要手动解决冲突再 commit原因: 本地和远程都改了同一个文件的同一段内容,Git 无法判断保留谁,必须手动选。
冲突文件标记: 打开冲突文件会看到:
<<<<<<< HEAD
你本地的修改内容
=======
远程最新的内容
>>>>>>> origin/main<<<<<<< HEAD~======== 你的版本=======~>>>>>>> origin/main= 远程版本
三种解决方式:
1. VSCode 编辑器(推荐) 打开冲突文件会高亮冲突区域,顶部按钮:
Accept Current Change→ 保留你的Accept Incoming Change→ 保留远程的Accept Both Changes→ 全部保留Compare Changes→ 对比查看
2. 手动编辑 删掉 <<<<<<<、=======、>>>>>>> 三个标记,保留需要的内容,保存。
3. 放弃合并回滚
git merge --abort # 取消合并,回到 pull 之前状态解决完提交:
git add . # 标记冲突已解决
git commit -m "解决 xxx.md 合并冲突" # 完成合并常用查看命令:
git status # 看哪些文件冲突
git diff # 看具体冲突内容
git log --oneline -5 # 看提交历史21.1 git config 查看当前配置(速查表)
查配置命令
# 1. 列出所有生效配置(按优先级从高到低输出)
git config --list
# 2. 推荐:每个值显示来源文件(一眼分清全局 / 仓库 / 系统)
git config --list --show-origin
# 3. 显示作用域(git 2.26+)
git config --list --show-scope
# 4. 按层级过滤
git config --list --local # 当前仓库 .git/config
git config --list --global # 用户级 ~/.gitconfig 或 ~/.config/git/config
git config --list --system # 系统级 /etc/gitconfig
# 5. 单项查询
git config user.name
git config user.email
# 6. 脚本里取值(未设置时返回非零退出码,便于判断)
git config --get user.name核心知识点:配置层级(高 → 低覆盖)
- 命令行参数(本次有效,
git -c user.name=x commit) --local→ 仓库.git/config--global→~/.gitconfig(新系统可能是~/.config/git/config)--system→/etc/gitconfig- 默认值(最低)
高层级覆盖低层级 —— 不会清空低层级,是叠加后再覆盖。同名 key 最终用最细的那条。
调试场景
- "明明全局设了 user.name,仓库里还是另一个人" →
git config --list --show-origin,看仓库层是否覆盖 - "想确认这个机器的 git 装在哪、版本" →
git --version+which git - "想批量改所有仓库的某项配置" → 用
--global,不要写到--system(影响其他用户)
写入 / 取消(顺手补)
git config --global user.name "你的名字"
git config --global user.email "your@email"
git config --local user.name "项目专用名" # 仅仓库内
git config --unset user.name # 取消当前仓库的设置
git config --global --unset user.name # 取消全局的设置
git config --global --edit # 直接打开 ~/.gitconfig 编辑22. stress-ng 压力测试工具
是什么
压力测试工具,可施加 CPU / 内存 / IO / 网络 等压力,常用于:
- 验证 Docker 资源限制(
-m、--cpus)是否生效 - 测试系统在极限负载下的表现
--vm 参数详解(重点)
核心理解: --vm 不是"虚拟内存"本身,是 vm 压力 worker 的数量。
--vm N:启动 N 个 vm 压力 worker--vm-bytes SIZE:每个 worker 占多少内存- 总占用 =
--vm×--vm-bytes
示例:
docker run tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
# 2 个 worker × 256MB = 512MB 总占用vm worker 反复写入内存,模拟"内存被疯狂使用"。
常用参数
| 参数 | 作用 | 默认 |
|---|---|---|
--vm N | vm worker 数量 | 0 |
--vm-bytes SIZE | 每个 worker 占用内存 | 256M |
--vm-hang N | 写完挂 N 秒再写 | 0 |
--vm-keep | 占着内存不释放 | - |
--cpu N | CPU 压力 worker(算素数) | 0 |
--io N | 磁盘 IO worker | 0 |
--timeout 60s | 跑 60 秒自动停 | 永久 |
Docker 资源限制验证示例
# 内存限制测试:-m 256m + 想用 512m → OOM
docker run -m 256m tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
# CPU 限制测试:--cpus 1 限制只用 1 核
docker run --cpus 1 tylersmith22/docker-stress-ng --cpu 1一句话总结
--vm = worker 数量,--vm-bytes = 每个 worker 内存大小 总内存压力 = --vm × --vm-bytes
💡 配合 Docker 资源限制:
-m是硬上限,设多少就是多少,超了直接 OOM kill。CPU 限制分硬(--cpus)和软(--cpu-shares)两种。详见 cloud.md §3.8。
23. lrzsz 文件传输工具(rz 上传 / sz 下载)
配合 Xshell / SecureCRT / WindTerm / tabby 等支持 Zmodem 协议的终端使用。
rz(上传)
rz
# 弹窗选本地文件上传到 LinuxReceived by zmodem —— 服务器接收客户端发来的文件。
sz(下载)
sz /path/file.txt
sz file1.txt file2.log
sz /path/*.log # 通配符Send to zmodem —— 服务器向客户端发送文件。
注意要跟文件名,不像 rz 直接回车。
sz 不支持目录下载
sz /etc/nginx/ # ❌ 报错:找不到文件
sz -y /etc/nginx/ # ❌ 也不行必须先打包再下载
# zip 包(Windows 用户友好)
cd /etc/nginx
zip -r nginx_conf.zip ./
sz nginx_conf.zip
# tar.gz 包(推荐,保留权限)
tar czf nginx_conf.tar.gz nginx/
sz nginx_conf.tar.gz收下之后 Linux 命令:
unzip nginx_conf.zip # 解 zip
tar xzf nginx_conf.tar.gz # 解 tar.gz常用参数
| 参数 | 作用 |
|---|---|
-y | 覆盖时不提示(默认会问 y/n) |
-b | 二进制传输(推荐,默认就行) |
-e | 转义所有控制字符(传输脚本常用) |
-v | 显示详细过程 |
-E | sz 专属:文件存在时强制覆盖 |
sz -y /var/log/messages # 强制覆盖,不问
sz -be script.sh # 二进制 + 转义控制字符
sz -Ey file.conf # 强制覆盖 + 二进制终端兼容性
sz/rz 默认只支持:
- ✅ Xshell、SecureCRT、PuTTY(Xmodem 扩展)
- ✅ tabby、WindTerm、MobaXterm
- ❌ Windows Terminal、iterm2 默认不支持
- 需要额外装 zmodem 脚本支持或者用别的终端
安装
# CentOS / RHEL
yum install -y lrzsz
# Debian / Ubuntu
apt install -y lrzsz24. Rocky Linux 配置网卡 IP(nmcli / NetworkManager)
来源:2026-07-18 交换区
Rocky Linux(RHEL 系)推荐用 NetworkManager 体系,三种方式:nmcli(命令行,生产推荐)、nmtui(图形菜单)、直接改配置文件。
核心概念:device vs connection
- device(网卡设备):物理/虚拟网卡本身,如
ens160 - connection(连接配置):网卡的配置档案,可与设备不同名
nmcli connection操作的是 connection,nmcli device操作的是设备
查网卡和连接
nmcli device status # 查看所有网卡设备
nmcli connection show # 查看所有连接
nmcli connection show "ens160" # 看 ens160 的现有配置nmcli 配置静态 IP(推荐)
# 1. 设置 IP + 子网掩码(CIDR 格式)
nmcli connection modify "ens160" ipv4.addresses 192.168.1.100/24
# 2. 设置网关
nmcli connection modify "ens160" ipv4.gateway 192.168.1.1
# 3. 设置 DNS(多个用空格分隔)
nmcli connection modify "ens160" ipv4.dns "223.5.5.5 8.8.8.8"
# 4. 把 ipv4 改为手动(manual),默认是 auto(DHCP)
nmcli connection modify "ens160" ipv4.method manual
# 5. 关闭 IPv6(可选)
nmcli connection modify "ens160" ipv6.method disabled
# 6. 让配置生效(推荐 up,不是重启网络)
nmcli connection up "ens160"modify只写入配置文件,不立即生效up才真正应用配置- 改完不需要
systemctl restart NetworkManager
重新读取配置(不改变连接状态)
nmcli connection reload "ens160"配置文件位置
nmcli modify 会写到下面两个位置之一:
- 新版(Rocky 9+ 默认):
/etc/NetworkManager/system-connections/ens160.nmconnection - 传统(兼容):
/etc/sysconfig/network-scripts/ifcfg-ens160
keyfile 格式示例
[connection]
id=ens160
type=ethernet
interface-name=ens160
[ipv4]
method=manual
address1=192.168.1.100/24,192.168.1.1
dns=223.5.5.5;8.8.8.8
[ipv6]
method=disable也可以直接
vi改这个文件,保存后跑nmcli connection reload+nmcli connection up "ens160"。
nmtui(图形菜单)
nmtui方向键选 "Edit a connection" → 选 ens160 → 改 IP/网关/DNS → OK → 退出。
适合不熟 nmcli 的场景,批量配置还是得用 nmcli。
临时 IP(重启失效,不写文件)
ip addr add 192.168.1.200/24 dev ens160
ip route add default via 192.168.1.1
ip link set ens160 up调试/排错时用,重启就没了。
验证
ip addr show ens160 # 看 IP
ip route # 看网关
nmcli -t -f IP4 connection show "ens160" # 看 NM 里的 IP 配置
ping 192.168.1.1 # 测网关
ping 223.5.5.5 # 测外网
cat /etc/resolv.conf # 看 DNS25. watch 命令(实时监控面板)
是什么
Linux 标准命令(来自 procps-ng 包),周期性执行同一个命令并全屏刷新输出 = 实时监控面板。
- 默认每 2 秒执行一次
- 不会滚屏,每次刷新整个屏幕
- 顶部默认显示
Every 2.0s: <command>+ 当前时间 - 退出:
Ctrl+C
常用参数
| 参数 | 作用 |
|---|---|
-n <秒> | 刷新间隔(覆盖默认 2s) |
-d / --differences | 高亮显示变化的部分 |
-t | 关闭顶部标题行 |
K8s 场景的经典用法
watch -n 1 kubectl get pod= 每 1 秒重跑 kubectl get pod 并全屏刷新。适合观察 Pod 状态从 Pending → ContainerCreating → Running 的过渡,或者看 Pod 被删除/重启。
教学常见套路:
- 滚动更新:
watch一边 +kubectl set image一边 → 看 Pod 一个个被替换 - Pod 删除:
watch一边 +kubectl delete pod一边 → 看新 Pod 被补上 - HPA 扩容:
watch一边 +ab -c 100压测一边 → 看 Pod 数量自动增加
watch vs kubectl -w 的区别
| 方式 | 行为 | 输出方式 |
|---|---|---|
watch -n 1 kubectl get pod | 定期重跑整个命令 | 每次重画整个表格 |
kubectl get pod -w | 只在有变化时输出新行 | 只追加变化行 |
- watch:看整个表(Status / READY / AGE 等所有列)
- kubectl -w:只看事件流(
Pod scheduled、Container started)
生产跟变化用 -w,教学盯表用 watch。
一句话速记
watch -n 1 <cmd> = 每 1 秒重画命令输出,实时监控面板。Ctrl+C 退出。-d 高亮变化。
相关记忆
- watch 默认 2s 刷新,-n 覆盖间隔
- watch 重画全表,kubectl -w 只追加变化行
- watch 来自 procps-ng 包(包含 ps、top、kill 等经典命令)