Linux 实战(一):CentOS 7、Rocky 9、Ubuntu 24.04 三台真机实测 —— 认清系统、换源、装包的版本坑

这个系列是什么

「Linux 实战」按线上真正会撞上的事情排:认清系统和装软件(本篇)、端口不通、服务起不来、磁盘满了、网络和 SSH、日志与性能......

每一篇都做两件事 :①所有命令在真机上跑过、贴原始输出;②同一件事在三个系统上各跑一遍 ------ CentOS 7 还大量在线上跑着,新机器多半是 Rocky 9 或 Ubuntu,而这三个系统在装软件、换源这件事上几乎处处不一样,照着一个系统的教程去弄另一个,常常是命令敲对了却不生效。

实测环境

机器 版本 内核 说明
CentOS 7 CentOS Linux release 7.9.2009 (Core) 3.10.0-1160.71.1.el7 VMware 虚拟机,firewalld 开、SELinux Enforcing
Rocky 9 Rocky Linux release 9.8 (Blue Onyx) 5.14.0-687.49.1.el9_8 KVM 虚拟机,最小化镜像后补装了 firewalld、SELinux 切到 Enforcing
Ubuntu 24.04 Ubuntu 24.04.5 LTS 6.8.0-139-generic KVM 虚拟机,最小化镜像后补装了 ufw(未启用)、AppArmor

⚠️ 后两台是最小化镜像,下文凡是写「这台机器上没有 X」,只代表这台机器,你那台标准安装的服务器可能装了。


1. 先认清是什么系统 ✅

装软件、改源、开端口的命令都跟系统走,所以第一步永远是确认自己在哪台什么系统上。

1.1 /etc/os-release:三个系统都有,最该先看

ini 复制代码
# cat /etc/os-release        (CentOS 7,截取前 6 行)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ini 复制代码
# cat /etc/os-release        (Rocky 9,截取)
NAME="Rocky Linux"
VERSION="9.8 (Blue Onyx)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="9.8"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Rocky Linux 9.8 (Blue Onyx)"
SUPPORT_END="2032-05-31"
ini 复制代码
# cat /etc/os-release        (Ubuntu 24.04,截取)
PRETTY_NAME="Ubuntu 24.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.5 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian

🔑 最有用的是 ID_LIKE :它说的是「这个系统像谁」。含 rhel → 按 yum/dnf 那一套走;含 debian → 按 apt 那一套走。

写脚本时只取一个值:

shell 复制代码
# . /etc/os-release && echo "$ID"
rocky
# grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"'
rocky

⚠️ . /etc/os-release 会把文件里的变量灌进当前 shell。实测(三台结果一致,这里贴 CentOS 7):

shell 复制代码
# VERSION=mine; . /etc/os-release; echo "VERSION 被覆盖成: $VERSION"
VERSION 被覆盖成: 7 (Core)
# VERSION=mine; ( . /etc/os-release; echo "子shell里: $ID" ); echo "外面 VERSION 仍是: $VERSION"
子shell里: centos
外面 VERSION 仍是: mine

脚本里自己有 VERSION、NAME 这类变量的,要么放进 ( ) 子 shell,要么用 grep 那种写法。

1.2 其他几个文件,各有各的坑

命令 CentOS 7 Rocky 9 Ubuntu 24.04
cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) Rocky Linux release 9.8 (Blue Onyx) No such file or directory
cat /etc/debian_version No such file or directory No such file or directory trixie/sid
cat /etc/issue \S / Kernel \r on an \m \S / Kernel \r on \m Ubuntu 24.04.5 LTS \n \l
command -v lsb_release 没有 没有 /usr/bin/lsb_release

三个要注意的地方:

  • Ubuntu 的 /etc/debian_version 给的是 trixie/sid,不是 24.04。判 Ubuntu 版本别看它。
  • RHEL 系的 /etc/issue 里是 \S、\r 这样的转义符 ,登录提示时才被替换,cat 出来看不到版本号。
  • lsb_release 两台 RHEL 系机器上都没有,Ubuntu 上有:
yaml 复制代码
# lsb_release -a            (Ubuntu 24.04)
Distributor ID:	Ubuntu
Description:	Ubuntu 24.04.5 LTS
Release:	24.04
Codename:	noble

# lsb_release -a            (Rocky 9)
bash: line 1: lsb_release: command not found

所以脚本里判系统用 /etc/os-release,别依赖 lsb_release。

另外,不知道有哪些 release 文件时 ls /etc/*release /etc/*version 能列全,但在 RHEL 系上它的退出码是 2 (/etc/*version 一个都匹配不到),写进脚本别拿退出码判断成败:

bash 复制代码
# ls /etc/*release /etc/*version 2>/dev/null      (Rocky 9,退出码 2)
/etc/os-release
/etc/redhat-release
/etc/rocky-release
/etc/system-release

1.3 内核、架构、是不是虚拟机

shell 复制代码
# uname -r; uname -m
3.10.0-1160.71.1.el7.x86_64          ← CentOS 7
5.14.0-687.49.1.el9_8.x86_64         ← Rocky 9
6.8.0-139-generic                    ← Ubuntu 24.04
x86_64

内核里的 el7 / el9 能反推 RHEL 大版本,但只能当线索:最终以 /etc/os-release 为准。

shell 复制代码
# systemd-detect-virt
vmware        ← CentOS 7(VMware 虚拟机)
kvm           ← Rocky 9 / Ubuntu 24.04(KVM 虚拟机)

# systemd-detect-virt -c; echo "退出码=$?"
none
退出码=1

⚠️ -c 只判容器:不是容器时输出 none、退出码是 1 。脚本里 if systemd-detect-virt -c 这样写,在物理机和虚拟机上都会走 else 分支,这是对的,但别把退出码 1 当成「命令出错」。

dmidecode 能看到虚拟化厂商:CentOS 7 是 VMware, Inc. / VMware Virtual Platform,Rocky 9 是 QEMU / Standard PC (Q35 + ICH9, 2009)。这台 Ubuntu 最小化镜像上没有 dmidecode 命令 (command not found)。

1.4 一段脚本拿全景(三台都实跑过)

bash 复制代码
echo "===== 系统 ====="
( . /etc/os-release 2>/dev/null && echo "$PRETTY_NAME  (ID=$ID  LIKE=$ID_LIKE)" ) \
  || cat /etc/redhat-release 2>/dev/null \
  || cat /etc/issue
echo "===== 内核/架构 ====="
uname -srm
echo "===== 虚拟化 ====="
systemd-detect-virt 2>/dev/null || echo "(无 systemd-detect-virt)"
echo "===== 包管理器 ====="
for p in dnf yum apt zypper apk pacman; do
  command -v $p >/dev/null 2>&1 && echo "有:$p"
done
echo "===== 防火墙 ====="
for p in firewall-cmd ufw nft iptables; do
  command -v $p >/dev/null 2>&1 && echo "有:$p"
done
echo "===== init ====="
ps -p 1 -o comm=

三台的输出:

ini 复制代码
===== 系统 =====
CentOS Linux 7 (Core)  (ID=centos  LIKE=rhel fedora)
===== 内核/架构 =====
Linux 3.10.0-1160.71.1.el7.x86_64 x86_64
===== 虚拟化 =====
vmware
===== 包管理器 =====
有:yum
===== 防火墙 =====
有:firewall-cmd
有:iptables
===== init =====
systemd
ini 复制代码
===== 系统 =====
Rocky Linux 9.8 (Blue Onyx)  (ID=rocky  LIKE=rhel centos fedora)
===== 内核/架构 =====
Linux 5.14.0-687.49.1.el9_8.x86_64 x86_64
===== 虚拟化 =====
kvm
===== 包管理器 =====
有:dnf
有:yum
===== 防火墙 =====
有:firewall-cmd
有:nft
有:iptables
===== init =====
systemd
ini 复制代码
===== 系统 =====
Ubuntu 24.04.5 LTS  (ID=ubuntu  LIKE=debian)
===== 内核/架构 =====
Linux 6.8.0-139-generic x86_64
===== 虚拟化 =====
kvm
===== 包管理器 =====
有:apt
===== 防火墙 =====
有:ufw
有:nft
有:iptables
===== init =====
systemd

2. 装软件:yum、dnf、apt 的差别 ✅

2.1 Rocky 9 上的 yum 其实就是 dnf

shell 复制代码
# ls -l $(command -v yum); yum --version | head -1      (Rocky 9)
lrwxrwxrwx. 1 root root 5 May 19 22:37 /usr/bin/yum -> dnf-3
4.14.0

# ls -l $(command -v yum); yum --version | head -1      (CentOS 7)
-rwxr-xr-x. 1 root root 801 Oct  2  2020 /usr/bin/yum
3.4.3

所以 Rocky 9 上敲 yum 和 dnf 结果一样;CentOS 7 上只有 yum,没有 dnf,也没有模块流:

bash 复制代码
# yum module list      (CentOS 7)
No such command: module. Please use /usr/bin/yum --help

2.2 装、卸、撤销(Rocky 9 实测)

arduino 复制代码
# dnf install -y nginx          (截取末尾)
  nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
  nginx-core-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
  nginx-filesystem-2:1.20.1-28.el9_8.6.rocky.0.1.noarch
  rocky-logos-httpd-90.17-1.el9.noarch

Complete!

🔑 dnf history undo 是后悔药:每次装卸都有一条带编号的记录,可以按编号撤销。

markdown 复制代码
# dnf history | head -5
ID     | Command line             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
     7 | remove -y nginx          | 2026-09-21 14:49 | Removed        |    4
     6 | install -y nginx         | 2026-09-21 14:49 | Install        |    4
     5 | -y -q install firewalld  | 2026-09-21 14:29 | Install        |   21 EE

# dnf history undo -y 7         (撤销第 7 次的卸载 = 装回来)
...
Complete!
# rpm -q nginx
nginx-1.20.1-28.el9_8.6.rocky.0.1.x86_64

CentOS 7 的 yum history undo 同样可用(下文 §3 测完后就是用它把装的包逐次撤掉的)。升级前记一下 history 的当前编号,出事时有救。

2.3 rpm -ivh / dpkg -i 不解依赖

手上只有一个包文件时,别直接 rpm -ivh:

vbnet 复制代码
# rpm -ivh nginx-1*.rpm nginx-core-*.rpm; echo "rpm 退出码=$?"      (Rocky 9)
error: Failed dependencies:
	nginx-filesystem = 2:1.20.1-28.el9_8.6.rocky.0.1 is needed by nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
	system-logos-httpd is needed by nginx-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
	nginx-filesystem is needed by nginx-core-2:1.20.1-28.el9_8.6.rocky.0.1.x86_64
rpm 退出码=2

换成 dnf install ./文件名,缺的依赖会从仓库自动补:

shell 复制代码
# dnf install -y ./nginx-1*.rpm ./nginx-core-*.rpm       (截取)
Installing:
Installing dependencies:
 nginx-filesystem   noarch  2:1.20.1-28.el9_8.6.rocky.0.1   appstream      11 k

CentOS 7 同理,rpm -ivh httpd 报缺 httpd-tools、libapr-1.so.0 等 4 项(退出码 1),yum install -y ./httpd-*.rpm 自动补上 apr、apr-util、httpd-tools、mailcap。

Ubuntu 上的对应情况:

vbnet 复制代码
# dpkg -i nginx_*.deb; echo "dpkg 退出码=$?"      (Ubuntu 24.04)
Selecting previously unselected package nginx.
...
dpkg: dependency problems prevent configuration of nginx:
 nginx depends on nginx-common (= 1.24.0-2ubuntu7.18); however:
  Package nginx-common is not installed.

dpkg: error processing package nginx (--install):
 dependency problems - leaving unconfigured
Errors were encountered while processing:
 nginx
dpkg 退出码=1

# dpkg -l | grep -E '^.. +nginx '
iU  nginx                           1.24.0-2ubuntu7.18                amd64        small, powerful, scalable web/proxy server

⚠️ iU = 已解包、未配置 ------ 包「装了一半」挂在那里。补救:

bash 复制代码
# apt --fix-broken install -y       (截取)
Correcting dependencies... Done
The following additional packages will be installed:
  nginx-common
...
# dpkg -l | grep -E '^.. +nginx'
ii  nginx                           1.24.0-2ubuntu7.18                amd64        small, powerful, scalable web/proxy server
ii  nginx-common                    1.24.0-2ubuntu7.18                all          small, powerful, scalable web/proxy server - common files

2.4 🔴 apt remove nginx 之后,/etc/nginx 还在

shell 复制代码
# apt remove -y nginx
...
Removing nginx (1.24.0-2ubuntu7.18) ...
# dpkg -l | grep -E '^.. +nginx'
ii  nginx-common                    1.24.0-2ubuntu7.18                all          small, powerful, scalable web/proxy server - common files
# ls /etc/nginx | head -5
conf.d
fastcgi.conf
fastcgi_params
koi-utf
koi-win

配置文件属于 nginx-common,不属于 nginx。想把配置改坏了「彻底重来」,要连它一起 purge:

bash 复制代码
# apt purge -y nginx nginx-common
...
# ls /etc/nginx
ls: cannot access '/etc/nginx': No such file or directory

很多教程写「apt purge nginx 连配置一起删」------ 只 purge nginx 这一个包是删不掉 /etc/nginx 的。

2.5 「命令找不到,该装哪个包」

以 semanage(SELinux 常用命令)为例:

yaml 复制代码
# dnf provides '*/semanage'        (Rocky 9,截取)
policycoreutils-python-utils-3.6-5.el9.noarch : SELinux policy core python utilities
Repo        : appstream
Matched from:
Filename    : /usr/sbin/semanage

# yum provides '*/semanage'        (CentOS 7,截取)
policycoreutils-python-2.5-34.el7.x86_64 : SELinux policy core python utilities
Repo        : @base
Matched from:
Filename    : /usr/sbin/semanage

注意两个版本的包名不一样 :CentOS 7 是 policycoreutils-python,Rocky 9 是 policycoreutils-python-utils。照抄 7 的教程在 9 上装会找不到包。

Ubuntu 上「命令找不到时提示你装哪个包」这个功能依赖 command-not-found 包 。这台最小化镜像一开始没有,敲 semanage 只有一句 command not found;装上之后:

csharp 复制代码
# apt install -y command-not-found && apt update
# semanage
Command 'semanage' not found, but can be installed with:
apt install policycoreutils-python-utils

没这个提示时用 apt-file(要先装、先 apt-file update):

bash 复制代码
# apt-file search /usr/sbin/semanage
policycoreutils-python-utils: /usr/sbin/semanage

2.6 两个写脚本时会咬人的细节

① check-update 有更新时退出码是 100,不是 1:

sql 复制代码
# yum check-update >/dev/null 2>&1; echo "yum check-update 退出码=$?"      (CentOS 7)
yum check-update 退出码=100
# dnf check-update >/dev/null 2>&1; echo "dnf check-update 退出码=$?"      (Rocky 9,当时无更新)
dnf check-update 退出码=0

脚本里 set -e 或 if yum check-update 会把「有可用更新」当成失败。

② 脚本里用 apt-get,别用 apt :apt 的输出一被管道接走,就会先打一行警告:

csharp 复制代码
# apt show nginx 2>&1 | head -3

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

2.7 锁住某个包不让升级(Ubuntu)

csharp 复制代码
# apt-mark hold nginx; apt-mark showhold
nginx set on hold.
nginx
# apt-mark unhold nginx
Canceled hold on nginx.

排查「这个包为什么一直没升级」时,先看一眼 apt-mark showhold。


3. 🔴 CentOS 7 源失效:照教程切 vault,实测 403 ✅

这是本篇的重点。 下面的测试把 CentOS 7 的仓库配置换回了 centos-release 包里自带的原版(从 rpm 包里解出来的,不是手写的),复现一台「从没改过源」的 CentOS 7 现在会遇到什么。

3.1 症状:Cannot find a valid baseurl

原版配置用的是 mirrorlist:

ini 复制代码
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
csharp 复制代码
# yum makecache         (截取末尾)
     5. Configure the failing repository to be skipped, if it is unavailable.
        Note that yum will try to contact the repo. when it runs most commands,
        so will have to try and fail each time (and thus. yum will be be much
        slower). If it is a very temporary problem though, this is often a nice
        compromise:

            yum-config-manager --save --setopt=<repoid>.skip_if_unavailable=true

Cannot find a valid baseurl for repo: base/7/x86_64

yum install 任何包都是同一句。原因不是网络,是源下线了:

shell 复制代码
# getent hosts mirrorlist.centos.org || echo "mirrorlist.centos.org 解析不到"
mirrorlist.centos.org 解析不到
# curl -sS -m 10 -o /dev/null -w '%{http_code}\n' http://mirror.centos.org/centos/7/os/x86_64/repodata/repomd.xml
404

3.2 教程里的第一选择 vault.centos.org:实测 403

大多数教程让你把 baseurl 指向官方归档 vault.centos.org。在我这条国内宽带上直连,它返回 403:

shell 复制代码
# curl -sS -m 15 -I https://vault.centos.org/7.9.2009/os/x86_64/repodata/repomd.xml      (截取)
HTTP/1.1 403 Forbidden
Server: CloudFront
X-Cache: Error from cloudfront

加浏览器 User-Agent 也还是 403。yum 里的表现:

vbnet 复制代码
failure: repodata/repomd.xml from base: [Errno 256] No more mirrors to try.
https://vault.centos.org/7.9.2009/os/x86_64/repodata/repomd.xml: [Errno 14] HTTPS Error 403 - Forbidden

⚠️ 这是 2026-09-21 在一条国内宽带上的读数;同一时刻从一个走代理出口的网络访问是 200 。所以它跟你的网络出口有关,不代表 vault 关了。切 vault 之前先 curl -I 看一眼能不能拿到 200,拿不到就直接用下面的镜像。

3.3 实测能用的:阿里云 centos-vault

先确认路径能拿到 200(这一步别省,路径写错的表现和源失效一模一样):

bash 复制代码
200 0.377s  https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml

然后:

bash 复制代码
mkdir -p /etc/yum.repos.d/bak
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/bak/

新建 /etc/yum.repos.d/CentOS-Vault.repo:

ini 复制代码
[base]
name=CentOS-7 - Base
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/os/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-7 - Updates
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/updates/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-7 - Extras
baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/extras/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
php 复制代码
# yum clean all; time yum makecache        (截取末尾)
Loaded plugins: fastestmirror
Determining fastest mirrors
Metadata Cache Created

real	3m7.691s

🔑 两个要点:

  • baseurl 写死 7.9.2009 ,别用 $releasever:它展开成 7,而归档站只有按小版本分的目录(7.0.1406/ ... 7.9.2009/),没有 7/(下面两行是在另一台机器上用 curl 查的):
bash 复制代码
404  https://mirrors.aliyun.com/centos-vault/7/os/x86_64/repodata/repomd.xml
200  https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/repodata/repomd.xml
  • 换完先 yum clean all 再 yum makecache,让 yum 丢掉旧的元数据。

⚠️ 切到归档只是让 yum 重新能用,归档里不会再有新的安全更新。长期看还是要迁到仍在维护的系统。

3.4 如果 mirrorlist 那一行没删掉,会怎样

很多教程说「mirrorlist= 不删,yum 还会去问已经下线的 mirrorlist,所以一定要删」。实测:在 baseurl 已经指向阿里云的前提下,把 mirrorlist 行加回去:

bash 复制代码
# yum --disablerepo='*' --enablerepo=base makecache      (截取末尾)
Loaded plugins: fastestmirror
Determining fastest mirrors
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock error was
14: curl#6 - "Could not resolve host: mirrorlist.centos.org; Unknown error"
Metadata Cache Created

退出码是 0 ------ yum 先问 mirrorlist、报一行错,然后回落到 baseurl,最后是成功的 。所以留着它不会让换源失败,但每次都会多一行报错、多一次解析等待。还是删掉,只是别把「换源没成功」归咎到它身上。

CentOS 7 上很多常用软件(比如 nginx)不在 base 源里,要先装 EPEL。epel-release 本身能从 extras 装上,但它写进去的是 metalink:

shell 复制代码
# grep -E '^(metalink|#baseurl)' /etc/yum.repos.d/epel.repo | head -2
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch

之后任何 yum 命令都会卡住。我给它设了 180 秒上限:

yaml 复制代码
# timeout 180 yum makecache
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * epel: d2lzkl7pfhq30w.cloudfront.net
退出码=124 用时=180s

退出码 124 = 被 timeout 杀掉,除了开头三行,180 秒里没有任何输出。EPEL 7 的正式地址已经 404,归档还在:

bash 复制代码
200  https://archives.fedoraproject.org/pub/archive/epel/7/x86_64/repodata/repomd.xml
200  https://mirrors.aliyun.com/epel-archive/7/x86_64/repodata/repomd.xml
404  https://dl.fedoraproject.org/pub/epel/7/x86_64/repodata/repomd.xml

把 /etc/yum.repos.d/epel.repo 的 [epel] 段改成:

ini 复制代码
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=https://mirrors.aliyun.com/epel-archive/7/$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
arduino 复制代码
# yum clean all; yum makecache
...
Metadata Cache Created
退出码=0 用时=100s

# yum install -y nginx          (截取末尾)
  nginx-filesystem.noarch 1:1.20.1-10.el7  openssl11-libs.x86_64 1:1.1.1k-7.el7

Complete!
# rpm -q nginx
nginx-1.20.1-10.el7.x86_64

4. Rocky 9:powertools 改名 crb、模块流要先 reset ✅

4.1 powertools 在 9 上叫 crb

照着 Rocky 8 的教程开 powertools 仓库:

shell 复制代码
# dnf config-manager --set-enabled powertools; echo "退出码=$?"
Error: No matching repo to modify: powertools.
退出码=1
# dnf config-manager --set-enabled crb; echo "退出码=$?"
退出码=0

⚠️ 在这台最小化的 Rocky 9 上,dnf config-manager 一开始根本不存在,报的是另一句:

bash 复制代码
No such command: config-manager. Please use /usr/bin/dnf --help
It could be a DNF plugin command, try: "dnf install 'dnf-command(config-manager)'"

要先 dnf install -y dnf-plugins-core。所以同一条命令可能撞上两种报错,先看清是哪一句。

装 EPEL 在 9 上是正常的:

rust 复制代码
# dnf install -y epel-release; dnf repolist | grep -i epel
epel                Extra Packages for Enterprise Linux 9 - x86_64
epel-cisco-openh264 Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64

4.2 模块流:换版本前要 reset

装特定大版本的 Node.js / PHP 这类软件,Rocky 9 用模块流:

ini 复制代码
# dnf module list nodejs      (截取)
Name   Stream Profiles                              Summary
nodejs 18     common [d], development, minimal, s2i Javascript runtime
nodejs 20     common [d], development, minimal, s2i Javascript runtime
nodejs 22     common [d], development, minimal, s2i Javascript runtime
nodejs 24     common [d], development, minimal, s2i Javascript runtime

先启用了 20,再想换成 22:

vbnet 复制代码
# dnf module enable -y nodejs:22
...
The operation would result in switching of module 'nodejs' stream '20' to stream '22'
Error: It is not possible to switch enabled streams of a module unless explicitly enabled via configuration option module_stream_switch.
It is recommended to rather remove all installed content from the module, and reset the module using 'dnf module reset <module_name>' command. After you reset the module, you can install the other stream.

先 reset 再启用就行:

ini 复制代码
# dnf module reset -y nodejs; dnf module enable -y nodejs:22
# dnf module list nodejs | grep -E '^nodejs'
nodejs 18     common [d], development, minimal, s2i Javascript runtime
nodejs 20     common [d], development, minimal, s2i Javascript runtime
nodejs 22 [e] common [d], development, minimal, s2i Javascript runtime
nodejs 24     common [d], development, minimal, s2i Javascript runtime

4.3 Rocky 9 换国内源

Rocky 默认用 mirrorlist(dnf repoinfo 里能看到它挑中的镜像)。改成阿里云:

bash 复制代码
cp -a /etc/yum.repos.d /root/yum.repos.d.bak
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak /etc/yum.repos.d/rocky*.repo
bash 复制代码
# grep -E '^(baseurl|#mirrorlist)' /etc/yum.repos.d/rocky.repo | head -2
#mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever$rltype
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/

# dnf clean all; time dnf makecache       (截取末尾)
Metadata cache created.

real	0m23.952s

# dnf repoinfo baseos | grep Repo-baseurl
Repo-baseurl       : https://mirrors.aliyun.com/rockylinux/9/BaseOS/x86_64/os/

5. Ubuntu 24.04:改 sources.list 不生效 ✅

5.1 源已经不在 sources.list 里了

shell 复制代码
# cat /etc/apt/sources.list
# Ubuntu sources have moved to the /etc/apt/sources.list.d/ubuntu.sources
# file, which uses the deb822 format. Use deb822-formatted .sources files
# to manage package sources in the /etc/apt/sources.list.d/ directory.
# See the sources.list(5) manual page for details.

真正的源在 /etc/apt/sources.list.d/ubuntu.sources,而且是多行格式:

makefile 复制代码
Types: deb
URIs: http://archive.ubuntu.com/ubuntu
Suites: noble noble-updates noble-backports
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://security.ubuntu.com/ubuntu
Suites: noble-security
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

5.2 老教程的 sed,一个字节都没改到

shell 复制代码
# sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list
# sed -i 's|//security.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list
# cmp /tmp/sources.list.before /etc/apt/sources.list && echo "sources.list 一个字节都没变"
sources.list 一个字节都没变

# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
      3 http://archive.ubuntu.com
      1 http://security.ubuntu.com

命令不报错,apt update 也正常,只是还在走官方源 ------ 这是最难发现的那种「没生效」。

5.3 改 ubuntu.sources,而且两个地址都要改

只改 archive 的话:

arduino 复制代码
# sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list.d/ubuntu.sources
# grep ^URIs /etc/apt/sources.list.d/ubuntu.sources
URIs: http://mirrors.aliyun.com/ubuntu
URIs: http://security.ubuntu.com/ubuntu

# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
     36 http://mirrors.aliyun.com
      1 http://security.ubuntu.com

security 那一段还在走官方。完整写法:

bash 复制代码
cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak
sed -i 's|//archive.ubuntu.com|//mirrors.aliyun.com|g'  /etc/apt/sources.list.d/ubuntu.sources
sed -i 's|//security.ubuntu.com|//mirrors.aliyun.com|g' /etc/apt/sources.list.d/ubuntu.sources
apt update
arduino 复制代码
# grep ^URIs /etc/apt/sources.list.d/ubuntu.sources
URIs: http://mirrors.aliyun.com/ubuntu
URIs: http://mirrors.aliyun.com/ubuntu
# apt-get update 2>&1 | grep -oE 'http://[a-z.]+' | sort | uniq -c
     16 http://mirrors.aliyun.com

备份放在 sources.list.d/ 里、叫 ubuntu.sources.bak 的话,实测不会 被当成源读进去:上面只改了 archive 那一次,.bak 里还是 archive.ubuntu.com,而 apt update 里一次都没出现它。

5.4 加第三方源:apt-key 还能用,但换成 signed-by

以 nginx 官方源为例。老写法 apt-key add 在 24.04 上还能执行成功,但会打弃用警告:

vbnet 复制代码
# apt-key add /tmp/nginx_signing.key; echo "apt-key 退出码=$?"
OK
apt-key 退出码=0
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).

现在的写法:把 key 转成二进制放进 /etc/apt/keyrings/,在源里用 signed-by 指定它:

bash 复制代码
install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://nginx.org/keys/nginx_signing.key -o /tmp/nginx_signing.key
gpg --dearmor -o /etc/apt/keyrings/nginx.gpg < /tmp/nginx_signing.key
echo "deb [signed-by=/etc/apt/keyrings/nginx.gpg] http://nginx.org/packages/ubuntu noble nginx" \
  | tee /etc/apt/sources.list.d/nginx.list
apt update
ruby 复制代码
# apt-get update 2>&1 | grep -iE 'nginx.org|W:|E:'
Get:5 http://nginx.org/packages/ubuntu noble InRelease [3278 B]
Get:6 http://nginx.org/packages/ubuntu noble/nginx amd64 Packages [45.3 kB]

# apt policy nginx | head -6
nginx:
  Installed: 1.24.0-2ubuntu7.18
  Candidate: 1.30.5-1~noble
  Version table:
     1.30.5-1~noble 500
        500 http://nginx.org/packages/ubuntu noble/nginx amd64 Packages

🔑 apt policy <包名> 能看到候选版本来自哪个源 ------ 排查「怎么装到的不是我想要的版本」就看它。

5.5 「Could not get lock」

另一个进程拿着 dpkg 的锁时(下面是我用一个脚本故意占住锁来复现的):

csharp 复制代码
# apt-get install -y tree; echo "退出码=$?"
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2879 (python3)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
退出码=100
  • apt-get 不会等,直接退出(退出码 100);
  • 报错里直接写了是哪个进程占着 (process 2879 (python3))------ 先看它是谁,等它结束。真实环境里最常见的是后台自动更新,这台机器上 unattended-upgrades 默认是 enabled 的。

别一上来就删锁文件,先看报错里写的是哪个进程、等它结束。锁释放后同一条命令直接成功:

java 复制代码
# apt-get install -y tree       (截取末尾)
Setting up tree (2.1.1-2ubuntu3.24.04.2) ...

6. 本篇速查(三台实测过的写法)

想做的事 CentOS 7 Rocky 9 Ubuntu 24.04
判系统 cat /etc/os-release 同左 同左
更新索引 yum makecache dnf makecache apt update
装本地包(自动解依赖) yum install ./x.rpm dnf install ./x.rpm apt install ./x.deb
文件属于哪个包(未安装) yum provides '*/名字' dnf provides '*/名字' apt-file search 路径
撤销上一次装卸 yum history undo <ID> dnf history undo <ID> ---
连配置一起删 --- --- apt purge 包 及其 -common 包
源配置在哪 /etc/yum.repos.d/*.repo 同左 /etc/apt/sources.list.d/ubuntu.sources
换源后必做 yum clean all && yum makecache dnf clean all && dnf makecache apt update
实测能用的国内源 mirrors.aliyun.com/centos-vault/7.9.2009 + epel-archive/7 mirrors.aliyun.com/rockylinux mirrors.aliyun.com/ubuntu

这一篇最容易踩的坑:

  1. 🔴 CentOS 7 源失效,切 vault.centos.org 前先 curl -I ------ 国内直连实测 403。
  2. 🔴 EPEL 7 的 metalink 会让 yum 卡死,改成 epel-archive 的 baseurl。
  3. 🔴 Ubuntu 24.04 改 sources.list 不生效;改 ubuntu.sources 要连 security 一起改。
  4. 🔴 apt remove nginx 删不掉 /etc/nginx,要 purge nginx-common。
  5. 🔴 Rocky 9 上 powertools 叫 crb;config-manager 可能要先装 dnf-plugins-core。
  6. 🔴 同一个命令,CentOS 7 和 Rocky 9 的包名可能不同(policycoreutils-python vs policycoreutils-python-utils)。
  7. ⚠️ check-update 有更新时退出码是 100;apt-get 撞锁退出码也是 100。

下一篇

(二)端口不通:firewalld / ufw / iptables / nftables / SELinux,同样三台机器实测。

相关推荐
迷途之人不知返1 小时前
【基础IO】-1-预备知识与准备工作
linux
xiaoqiMikko1 小时前
Linux 实战(二):端口不通 —— CentOS 7、Rocky 9、Ubuntu 24.04 上防火墙和 SELinux 的实测差异
linux·centos
大鹏的NLP博客2 小时前
WSL Ubuntu 26.04 升级与环境整理记录
linux·ubuntu·wsl
GeW2 小时前
如何打造真正的数字化工厂?需从Red Hat到数据库底层打捞基石
linux
沫璃染墨2 小时前
从零入门计算机网络系列(一):计算机网络初识——从网络发展史到TCP/IP协议》
linux·网络·网络协议·tcp/ip·计算机网络
忆挽篱笙歌4 小时前
gdb/cgdb
linux·ubuntu
Julien20045 小时前
管理 Ansible 配置文件
linux·运维·服务器·ssh·学习方法
MicrosoftCloud6 小时前
性能排查 01|free 显示内存用了 90% 就是快满了吗?buff/cache 与 available 一次讲清
linux·运维·内存·free·buff/cache
xiaoye-duck6 小时前
《Linux 网络编程》深入理解 epoll(下):epoll 实战开发与 LT/ET 触发模式深度剖析
linux·网络