第 13 章:故障排查
第 13 章:故障排查
常见问题诊断与解决方法、musl 兼容性处理和系统调试技巧。
13.1 musl 兼容性问题
常见错误及解决
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
No such file or directory | 程序链接 glibc 动态链接器 | 安装 gcompat 或重编译 |
Error relocating: symbol not found | glibc 专有符号 | 安装 gcompat |
Segmentation fault | glibc 二进制不兼容 | 使用容器隔离或重编译 |
DNS resolution failed | musl DNS 实现差异 | 检查 resolv.conf |
gcompat 兼容层
# 安装 glibc 兼容层
apk add gcompat
# 设置 glibc 链接器路径
export LD_LIBRARY_PATH=/lib64:/usr/lib64
# 验证 glibc 程序运行
ldd /path/to/glibc/binary
# 应显示 /lib64/ld-linux-x86-64.so.2
# 常见需 gcompat 的软件
# - Steam
# - 某些 Electron 应用
# - 部分商业软件
# - 某些预编译二进制
DNS 解析问题
# musl 的 DNS 解析行为与 glibc 不同
# musl 不支持 nsswitch.conf 的复杂配置
# 问题:某些程序无法解析主机名
# 解决:检查 /etc/resolv.conf
cat /etc/resolv.conf
# 确保包含有效的 nameserver
# 问题:DNS 超时
# musl 默认不支持 search 域的复杂解析
# 解决方案:
echo "options single-request-reopen" >> /etc/resolv.conf
# 问题:IPv6 DNS 解析问题
# musl 优先尝试 IPv6
# 解决:
echo "options single-request" >> /etc/resolv.conf
# DNS 调试
apk add bind-tools
dig example.com +trace
nslookup example.com 8.8.8.8
字符编码问题
# musl 的 locale 支持有限
# 默认只有 C/POSIX locale
# 安装 locale 支持
apk add musl-locales
# 设置 locale
export MUSL_LOCPATH=/usr/share/i18n/locales/musl
export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8
# 查看可用 locale
ls /usr/share/i18n/locales/musl/
# 持久化配置
cat >> /etc/profile.d/locale.sh << 'EOF'
export MUSL_LOCPATH=/usr/share/i18n/locales/musl
export LANG=zh_CN.UTF-8
EOF
静态链接解决兼容性
# 编译静态链接的程序,避免运行时依赖
# C/C++
gcc -static -o myapp myapp.c
# 或使用 musl-gcc
musl-gcc -static -o myapp myapp.c
# Go
CGO_ENABLED=0 go build -o myapp .
# Rust
cargo build --release --target x86_64-unknown-linux-musl
# 检查静态链接
file myapp
# 应显示 "statically linked"
ldd myapp
# 应显示 "not a dynamic executable"
13.2 启动问题排查
引导失败
# 1. 从 Live CD 启动
# 2. 挂载根分区
mount /dev/sda2 /mnt
mount /dev/sda1 /mnt/boot
# 3. chroot 进入系统
chroot /mnt /bin/sh
# 4. 检查关键配置
cat /etc/fstab # 检查文件系统配置
cat /etc/network/interfaces # 检查网络配置
cat /etc/conf.d/* # 检查服务配置
# 5. 检查内核和 initramfs
ls -la /boot/
# 6. 重新安装引导
extlinux --install /boot
dd if=/usr/share/syslinux/mbr.bin of=/dev/sda bs=440 count=1
# 7. 检查文件系统
fsck /dev/sda2
服务启动失败
# 查看服务状态
rc-service nginx status
# 查看服务日志
tail -100 /var/log/messages | grep nginx
# 手动启动服务查看错误
nginx -t # 测试配置文件语法
nginx # 前台运行查看输出
# 详细日志模式
# /etc/init.d/nginx
# 在 start 函数前添加:
# set -x
# 检查依赖
rc-service -D nginx # 显示依赖树
# 重建服务依赖
rc-update --update
13.3 网络问题排查
网络诊断流程
# 1. 检查接口状态
ip link show
# 确保接口 UP
# 2. 检查 IP 地址
ip addr show
# 确保有正确 IP
# 3. 检查路由
ip route show
# 确保有默认路由
# 4. 测试本地连通性
ping 127.0.0.1
ping <网关IP>
# 5. 测试外网连通性
ping 8.8.8.8
# 6. 测试 DNS
nslookup example.com
dig @8.8.8.8 example.com
# 7. 测试端口连通性
nc -zv example.com 80
curl -v https://example.com
# 8. 检查防火墙规则
iptables -L -n -v
iptables -L -n -v -t nat
常见网络问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 无 IP 地址 | DHCP 失败 | 检查网络配置、DHCP 服务 |
| 有 IP 无网络 | 路由/DNS 问题 | 检查路由表和 resolv.conf |
| DNS 解析失败 | DNS 配置错误 | 检查 /etc/resolv.conf |
| 端口无法访问 | 防火墙阻止 | 检查 iptables 规则 |
| 连接超时 | MTU 问题 | 降低 MTU 值 |
抓包分析
# 安装 tcpdump
apk add tcpdump
# 抓取 HTTP 流量
tcpdump -i eth0 -nn port 80 -A
# 抓取 DNS 查询
tcpdump -i eth0 -nn port 53
# 保存到文件分析
tcpdump -i eth0 -nn -w /tmp/capture.pcap
# 安装 Wireshark CLI
apk add tshark
tshark -r /tmp/capture.pcap
13.4 性能问题排查
CPU 问题
# 查看 CPU 使用率
top -bn1 | head -20
htop # 需安装
# 查看每个 CPU 核心
mpstat -P ALL 1 5 # 需安装 sysstat
# 进程 CPU 使用率排序
ps aux --sort=-%cpu | head -10
# CPU 密集型进程追踪
strace -c -p <PID> # 统计系统调用
perf top # 性能分析(需安装)
内存问题
# 内存使用概览
free -h
# 详细内存信息
cat /proc/meminfo
# 进程内存使用排序
ps aux --sort=-%mem | head -10
# 查看进程内存映射
cat /proc/<PID>/smaps
# 内存泄漏检测
apk add valgrind
valgrind --leak-check=full ./myapp
磁盘 IO 问题
# IO 统计
iostat -x 1 5 # 需安装 sysstat
# 查看 IO 最多的进程
iotop # 需安装 iotop
# 磁盘使用检查
df -h
du -sh /* | sort -h | tail -10
网络性能
# 带宽测试
apk add iperf3
# 服务端
iperf3 -s
# 客户端
iperf3 -c <服务端IP>
# 延迟测试
ping -c 100 <目标IP> | tail -1
# 连接数统计
ss -s
ss -tlnp | wc -l
13.5 日志分析
# 系统日志
tail -f /var/log/messages
# 认证日志
grep "Failed password" /var/log/messages
grep "Accepted publickey" /var/log/messages
# 内核日志
dmesg | tail -50
dmesg -T | grep -i error # 带时间戳
# 服务特定日志
journalctl -u nginx # 如果有 systemd
# 日志分析脚本
cat > /usr/local/bin/log-analyzer << 'SCRIPT'
#!/bin/sh
echo "=== 最近登录失败 ==="
grep "Failed" /var/log/messages 2>/dev/null | tail -10
echo ""
echo "=== 最近错误 ==="
grep -i "error\|critical\|fatal" /var/log/messages | tail -10
echo ""
echo "=== 磁盘空间 ==="
df -h | grep -E '^/dev' | awk '{print $5, $6}'
echo ""
echo "=== 内存使用 ==="
free -h
echo ""
echo "=== 负载 ==="
uptime
SCRIPT
chmod +x /usr/local/bin/log-analyzer
13.6 容器故障排查
# Docker 容器无法启动
docker logs <container>
docker inspect <container>
# 进入运行中的容器
docker exec -it <container> sh
# 进入已停止的容器
docker run -it --rm --entrypoint sh <image>
# 检查容器资源
docker stats <container>
docker inspect --format='{{.State.Pid}}' <container>
cat /proc/<PID>/cgroup
# 网络问题
docker network inspect <network>
docker exec <container> ping <host>
docker exec <container> cat /etc/resolv.conf
# 存储问题
docker exec <container> df -h
docker system df
docker system prune -a
13.7 包管理问题
# 错误: ERROR: unsatisfiable constraints
# 原因: 包依赖冲突
# 解决:
apk update
apk add --simulate package-name # 预览安装
apk fix package-name # 尝试修复
# 错误: unable to select packages
# 原因: 包名错误或不在当前仓库
apk search keyword # 搜索正确包名
cat /etc/apk/repositories # 检查仓库配置
# 错误: BAD signature
# 原因: 密钥过期或损坏
apk update --allow-untrusted # 不推荐,仅调试
# 正确方式:更新密钥
apk fix --upgrade alpine-keys
apk update
# 缓存损坏
rm -rf /var/cache/apk/*
apk update
13.8 调试工具速查
| 工具 | 安装命令 | 用途 |
|---|---|---|
| strace | apk add strace | 系统调用追踪 |
| ltrace | apk add ltrace | 库函数追踪 |
| gdb | apk add gdb | 程序调试 |
| ldd | 内置 | 查看动态库依赖 |
| file | 内置 | 文件类型识别 |
| readelf | 内置 | ELF 文件分析 |
| objdump | apk add binutils | 二进制分析 |
| tcpdump | apk add tcpdump | 网络抓包 |
| perf | apk add linux-tools | 性能分析 |
| valgrind | apk add valgrind | 内存检测 |
13.9 常见问题 FAQ
Q: 为什么 glibc 编译的程序在 Alpine 上运行报 “No such file or directory”?
A: 程序的 ELF 解释器指向 /lib64/ld-linux-x86-64.so.2(glibc),而 Alpine 使用 /lib/ld-musl-x86_64.so.1。解决:安装 gcompat 或重新编译。
Q: 如何在 Alpine 上运行 Ubuntu 的 deb 包? A: 不推荐。应寻找 Alpine 原生包或源码编译。必要时可使用容器运行 Ubuntu 环境。
Q: Docker 中使用 Alpine 时 musl 导致的问题?
A: 使用多阶段构建,在 Alpine 环境中编译程序;或使用 gcompat 包;或静态链接编译。
Q: 如何调试 OpenRC 服务?
A: 使用 rc-service <name> -d start(调试模式),或直接运行服务命令查看输出。
13.10 故障排查清单
- 确认 Alpine 版本:
cat /etc/alpine-release - 检查系统日志:
tail -100 /var/log/messages - 检查磁盘空间:
df -h - 检查内存:
free -h - 检查网络:
ip addr show && ip route show - 检查 DNS:
nslookup example.com - 检查防火墙:
iptables -L -n - 检查服务状态:
rc-status - 检查最近更新:
apk version -l '<'
扩展阅读
上一章:第 12 章:系统加固 下一章:第 14 章:嵌入式应用