Linux 常见问题
本篇记录 Linux 系统维护中风险较高的问题。执行修改前应确认发行版、版本、启动方式和恢复入口,并保留当前会话或带外控制台。
如何安全升级 OpenSSH
推荐方案
优先使用发行版安全仓库提供的 OpenSSH 更新。发行版通常会将安全补丁回移到现有版本,版本号较旧并不等于漏洞未修复。
# RHEL 8/9、Rocky Linux、AlmaLinux
sudo dnf update openssh openssh-server openssh-clients
# Ubuntu / Debian
sudo apt update
sudo apt install --only-upgrade openssh-client openssh-server升级前后检查版本和服务状态:
ssh -V
sudo sshd -t
sudo systemctl status sshd --no-pagerUbuntu 和 Debian 的服务名通常是 ssh,RHEL 系列通常是 sshd。
远程操作的安全顺序
- 保留当前 SSH 会话,不要提前退出。
- 确认云控制台、IPMI、iDRAC 或虚拟机控制台可用。
- 备份
/etc/ssh/sshd_config和/etc/ssh/sshd_config.d/。 - 使用
sshd -t验证配置。 - 使用
reload重新加载配置,避免无必要的服务中断。 - 新开一个终端验证登录成功后,再关闭旧会话。
sudo cp -a /etc/ssh /etc/ssh.backup
sudo sshd -t
sudo systemctl reload sshd不要通过下面的方式“保护”升级过程:
- 不要开启明文 Telnet 服务;Telnet 默认使用 TCP 23 端口,认证信息不会加密。
- 不要先停止或卸载正在工作的 OpenSSH。
- 不要将源码编译结果直接覆盖
/usr/bin/ssh或/usr/sbin/sshd。 - 不要为方便测试开启 Root 密码登录。
如果合规扫描要求高于发行版提供的版本,应优先升级操作系统。确需源码构建时,应安装到独立前缀并创建单独的测试服务和端口,验证完成后再设计切换方案。
是否应该在原系统上升级 glibc
通常不应该。glibc 被 shell、SSH、systemd、包管理器和大量基础命令依赖,直接编译覆盖 /usr 中的系统版本可能让整台机器无法启动或维护。
| 需求 | 推荐方案 |
|---|---|
| 应用需要更新的 glibc | 使用与应用要求匹配的容器或基础镜像 |
| 老系统缺少安全更新 | 升级或迁移到受支持的发行版 |
| 编译测试新版本 | 安装到隔离目录,仅供测试程序显式加载 |
| 第三方二进制无法启动 | 向供应商索取兼容构建,或在匹配的运行环境中执行 |
排查二进制依赖时可使用:
ldd --version
ldd /path/to/program
readelf -l /path/to/program | grep interpreter不要使用 --disable-sanity-checks 绕过 glibc 构建检查,也不要直接替换 /lib64/libc.so.6。如果系统库已经损坏,应从同版本安装介质进入救援环境,通过包管理器恢复原发行版软件包。
Docker 容器端口如何限制来源地址
Docker 发布端口的流量通常经过 FORWARD 和 Docker 自建链,不一定经过普通的 INPUT 链。需要额外限制时可使用 DOCKER-USER 链,但应先理解当前防火墙后端和已有规则。
# 查看 Docker 用户链及命中计数
sudo iptables -L DOCKER-USER -n -v --line-numbersDocker 在规则到达 DOCKER-USER 前通常已完成 DNAT,因此 --dport 看到的可能是容器端口,而不是宿主机发布端口。如果二者不同,应使用 conntrack 匹配原始目标:
# 示例:只允许 10.108.11.178 访问宿主机发布的 TCP 1521 端口
sudo iptables -I DOCKER-USER 1 \
-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -I DOCKER-USER 2 \
-p tcp -s 10.108.11.178 \
-m conntrack --ctorigdstport 1521 -j ACCEPT
sudo iptables -I DOCKER-USER 3 \
-p tcp -m conntrack --ctorigdstport 1521 -j DROP这只是规则结构示例。生产环境还需确认 IPv6、多个 Docker 网络、规则持久化以及 firewalld/nftables 的集成方式。修改远程防火墙前应准备回滚命令和控制台入口。
Docker 代理、镜像构建和 NVIDIA 容器运行时属于 Docker 专题,不在 Linux QA 中重复维护。
如何调整和重新加载 Swap
vm.swappiness 控制内核使用 Swap 的倾向,取值为 0~200。它不是“剩余内存百分比”,也不表示设置为 0 后完全禁用 Swap。
# 查看当前值
sysctl vm.swappiness
# 临时调整
sudo sysctl vm.swappiness=10
# 写入独立配置文件并加载
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/90-swappiness.conf
sudo sysctl --system重新加载所有 Swap 前必须确认可用内存足够容纳当前已使用的 Swap,否则 swapoff -a 可能失败,甚至触发 OOM:
free -h
swapon --show
sudo swapoff -a
sudo swapon -a如何确认是否发生 OOM
OOM Killer 通常终止进程,不一定导致操作系统重启。优先查询当前和上一次启动的内核日志:
# 当前启动
sudo journalctl -k -g 'oom|out of memory|killed process' --no-pager
# 上一次启动
sudo journalctl -k -b -1 -g 'oom|out of memory|killed process' --no-pager
# 不使用 systemd-journald 的系统
dmesg -T | grep -Ei 'oom|out of memory|killed process'定位问题时重点记录:
- 被终止的进程名和 PID
anon-rss、file-rss、Swap 使用量- 进程是否位于容器或 systemd cgroup 中
- 是否配置了内存限制
- OOM 前后的业务流量和内存趋势
容器或服务可能触发 cgroup OOM,而不是整机 OOM。可以进一步查看:
systemctl status my-service
systemctl show my-service -p MemoryCurrent -p MemoryMax
docker inspect my-container --format '{{.HostConfig.Memory}}'仅看到 last reboot 记录不能证明 OOM 导致重启,还需要结合上一次启动的内核日志、硬件日志和云平台事件判断。
GRUB 损坏时如何恢复
GRUB 修复命令取决于启动模式、发行版、磁盘和分区布局,不能固定使用 /dev/sda。
修复前确认环境
在 Live 或 Rescue 环境中先收集信息:
lsblk -f
blkid
sudo fdisk -l
# 存在该目录通常表示当前救援环境以 UEFI 启动
test -d /sys/firmware/efi && echo UEFI || echo BIOS还需要确认:
- 根文件系统、
/boot和 EFI System Partition 分别位于哪里 - 是否使用 LVM、软件 RAID 或磁盘加密
- 原系统是 RHEL 系列还是 Debian/Ubuntu
- 当前启动的是 BIOS 还是 UEFI 模式
挂载并进入系统
下面仅展示通用结构,设备名必须替换为实际值:
sudo mount /dev/mapper/vg-root /mnt
sudo mount /dev/vda2 /mnt/boot
# UEFI 系统还需挂载 EFI System Partition
sudo mount /dev/vda1 /mnt/boot/efi
for path in /dev /dev/pts /proc /sys /run; do
sudo mount --bind "$path" "/mnt$path"
done
sudo chroot /mnt /bin/bash选择对应修复流程
- RHEL 系列 BIOS:通常重新安装
grub2-pc相关组件、执行grub2-install,再生成/boot/grub2/grub.cfg。 - RHEL 系列 UEFI:应恢复 EFI 版 GRUB 和 shim 软件包,并生成对应配置,不应对整块磁盘执行 BIOS 式安装。
- Ubuntu/Debian BIOS:通常重新安装
grub-pc并执行grub-install、update-grub。 - Ubuntu/Debian UEFI:应挂载 EFI 分区,重新安装
grub-efi-*和 shim,再执行update-grub。
具体命令应以发行版对应版本的救援文档为准。操作完成后退出 chroot,并按挂载顺序反向卸载:
exit
sudo umount -R /mntsudo 如何保留必要的环境变量
sudo -E 会请求保留调用者环境,但最终是否保留由 /etc/sudoers 的 env_reset、env_keep 和安全策略决定。它不会保证所有变量都被传递。
优先只传递当前命令需要的变量:
sudo HTTP_PROXY="$HTTP_PROXY" HTTPS_PROXY="$HTTPS_PROXY" command-name需要长期允许特定变量时,应使用 visudo 配置精确白名单,例如:
Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY"不要为了传递环境变量而习惯性执行 sudo -E /bin/bash,这会启动继承较多用户环境的 Root Shell,扩大误操作和环境注入风险。