开头先说几句掏心窝的话
兄弟们,如果你跟我一样,从CentOS 6一路用到CentOS 8,那你肯定经历过那种”说散就散”的痛。2021年12月31日,CentOS 8正式停服,那一刻多少运维老哥的ใจ都碎了一地。
我那时候就一个念头:”我那么多生产环境,难道要一个一个重新装?”
花了三个月时间,我把公司120台服务器从CentOS 8全部迁移到AlmaLinux 9,踩过无数坑,也总结出一套相对靠谱的迁移方案。今天就把所有细节掰开揉碎了讲给你听。
第一章:为什么选AlmaLinux?
1.1 选项对比
在决定迁移方案之前,我先把市场上主流的RHEL兼容发行版过了一遍:
| 发行版 | 创建时间 | 背景 | 活跃度 | 推荐度 |
|---|---|---|---|---|
| AlmaLinux | 2021.3 | CloudLinux团队 | ⭐⭐⭐⭐⭐ | 首选 |
| Rocky Linux | 2021.3 | CentOS创始人创建 | ⭐⭐⭐⭐⭐ | 次选 |
| Oracle Linux | 2021之前 | Oracle官方 | ⭐⭐⭐⭐ | 特定场景 |
| CentOS Stream | 2020 | RHEL上游 | ⭐⭐⭐ | 不推荐生产 |
我的选择逻辑:
- AlmaLinux 由CloudLinux团队维护,商业支持完善,有专门的SLA承诺
- Rocky Linux 虽然社区活跃,但初期社区稳定性稍逊
- CentOS Stream 是RHEL的上游,等于”滚动预览版”,生产环境不推荐
- Oracle Linux 需要绑定Oracle生态,灵活性差
说实话,AlmaLinux在社区投票和实际测试中表现更稳,特别是在RPM包兼容性方面,几乎跟RHEL 9完全一致。
第二章:迁移前的准备
2.1 服务器清单盘点
在动手之前,我花了一周时间做资产盘点,这是整个迁移中最容易被忽视但最重要的环节。
创建服务器清单脚本 inventory.sh:
#!/bin/bash
# 服务器资产盘点脚本
echo "=========================================="
echo "服务器资产盘点 - $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
echo ""
# 基本信息
echo "【基本信息】"
echo "主机名: $(hostname)"
echo "系统版本: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo "内核版本: $(uname -r)"
echo "IP地址: $(ip addr | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -1)"
echo "CPU核心数: $(nproc)"
echo "内存大小: $(free -h | grep Mem | awk '{print $2}')"
echo "磁盘使用: $(df -h / | tail -1 | awk '{print $5}')"
echo ""
# 运行服务
echo "【运行服务】"
systemctl list-units --type=service --state=running | grep -v '^●' | awk '{print $1}' | sed 's/\.service//' | sort
echo ""
# 监听端口
echo "【监听端口】"
ss -tlnp | grep LISTEN | awk '{print $4}' | cut -d':' -f2 | sort -n
echo ""
# 已安装的关键包
echo "【关键软件包】"
echo "Nginx版本: $(nginx -v 2>&1 | grep -oP '\d+\.\d+\.\d+' || echo '未安装')"
echo "MySQL版本: $(mysql --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo '未安装')"
echo "PostgreSQL版本: $(psql --version 2>/dev/null | grep -oP '\d+\.\d+' || echo '未安装')"
echo "PHP版本: $(php -v 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo '未安装')"
echo "Docker版本: $(docker --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo '未安装')"
echo ""
# 定时任务
echo "【定时任务】"
crontab -l 2>/dev/null || echo "无定时任务"
echo ""
# 挂载点
echo "【磁盘挂载】"
df -hT | grep -v '^Filesystem' | grep -v '^tmpfs'
echo ""
# 网络配置
echo "【网络配置】"
nmcli connection show | grep -E '^NAME'
echo ""
echo "盘点完成!"
执行清单:
chmod +x inventory.sh
./inventory.sh > inventory_$(hostname).log
2.2 业务依赖分析
每个服务都可能依赖特定的包版本,我做了个依赖关系表:
服务 依赖包 最低版本要求
-----------------------------------------------
Nginx nginx 1.20.0
MySQL mysql-server 8.0.28
PostgreSQL postgresql-server 13.0
Redis redis 6.2.0
Docker docker-ce 20.10.0
Node.js nodejs 16.0.0
Python python3 3.9.0
2.3 备份策略制定
备份是迁移成功的生命线。我采用了”三层备份”策略:
第一层:系统配置备份
#!/bin/bash
# 系统配置备份脚本
BACKUP_DIR="/backup/pre-migration-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"/{etc,packages,services,data}
echo "开始系统配置备份..."
# 备份/etc目录关键配置
echo "备份系统配置..."
tar czf "$BACKUP_DIR/etc/system-config.tar.gz" \
/etc/nginx /etc/my.cnf /etc/postgresql /etc/redis \
/etc/docker /etc/crontab /etc/yum.repos.d /etc/fstab \
/etc/selinux/config /etc/hostname /etc/sysctl.conf 2>/dev/null
# 备份已安装包列表
echo "备份安装包列表..."
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' \
| sort > "$BACKUP_DIR/packages/installed-packages.txt"
# 备份yum仓库配置
echo "备份yum仓库..."
cp -r /etc/yum.repos.d/ "$BACKUP_DIR/etc/yum.repos.d/"
# 备份服务状态
echo "备份服务状态..."
systemctl list-units --type=service --state=running \
> "$BACKUP_DIR/services/running-services.txt"
# 备份定时任务
echo "备份定时任务..."
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u "$user" -l > "$BACKUP_DIR/etc/crontab-$user.txt" 2>/dev/null
done
echo "系统配置备份完成!"
echo "备份路径: $BACKUP_DIR"
第二层:数据库备份
#!/bin/bash
# 数据库备份脚本
BACKUP_DIR="/backup/db-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
echo "开始数据库备份..."
# MySQL备份
echo "备份MySQL数据库..."
mysql_user="root"
mysql_pass="your_password"
mysql -u"$mysql_user" -p"$mysql_pass" -e "SHOW DATABASES;" \
| grep -Ev "^(Database|information_schema|performance_schema|mysql|sys)" \
| xargs -I{} mysqldump -u"$mysql_user" -p"$mysql_pass" --single-transaction --routines --triggers {} \
> "$BACKUP_DIR/{}.sql"
# PostgreSQL备份
echo "备份PostgreSQL数据库..."
psql -U postgres -c "\l" | grep -v "^(\|template\|postgres\|List)" \
| awk '{print $1}' \
| xargs -I{} pg_dump {} > "$BACKUP_DIR/{}.sql"
# Redis备份
echo "备份Redis数据..."
if command -v redis-cli &> /dev/null; then
redis-cli BGSAVE
sleep 2
cp /var/lib/redis/dump.rdb "$BACKUP_DIR/redis-dump.rdb" 2>/dev/null
fi
echo "数据库备份完成!"
echo "备份路径: $BACKUP_DIR"
# 验证备份文件
echo "备份文件清单:"
ls -lh "$BACKUP_DIR"
第三层:业务数据备份
#!/bin/bash
# 业务数据备份脚本
BACKUP_DIR="/backup/data-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
echo "开始业务数据备份..."
# Web应用数据
echo "备份Web应用..."
if [ -d "/var/www/html" ]; then
tar czf "$BACKUP_DIR/web-html.tar.gz" /var/www/html 2>/dev/null
fi
if [ -d "/var/www/vhosts" ]; then
tar czf "$BACKUP_DIR/web-vhosts.tar.gz" /var/www/vhosts 2>/dev/null
fi
# 用户上传文件
echo "备份用户上传文件..."
if [ -d "/data/uploads" ]; then
tar czf "$BACKUP_DIR/uploads.tar.gz" /data/uploads 2>/dev/null
fi
# 日志文件(可选)
echo "备份日志..."
if [ -d "/var/log" ]; then
tar czf "$BACKUP_DIR/logs.tar.gz" /var/log 2>/dev/null
fi
# 应用程序代码
echo "备份应用程序..."
if [ -d "/opt/app" ]; then
tar czf "$BACKUP_DIR/app.tar.gz" /opt/app 2>/dev/null
fi
echo "业务数据备份完成!"
echo "备份路径: $BACKUP_DIR"
# 计算备份大小
echo ""
echo "备份统计:"
du -sh "$BACKUP_DIR"
2.4 测试环境搭建
千万不要直接在生产环境动手! 我先找了两台闲置服务器搭建测试环境:
# 在测试环境安装AlmaLinux 9
#!/bin/bash
# 测试环境部署脚本
echo "开始部署测试环境..."
# 1. 下载AlmaLinux 9 ISO
curl -LO https://repo.almalinux.org/almalinux/iso/9.0/AlmaLinux-9-latest-x86_64-dvd1.iso
# 2. 创建虚拟机(使用KVM)
virt-install \
--name almalinux9-test \
--ram 4096 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/almalinux9-test.qcow2,size=50 \
--cdrom AlmaLinux-9-latest-x86_64-dvd1.iso \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial
# 3. 安装后配置
ssh root@<test-ip> << 'EOF'
# 配置Yum仓库
dnf install -y epel-release
dnf config-manager --set-enabled powertools
# 安装常用工具
dnf install -y nginx mysql-server postgresql-server redis docker
EOF
echo "测试环境部署完成!"
第三章:迁移方案详解
3.1 方案对比
我研究了三种迁移方案:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| In-Place升级 | 保留配置和数据 | 风险高,可能遗留问题 | 测试环境、非关键业务 |
| 干净重装 | 最稳定,无历史包袱 | 需要重新配置 | 生产环境首选 |
| 并排迁移 | 风险最低,可回滚 | 需要额外资源 | 大型集群、关键业务 |
我的推荐方案:并排迁移 + 数据同步
理由:
- 风险可控,新环境有问题可随时切回旧环境
- 可以充分测试后再切换
- 符合生产环境的”平稳过渡”原则
3.2 详细迁移步骤
步骤1:在新服务器上安装AlmaLinux 9
# 使用官方镜像安装
# 下载地址:https://repo.almalinux.org/almalinux/iso/9.0/
# 验证安装
cat /etc/os-release
# 应该输出:
# NAME="AlmaLinux"
# VERSION="9.0 (Seafoam Ocelot)"
# ID_alma="alma"
# 检查内核版本
uname -r
# 应该输出:5.14.x-111.x
步骤2:配置Yum仓库
#!/bin/bash
# AlmaLinux 9 Yum仓库配置
echo "配置Yum仓库..."
# 1. 安装EPEL仓库
dnf install -y epel-release
dnf install -y epel-next-release
# 2. 启用PowerTools仓库(AlmaLinux 9已改名为CRB)
dnf config-manager --set-enabled crb
# 3. 验证仓库状态
dnf repolist
# 应该看到:
# repo id repo name
# almalinux AlmaLinux 9 - BaseOS
# almalinux-plus AlmaLinux 9 - Plus
# almalinux-extras AlmaLinux 9 - Extras
# epel EPEL
# crb Code Ready Builder
# 4. 更新系统
dnf update -y
# 5. 安装常用工具
dnf groupinstall -y "Development Tools"
dnf install -y git vim curl wget net-tools bash-completion
步骤3:迁移系统配置
#!/bin/bash
# 系统配置迁移脚本
echo "开始迁移系统配置..."
# 1. 网络配置
echo "配置网络..."
# 复制网络配置(注意:CentOS 8使用nmcli,AlmaLinux 9也是,但配置路径不同)
# CentOS 8: /etc/sysconfig/network-scripts/ifcfg-*
# AlmaLinux 9: /etc/sysconfig/network-scripts/ifcfg-* (兼容)
# 2. 主机名配置
echo "配置主机名..."
hostnamectl set-hostname your-new-hostname
echo "127.0.0.1 $(hostname)" > /etc/hosts
echo "$(hostname)" > /etc/hostname
# 3. 时间同步
echo "配置时间同步..."
dnf install -y chrony
systemctl enable chronyd
systemctl start chronyd
timedatectl set-timezone Asia/Shanghai
# 4. SELinux配置
echo "配置SELinux..."
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
setenforce 1
# 5. 防火墙配置
echo "配置防火墙..."
dnf install -y firewalld
systemctl enable firewalld
systemctl start firewalld
# 开放常用端口
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
# 6. 系统参数优化
echo "优化系统参数..."
cat > /etc/sysctl.d/99-optimization.conf << 'EOF'
# 网络优化
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 32768
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 文件描述符
fs.file-max = 65535
fs.nr_open = 65535
# 内存优化
vm.swappiness = 10
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
EOF
sysctl -p /etc/sysctl.d/99-optimization.conf
# 7. 用户和权限配置
echo "配置用户..."
# 复制用户组(注意:不要复制密码,需要重新设置)
getent group | awk -F: '{print $1":"$3}' > /tmp/groups.txt
while IFS=: read -r line; do
group_name=$(echo "$line" | cut -d: -f1)
group_id=$(echo "$line" | cut -d: -f2)
groupadd -g "$group_id" "$group_name" 2>/dev/null
done < /tmp/groups.txt
# 复制用户(同样注意密码需要重置)
getent passwd | awk -F: '{print $1":"$3":"$4":"$5":"$6":"$7}' > /tmp/users.txt
while IFS=: read -r line; do
username=$(echo "$line" | cut -d: -f1)
uid=$(echo "$line" | cut -d: -f2)
gid=$(echo "$line" | cut -d: -f3)
home=$(echo "$line" | cut -d: -f6)
shell=$(echo "$line" | cut -d: -f7)
useradd -u "$uid" -g "$gid" -d "$home" -s "$shell" "$username" 2>/dev/null
mkdir -p "$home"
done < /tmp/users.txt
echo "系统配置迁移完成!"
