CommunityCodierung & Entwicklunggithub.com

CentOS 7 → AlmaLinux 10 原地升级

在单个服务器或整个集群上,将老旧 CentOS 7 / CentOS 8(及 RHEL 7/8 系列)服务器安全地原地升级到最新的 AlmaLinux 10,确保业务、容器、nginx、kubectl 等组件在升级后正常工作。

Was ist CentOS 7 → AlmaLinux 10 原地升级?

该技能提供了一套经过生产验证的流程,用于将 CentOS 7 或 CentOS 8 服务器原地升级到 AlmaLinux 10。它实现了优雅的升级路径——对于 CentOS 7 用户,通过 ELevate 工具逐步升级 (7→8→9→10);对于 CentOS 8 用户,则使用 almalinux-deploy 先转换为 AlmaLinux 8,再继续升级。该流程包含一套全面的脚本工具(survey.sh 用于勘察、backup.sh 用于创建基线、hop.sh 用于执行升级步骤等),旨在确保安全、可回滚的升级,并强制进行关键的前期检查,例如云快照、停机窗口、带外控制和访问路径审查。该技能支持单机部署和批量部署(通过 fleet_summary.py),并强调在每次升级步骤后验证基线,以立即发现并修复问题(如 cgroup 版本差异或 Docker Compose 兼容性)。它特别针对中国云环境(阿里云、华为云)的挑战进行了优化,例如使用国内镜像源以避免限速问题,并包含了处理常见问题的详细参考文档(pitfalls.md、app-compat.md、recovery.md)。

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/seaworld008/centos7-lighthouse/tree/HEAD/skills/centos7-almalinux-upgrade

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht CentOS 7 → AlmaLinux 10 原地升级?

这是一次真实生产迁移(华为云跳板机,CentOS 7.7 → AlmaLinux 10.2,nginx/Docker/xxl-job/MySQL/NetBird/kubectl 全部保住)沉淀下来的流程。目标是每台机器都能安全、可回滚、可验证地升上去,同时能批量推进。

核心思路:先摸清 → 快照兜底 → 每跳小步走(预检→升级→重启→对比基线→收尾)→ 最后现代化。坑几乎都出在"非官方的东西"上(自编译程序、pip 包、第三方源、自打包 openssh、容器重启策略、VPN 访问路径),所以勘察阶段的价值最大。

什么时候不要原地升级

先看 survey.sh 的 BLOCKER。以下情况建议新建 AlmaLinux 10 机器迁移业务,而不是原地升级:

  • 是 Kubernetes 节点(kubelet 在跑)——要当成集群级变更来做,按 references/kubernetes.md(已实测 kubeadm 1.21 + dockershim + flannel/ipvs 在 EL10 上可用,3m3w 集群约 6 小时);也可以 drain 后换新节点
  • 宿主机 rpm 装的数据库要跨多个大版本(MariaDB 5.5→10.11、PostgreSQL 9.2→16)且数据量大
  • 非 x86_64、btrfs、系统盘极小且无法扩容
  • CPU 不支持 x86-64-v3(AlmaLinux 10 标准版跑不了;可以只升到 9,或用 AlmaLinux 10 的 x86_64_v2 变体)
  • 业务本身就是容器化的、配置都在 compose/k8s 里——新建机器重新部署往往比原地升级更快

拿不准时把判断依据告诉用户,让用户选。

工具包

技能目录 scripts/ 下(全部在本机经 SSH 上传到目标机 /root/os-upgrade-kit/ 执行):

脚本作用
remote.py本机运行:从资产表(xlsx/csv)取凭据,SSH 执行命令/上传/下载/等待重启;开了 keepalive;不打印密码
survey.sh只读勘察,末尾输出分级 RISK FLAGS(BLOCKER/HIGH/MEDIUM/INFO)
backup.sh备份配置 + 生成业务基线 baseline.tsv(服务/端口/容器/各域名 HTTP 码/kubectl)
state.sh / verify.sh生成当前状态 / 与基线对比,输出 FAIL/WARN
prep-el7.shEL7 准备:repos 修源、update 到 7.9、pipfix、inhibitors
convert-el8.sh源系统是 CentOS 8 时:prep → run(官方 almalinux-deploy)→ post,转成 AlmaLinux 8
swap-openssh.sh把自编译 openssh 换回官方包(带自动兜底)
hop.sh每一跳:prep→pre→report/answer→up→reboot→post
nginx-static-build.sh自编译 nginx 同版本静态重编(过渡期一路可用)
fleet_summary.py本机运行:汇总多台 survey 结果 → A/B/C/D 分类、VPN/EL8 标记、金丝雀与分批建议(--groups 让同业务主备不同批)
finalize.shEL10 收尾:compose 包装、kubectl 对齐集群、helm、postfix lmdb、nginx.org 源、cgroup v1 兼容、SysV 包装、legacy iptables 模块、redis→valkey、手工启动进程转 systemd 服务
k8s.shK8s 节点:backup(etcd 快照/配置/二进制/pod 列表,自动 pin 版本)、stop、nfs-off/nfs-on、nm、fix、check、pods(与升级前对比)、jvm-maxram(cgroup v2 下老 JDK 的 OOM)

本机在 Windows Git Bash 下调用时,remote.py 已自动处理 MSYS 把 /root/... 改写成 C:/Program Files/Git/root/... 的问题。

常用:

export FLEET_INVENTORY="/path/to/servers.xlsx"   # 列: name, host, port, username, password(含密码,切勿提交到仓库)
S=<技能目录>/scripts
python $S/remote.py HOST put $S /root/os-upgrade-kit
python $S/remote.py HOST run "bash /root/os-upgrade-kit/survey.sh > /root/os-upgrade-kit/survey.txt; sed -n '/RISK FLAGS/,\$p' /root/os-upgrade-kit/survey.txt"
python $S/remote.py HOST wait-ssh --timeout 3600

流程

阶段 0:开工前必须和用户确认的事(缺一不可)

这些是"用户的决定",不要替用户假设:

  1. 云快照/整机备份已做(系统盘+数据盘)。这是唯一可靠的回滚手段,Claude 在机器内部做不了。
  2. 停机窗口:每跳一次重启,全程约 2~4 小时(多数时间在下载包,镜像源快慢决定);业务会中断数次。
  3. 带外控制台可用:阿里云 VNC / 华为云 VNC / AWS EC2 Serial Console(各自前置条件见 references/cloud-providers.md)。升级卡在 initramfs 时只能从这里救。
  4. 访问路径:你(本机)是怎么连到这台机器的?如果走的 VPN/隧道就运行在这台机器上(survey 会报 BLOCKER),重启和容器操作要格外小心——我们的真实事故就是 docker stop 了全部容器导致 NetBird 路由容器开机不自启,整个 VPC 失联。
  5. 哪些东西已经没用:勘察完把清单给用户,让用户确认哪些组件/站点可以下线(例如 PHP、旧站点)。删之前说清楚影响面(比如"删 PHP 会导致 xxx 站点 404"),由用户拍板。

阶段 1:勘察 + 备份 + 基线

  1. 上传工具包,跑 survey.sh,逐条看 RISK FLAGS,结合 references/app-compat.md 给每条定处理方案。
  2. 跑 backup.sh(默认放非系统盘如 /data),记下 BACKUP_DIR。baseline.tsv 是后面每跳对比的依据——升级前就已经异常的项目(如 502)要在报告里注明"升级前即如此",免得事后说不清。
  3. 把勘察结论、处理方案、需要用户决定的事一次性告诉用户(见阶段 0)。

阶段 2:EL7 准备

bash prep-el7.sh repos <MIRROR>      # 国内推荐 https://mirrors.aliyun.com;阿里云内网 http://mirrors.cloud.aliyuncs.com;海外 upstream
bash prep-el7.sh update              # 到 7.9;出现 Failed 的包基本是 pip 冲突
bash prep-el7.sh pipfix
bash prep-el7.sh inhibitors
bash swap-openssh.sh                 # 仅当 survey 报 openssh 非官方包;完成后用【新连接】验证

自编译 nginx 等依赖 EL7 库的程序:EL7 上就用 nginx-static-build.sh 静态重编(或接受过渡期停用,最后装官方包)。 宿主机数据库:先逻辑备份。

源系统是 CentOS Linux 8 / CentOS Stream 8 时(survey 会报 BLOCKER):ELevate 不支持以它为源,跳过上面的 EL7 准备,先做同版本转换,然后从阶段 3 的 8→9 开始:

bash convert-el8.sh prep <MIRROR>                    # 修源(vault、EPEL8)、pip 冲突、多余 kernel-devel
bash convert-el8.sh update                           # 升到 8.5(almalinux-deploy 要求 ≥8.4)
bash convert-el8.sh run  <MIRROR> <almalinux-deploy.sh>   # 官方 almalinux-deploy:-d 允许降级,-l 用镜像
bash hop.sh reboot && python remote.py HOST wait-ssh   # 重启进入 AlmaLinux 内核
bash convert-el8.sh post                             # 删除非 AlmaLinux 内核,dnf upgrade

国内服务器通常访问不了 GitHub raw,需要先在本机下载 almalinux-deploy.sh 再上传。

阶段 3:每一跳(7→8、8→9、9→10 各做一遍)

bash hop.sh prep <MIRROR>     # 装本跳 ELevate、目标源和 docker-ce/epel 厂商源改镜像、关掉 test/nightly 段、pip 清理、探测可达
bash hop.sh pre               # 后台 preupgrade 并等待 → 自动 report
bash hop.sh answer            # 已知安全问题自动回答;其余阻断项按 report 里的修复命令处理,再 pre,直到 0 阻断
bash hop.sh report            # 重点看"将被删除的包"和"关键包去向"——有业务依赖的要先想办法
bash hop.sh up                # 后台下载+生成升级环境
bash hop.sh reboot [额外要停的容器名]   # 只停 restart=always 的有状态容器;VPN 容器和 unless-stopped 容器不碰;业务方说"别动"就用 --no-stop
python remote.py HOST wait-ssh --timeout 3600   # 本机等;超时 → 控制台,见 references/recovery.md
bash hop.sh post <MIRROR>     # 检查失败标记、清 leapp/旧内核/残留源、dnf upgrade
bash verify.sh <BACKUP_DIR>   # FAIL 必须处理;WARN 判断是否预期

每跳之后修复业务问题再进下一跳,不要攒到最后。各跳特有的阻断项和处理见 references/pitfalls.md 的"按跳分类"。

长任务一律后台跑:脚本已用 systemd-run 执行 leapp/dnf,SSH 断了不影响;你只管轮询。自己写命令时也照此办理,不要让一个 SSH 会话挂几十分钟。

阶段 4:EL10 收尾与现代化

按用户需要选用 finalize.sh 子命令,并参考 references/app-compat.md:

  • 自编译 nginx → nginx.org 官方 stable 包(ssl on; 改 listen 443 ssl;、TLS1.2/1.3、证书放 /etc/nginx/ssl、systemd 自启)
  • docker-compose v1 → 包装到 compose v2;cgroup v1 老应用加 shim
  • kubectl → pkgs.k8s.io 源、与集群同 minor;helm → 最新 v3
  • postfix hash → lmdb;rc.local 里的启动项改成 systemd unit
  • dnf -y upgrade 全量更新,确认 dnf check-update 为空
  • 最后再重启一次做开机自启测试,跑 verify.sh,全部服务自己起来才算完成

阶段 5:交付报告

用 assets/report-template.md 的结构写给用户:版本对比、业务对比表(升级前/后)、做过的兼容性改动、遗留与需要用户处理的事(证书到期、没修好的云厂商插件等)、备份位置。批量场景同时更新资产跟踪表(assets/fleet-tracker.csv)。

阶段 6:沉淀经验(回馈技能仓库)

这个技能靠真实执行不断进化,项目地址:https://github.com/seaworld008/centos7-lighthouse 。每次真实执行之后(成功、失败、回滚都算):

  • 按仓库的 field-reports/TEMPLATE.md 写一份脱敏实战报告(不写真实 IP、域名、主机名、凭据)。
  • 新问题写进 references/pitfalls.md;能自动检测的加进 survey.sh;能自动处理的改进脚本。
  • 如果当前工作目录就是该仓库,按其 AGENTS.md 执行;否则把报告交给用户,建议提交 issue 或 PR。

关键原则(每条都对应一次真实踩坑)

  • 重启前绝不 docker stop $(docker ps -q):unless-stopped 的容器被手动停过就不会自启;VPN 容器停了你就失联。用 hop.sh reboot。
  • pip 装进系统 site-packages 的东西必须在每跳前挪走:它们和 rpm 文件冲突时,升级会在 initramfs 里半途失败,系统卡在紧急模式且处于"半升级"状态。
  • 不认识的、非官方的东西都要先处理:自编译 openssh、自编译 nginx、第三方 repo、mysql-community-libs 替换了 mariadb-libs……leapp 不管它们,升级后它们就坏。
  • 国内用国内镜像,并关掉厂商源的 test/nightly 段:mirrorlist/metalink 常年慢或超时,docker nightly 源超时会直接让 leapp 失败。华为云镜像会 429 限流,阿里云最稳。
  • pkill -f / pgrep -f 的模式不能出现在你自己的命令行里,否则把自己的 SSH 会话杀掉(我们中招两次)。用 PID、用脚本文件、或 [l]eapp 这种写法。
  • 每跳都对比基线:业务问题当跳发现当跳修,比如 cgroup v2 让 Yearning 崩、docker-compose v1 失效。
  • 改变业务行为的决定交给用户:删组件、下线站点、关 TLS1.0/1.1、换大版本数据库。

参考文档(按需读取)

  • references/pitfalls.md — 全部坑:现象 → 原因 → 处理,按跳分类 + 通用。遇到报错先查这里。
  • references/app-compat.md — 各类应用跨 EL7→EL10 的兼容处理:nginx、Docker/compose/cgroup v2、Java、Python、PHP、数据库、postfix、网络、SSH、kubectl/helm、SysV、TLS 加密策略。
  • references/cloud-providers.md — 阿里云/华为云/AWS 差异:快照、带外控制台前置条件、镜像源、云厂商 agent、cloud-init。
  • references/recovery.md — 卡在 initramfs 紧急模式、开机失联、半升级状态时怎么救(含 VNC 操作技巧)。
  • references/fleet.md — 几十上百台批量推进:资产表、并行勘察、分类、金丝雀、分批、记录。
  • references/kubernetes.md — K8s 节点原地升级:开工前必须弄清的事(访问路径/控制面入口/etcd/存储)、兼容性结论、推荐顺序、踩过的坑、恢复检查清单。

Verwandte Skills