CentOS 8停服后企业服务器如何平稳迁移到AlmaLinux 9并避免兼容性问题 测试数据表明多数应用升级后无需代码修改即可正常运行 本文详细记录迁移前后的配置变更与故障排查过程 为运维团队提供可直接复用的升级方案 帮助企业在2025年底前完成CentOS生态过渡 避免服务中断风险
最近不少同事都在问我,CentOS 8都停服半年了,咱们还在上面跑的这些服务到底该怎么搬?说实话,这个问题我帮至少五家企业处理过,有些走得顺,有些确实踩了坑。今天就把整个迁移过程、遇到的问题还有怎么避坑,掰开了揉碎了讲清楚。
先说结论——如果你跑的是主流业务应用,比如Nginx、MySQL、Redis、Docker这些,AlmaLinux 9基本可以做到无缝迁移,连配置文件都不用改。但前提是,你得做好迁移前的全面体检,不能抱着”跑得了和尚跑不了庙”的侥幸心理直接上手。
为什么要迁移,现在还有多少犹豫空间?
CentOS 8在2021年12月就已经停止维护了,官方给了三年的过渡期,但很多企业的服务器就是拖着不动。现在回头看,拖得越久的风险越大——没有安全补丁、没有软件更新、出了问题没人兜底。更重要的是,很多云服务商和应用厂商开始逐步取消对CentOS 8的原生支持,你到时候想装个新软件可能都装不上。
AlmaLinux和Rocky Linux是目前CentOS的两大替代选择,都继承了CentOS的RHEL兼容基因,包管理、系统命令、服务管理几乎一模一样。选哪个都行,这边我统一用AlmaLinux 9来讲,毕竟我手头案例都是这个。
迁移前的准备:别急着动手,先把家底盘清楚
很多团队迁移翻车,不是因为技术不行,是因为没搞清楚自己的环境到底长什么样。我给你一个我在客户那里常用的检查清单,照着跑一遍心里就有数了。
先看看有哪些服务器还在跑CentOS 8:
# 批量检查网络中CentOS 8主机
for ip in $(cat server_list.txt); do
if ssh -o ConnectTimeout=5 -o BatchMode=yes root@$ip "cat /etc/os-release | grep 'CentOS Linux 8'" 2>/dev/null; then
echo "$ip 需要迁移" >> need_migrate.txt
fi
done
cat need_migrate.txt
接下来要重点排查几个高风险点。第一个是内核相关服务,比如一些自定义的内核模块或者依赖特定内核版本的软件:
# 检查自定义内核模块
lsmod | grep -v "^Module"
echo "---"
# 检查DKMS驱动
dkms status 2>/dev/null
echo "---"
# 检查与内核版本强绑定的服务
rpm -qa | grep kernel
uname -r
第二个是软件源依赖。有些老系统会配一些第三方的yum源,比如某些公司内部的私有源或者已经挂掉的开源镜像,这些在AlmaLinux 9上肯定不兼容,必须提前清理掉:
# 导出所有已配置的yum源
cat /etc/yum.repos.d/*.repo
echo "==="
# 检查第三方源
ls /etc/yum.repos.d/ | grep -v "almalinux\|centos\|base\|epel"
echo "==="
# 检查已安装的第三方rpm包
rpm -qa | grep -E "remi|webtatic|atrpms|nux"
第三个最容易被忽视——系统级的自定义配置。比如crontab里有没有定时任务在跑老版本的脚本,systemd服务有没有自己写的unit文件,或者/etc/rc.local里有没有开机自启的命令:
# 检查自定义systemd服务
ls /etc/systemd/system/ | grep -v ".wants\|.requires\|.d"
echo "==="
# 检查crontab
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u $user -l 2>/dev/null | grep -v "^#" | grep -v "^$" && echo "--- user: $user ---"
done
echo "==="
# 检查/etc/rc.local
cat /etc/rc.local 2>/dev/null
echo "==="
# 检查profile.d里的自定义脚本
ls /etc/profile.d/
把这些都摸清了,你才能知道迁移的难点在哪里。我见过最坑的一个案例,是一家电商公司的服务器上有台跑着十年老代码的机器,里面有个用Perl写的脚本通过crontab每分钟跑一次,依赖的是CentOS 8上某个特定的Perl模块版本,迁移完才发现这个模块在AlmaLinux 9上名字都不一样了。这种问题提前检查能省掉半夜被报警叫醒的烦恼。
迁移工具的选择:leapp是不是万能的?
官方推荐的迁移工具是leapp,它是Red Hat生态里专门做版本升级的。但说实话,用过的都知道,leapp不靠谱的地方也不少。我给你对比一下两种主流方案。
第一种是leapp在体升级。命令很简单:
# 安装leapp升级工具
dnf install -y leapp leapp-upgrade leapp-ui
# 预检查(这一步很关键,它会告诉你哪些地方会出问题)
leapp preupgrade
# 查看预检查结果
leapp preupgrade --answer-missing answers.json
预检查通过后再执行升级:
# 执行升级
leapp upgrade
# 重启进入升级模式
reboot
这个流程看着挺美,但我必须说几个真实的踩坑点。第一个,leapp对Python版本很敏感,如果你的系统上Python脚本引用了旧版本的路径,升级后可能直接报找不到解释器的错误。第二个,一些自定义的systemd服务在升级过程中可能没有被正确处理,升级完发现服务起不来,还得手动调。第三个,leapp的日志文件有时候会把你绕晕,报错信息不够直白。
第二种方案其实更稳妥,就是新建一台AlmaLinux 9的服务器,然后把数据和配置慢慢迁过去。这种方式看起来麻烦,但可控性高得多,出了问题直接回滚到旧服务器,不影响线上业务:
# 在新AlmaLinux 9服务器上配置基础环境
# 1. 配置dnf源(使用阿里云镜像)
curl -o /etc/yum.repos.d/AlmaLinux.repo https://mirrors.aliyun.com/repo/AlmaLinux-9.repo
# 2. 更新系统
dnf update -y
# 3. 安装基础工具
dnf install -y epel-release
dnf install -y vim net-tools wget curl git rsync
# 4. 配置防火墙
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
数据迁移的具体操作
如果是业务系统迁移,关键就是几个部分:数据文件、配置文件、日志文件。我用rsync来做增量同步,这样在切换前可以反复同步几次,保证数据一致性:
# 第一次全量同步(迁移前一周做)
rsync -avz --progress \
--exclude='/proc' \
--exclude='/sys' \
--exclude='/dev' \
--exclude='/tmp' \
--exclude='/var/log' \
--exclude='/var/cache' \
/data/ root@new-server:/data/
# 业务低峰期再做一次增量同步(迁移前一刻做)
rsync -avz --delete --progress \
--exclude='/proc' \
--exclude='/sys' \
--exclude='/dev' \
--exclude='/tmp' \
--exclude='/var/log' \
--exclude='/var/cache' \
/data/ root@new-server:/data/
配置文件迁移也有讲究。不是所有配置文件都能直接拷过去,有些路径在AlmaLinux 9上可能有变化:
# 对比新旧系统的配置差异
diff /etc/nginx/nginx.conf /etc/nginx/nginx.conf.new
diff /etc/my.cnf /etc/my.cnf.new
diff /etc/redis/redis.conf /etc/redis/redis.conf.new
我发现一个规律,绝大多数主流应用的配置文件在CentOS 8和AlmaLinux 9之间是完全兼容的。MySQL、Nginx、Redis这些,直接拷过去就行。但有些老应用可能会有问题,比如某些基于旧版glibc编译的二进制程序,或者依赖了特定版本系统库的应用。
迁移后的验证清单
新服务器上线不代表结束,验证才是最重要的环节。我给你整理了一套我在客户那边实际用的验证脚本,覆盖了服务状态、端口监听、关键业务接口和健康检查:
#!/bin/bash
# migration_check.sh - 迁移后验证脚本
echo "=== 系统信息 ==="
cat /etc/os-release
echo "内核版本: $(uname -r)"
echo ""
echo "=== 关键服务状态 ==="
for service in nginx mysql redis docker; do
if systemctl is-active --quiet $service 2>/dev/null; then
echo "✓ $service 运行中"
else
echo "✗ $service 异常: $(systemctl status $service 2>&1 | tail -3)"
fi
done
echo ""
echo "=== 端口监听检查 ==="
ss -tlnp | grep -E ':(80|443|3306|6379|8080|8443)\s'
echo ""
echo "=== 磁盘使用情况 ==="
df -h | grep -E 'Filesystem|/dev/'
echo ""
echo "=== 内存使用 ==="
free -h
echo ""
echo "=== 进程检查 ==="
ps aux | grep -E '(nginx|mysql|redis|docker)' | grep -v grep | wc -l
echo "个相关进程在运行"
echo ""
echo "=== 关键日志错误 ==="
tail -20 /var/log/messages | grep -i error
tail -20 /var/log/secure | grep -i error
echo ""
echo "=== 业务接口健康检查 ==="
curl -s -o /dev/null -w "%{http_code}" http://localhost:80/health
echo " <- HTTP健康检查"
curl -s -o /dev/null -w "%{http_code}" https://localhost:443/health
echo " <- HTTPS健康检查"
mysql -u root -e "SELECT 1" 2>/dev/null && echo "✓ MySQL可连接" || echo "✗ MySQL连接失败"
redis-cli ping 2>/dev/null && echo "✓ Redis可连接" || echo "✗ Redis连接失败"
把这个脚本跑一遍,如果大部分都打钩了,说明迁移基本成功。
真实踩坑案例:一个让人头疼的兼容性问题
说一个真实的例子,是一家物流公司的ERP系统。他们的系统是用Java写的,但底层依赖了一个叫libssl的组件,而且这个组件是他们自己编译的,版本号是1.0.2k。AlmaLinux 9默认的OpenSSL是3.0版本,直接不兼容。
迁移后启动ERP应用报错:
Error: /lib64/libssl.so.10: version 'OPENSSL_1.0.2' not found
Error: /lib64/libcrypto.so.10: version 'OPENSSL_1.0.2' not found
排查思路是这样的——先确认到底是哪个程序在报这个错,然后看这个程序依赖的具体是哪个库:
# 找出哪个进程依赖了老版本的openssl
ldd $(which java) | grep ssl
echo "==="
# 查看系统上有哪些openssl相关包
rpm -qa | grep openssl
echo "==="
# 查看libssl.so.10是否存在
ls -la /lib64/libssl.so*
echo "==="
# 找出哪些包提供了libssl.so.10
rpm -qf /lib64/libssl.so.10 2>/dev/null || echo "未找到所属包"
解决方案是给AlmaLinux 9安装openssl1.1的兼容包:
# 启用AppStream仓库中的openssl1.1
dnf module list | grep openssl
dnf install -y openssl1.1 openssl1.1-devel
安装完之后再验证一下:
# 验证openssl1.1是否安装成功
ls -la /usr/lib64/openssl1.1/libssl.so*
ls -la /usr/lib64/openssl1.1/libcrypto.so*
echo "==="
# 为ERP系统创建软链接(如果它期望的是旧路径)
ln -sf /usr/lib64/openssl1.1/libssl.so.1.1 /usr/lib64/libssl.so.10
ln -sf /usr/lib64/openssl1.1/libcrypto.so.1.1 /usr/lib64/libcrypto.so.10
echo "==="
# 测试ERP系统是否能正常启动
systemctl restart erp-system
systemctl status erp-system
这个问题解决后,我还建议他们后续想办法把那个自编译的OpenSSL组件换成官方版本,因为依赖私有编译的库迟早是个定时炸弹。
还有一个容易被忽略的细节:SELinux
CentOS 8和AlmaLinux 9的SELinux策略有一些差异,尤其是默认策略从targeted升级到了更严格的配置。迁移后如果发现有些应用启动失败或者访问被拒绝,大概率是SELinux在作怪:
# 检查SELinux状态
getenforce
sestatus
echo "==="
# 查看SELinux审计日志中的拒绝记录
ausearch -m avc -ts recent
echo "==="
# 如果需要临时排查,可以切换到permissive模式(记得排查完改回去)
setenforce 0
# 复现问题后查看具体拒绝原因
ausearch -m avc -ts recent
# 问题确认后再切回enforcing
setenforce 1
有些应用会有自己的SELinux策略文件,迁移前最好备份一下:
# 备份当前的SELinux策略
semanage export | grep -v "^#" > selinux_policy_backup.txt
# 查看自定义的SELinux上下文
ls -laZ /etc/nginx/
ls -laZ /var/www/
迁移后的性能调优
从CentOS 8到AlmaLinux 9,内核从4.18升级到了5.14,性能其实是有提升的,但需要做一些参数调整才能充分发挥。比如TCP连接参数、文件描述符限制这些:
# 优化TCP连接参数
cat >> /etc/sysctl.d/99-network-optimize.conf << 'EOF'
# TCP连接优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
# 文件描述符优化
fs.file-max = 655350
fs.nr_open = 655350
# 内存优化
vm.swappiness = 10
vm.dirty_ratio = 5
vm.dirty_background_ratio = 2
EOF
sysctl --system
# 调整文件描述符限制
cat >> /etc/security/limits.d/99-nofile.conf << 'EOF'
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535
EOF
还有一个很多人不知道的优化点——AlmaLinux 9默认启用了PowerTOP的自动调优,对于服务器场景可能不太合适,可以根据实际情况调整:
# 检查powertop状态
systemctl status tuned
# 切换到throughput-performance模式
tuned-adm profile throughput-performance
# 或者保持默认
tuned-adm active
给你的迁移时间表建议
别想着一次性把所有服务器都搬完,那样风险太大。我给你一个分阶段迁移的建议节奏:
第一阶段,先把那些非核心的、可以停服的测试机和开发机搬过去。这个阶段主要目的是验证迁移流程是否顺畅,让团队积累实际操作经验。
第二阶段,迁移边缘业务系统,比如内部工具、监控服务器、日志收集节点这些。即使出了问题,影响范围也有限。
第三阶段,才是核心业务系统。这时候你的团队已经跑通了两轮迁移,对可能出现的问题有了预案,迁移起来会稳很多。
每一阶段之间留至少一周的缓冲期,用来观察新系统的稳定性,也给自己时间复盘和修正流程。
最后说几句
迁移这件事,技术上其实不难,难的是管理和风险管控。我见过太多团队因为急于完成迁移任务,跳过了预检查环节,结果上线后才发现一堆问题,反过来又得倒回去改,反而更浪费时间。
现在距离2025年底还有一段时间,但如果你的服务器还在CentOS 8上裸奔,真的该提上日程了。提前规划、分阶段执行、做好验证,这条路走得稳,就不会有什么大坑。
如果你在执行过程中遇到什么具体问题,随时可以聊聊,每个企业的实际情况都不一样,但很多坑是共通的,踩过的路别人不用再走一遍。
