机房断外网的那天下午,我盯着终端里满屏的E: 无法定位软件包发了十分钟呆。银河麒麟软件源这东西,平时不显山不露水,真到内网环境里,能让你连一个 nginx 都装不上。这些年我在麒麟 V10 桌面版和服务器版之间来回折腾,从/etc/apt/sources.list改到/etc/yum.repos.d,从公网镜像换到单位自建源,再到现在移动硬盘里常备几个版本的 ISO 应急,踩过的坑基本能凑成一本小册子。
这篇东西想讲清楚三件事:银河麒麟软件源的配置到底改哪个文件、内网没网的时候怎么用 ISO 自己搭一个可用的源、以及各种报错背后真正的原因是什么。不管你是刚接手麒麟机器的运维,还是被派去给业务系统做国产化适配的开发,只要手上有一台麒麟 V10,看完基本能自己把源这件事理顺。命令我尽量给全,路径我尽量写死,你照着敲就行,但每一步为什么这么做,我也会讲明白。
1. 银河麒麟软件源到底是什么,为什么值得单独拎出来讲
软件源说白了就是一份"软件从哪儿下载"的地址清单。系统装包的时候,包管理器会去这份清单里列出的地址拉取索引文件,索引里记录了每个包的名字、版本、依赖关系、校验值,然后按需下载安装。这事儿在 Ubuntu、CentOS 上大家都熟,但银河麒麟的情况有点特殊——它同时存在桌面版和服务器版两条产品线,两条线的包管理体系完全不同,再加上国内大量麒麟机器部署在物理隔离的内网里,软件源这件事就从"顺手改个文件"变成了一个必须提前规划的工程问题。
1.1 桌面版走 apt,服务器版走 yum,两套体系千万别混
银河麒麟桌面操作系统 V10 的底层是 Debian 系,包管理工具是 dpkg 加 apt,配置文件是sources.list,包格式是.deb。银河麒麟服务器操作系统 V10 的底层是 RPM 系,包管理工具是 yum 或 dnf,配置文件是/etc/yum.repos.d/下的.repo文件,包格式是.rpm。
这个分岔点必须放在第一位说,因为我见过太多人拿着桌面版的教程去配服务器版,改了半天/etc/apt/sources.list,最后发现机器上压根没有这个目录。反过来也一样,服务器版的yum.repos.d在桌面版上同样不存在。判断方法很简单,两条命令下去就清楚了:
# 看包管理器是谁 which apt yum dnf # 看系统标识 cat /etc/os-release桌面版的os-release里通常能看到NAME="Kylin"、VERSION="V10 (SP1)"这类信息,服务器版的/etc/system-release里会写Kylin Linux Advanced Server release V10 (SP3)之类的字样,而且往往带着(Tercel)、(Sword)这样的内部代号。这些代号在配源的时候用得上,后面会讲。
1.2 源配置文件到底藏在哪些目录里
桌面版的主配置文件是/etc/apt/sources.list,但银河麒麟出厂时经常把实际的源条目放在/etc/apt/sources.list.d/kylin.list里,主文件反而是空的或者只有注释。这两个位置都会生效,apt 在读的时候会把sources.list.d/目录下所有以.list结尾的文件一并加载。除此之外还有几个相关目录值得记住:/etc/apt/apt.conf.d/里放的是 apt 的行为配置,比如代理、超时、是否校验有效期;/var/lib/apt/lists/是索引缓存,出问题的时候经常要整个删掉重建;/var/cache/apt/archives/是下载下来的 deb 包缓存,离线装包的时候这个目录是宝贝。
服务器版的主配置在/etc/yum.repos.d/,出厂一般会有两到三个.repo文件,名字类似kylin-server.repo、ks10-adv-os.repo。另外/etc/yum.conf管全局行为,dnf 环境下还有/etc/dnf/dnf.conf。缓存目录在/var/cache/yum/或者/var/cache/dnf/,同样是可以放心删掉重建的东西。
1.3 内网环境下自建源几乎是唯一出路
我接触过的麒麟部署场景里,八成以上是内网或者半隔离环境。这种情况下用公网源有几个绕不过去的坎:第一是物理上不通,防火墙策略卡死,curl直接超时;第二是版本一致性没法保证,今天源上更新了个包,明天另一台机器装出来版本就不一样了,业务系统跑起来排查问题会非常痛苦;第三是带宽,几十台机器同时从外网拉包,出口直接被占满。
所以正经的玩法是自己搭一个内网镜像源,把所有麒麟机器都指过去。搭源本身不复杂,无非是把官方归档的文件同步到内网服务器上,再起个静态文件服务。真正的难点在于:你得知道哪些目录必须同步、不同 SP 版本之间目录结构有什么差异、增量更新怎么做。这些我们在第 5 节会详细说。
2. 动手改源之前,这三件事必须先做完
我养成的一个习惯是:任何涉及系统配置的改动,先花五分钟做前置检查,能省下后面几个小时甚至一天的排查时间。软件源这块尤其如此,因为源配错的报错信息往往很含糊,指向性不强。
2.1 把版本号、架构、源代号一次查清楚
配源需要的三个关键信息是:系统大版本(V10 还是 V10 SP1/SP2/SP3)、CPU 架构(x86_64 还是 aarch64 还是 loongarch64)、以及源目录用的套件代号。前两个直接查就行:
# 系统版本详情 cat /etc/os-release # 桌面版还能看这个 cat /etc/kylin-release 2>/dev/null # 服务器版 cat /etc/system-release # 架构 uname -m # 桌面版再看一层 dpkg --print-architecture 2>/dev/nulluname -m在 x86 机器上返回x86_64,在 ARM 机器上返回aarch64,在龙芯上返回loongarch64。这个值决定了你要从源里拉哪个架构的包,拿错了就是一堆"无法定位软件包",而且报错信息不会直接告诉你是架构不对。
套件代号是 apt 体系特有的概念,写在源行中间那个位置。银河麒麟桌面 V10 系列用的代号通常是10.1,SP1、SP2 很多时候共用同一个代号,但也有一些版本的归档目录会细分。最可靠的确认方式不是猜,而是直接去源站上列目录,看dists/下面到底有哪些子目录:
curl -s http://你的源地址/kylin/KYLIN-ALL/dists/ | head -30列出来的目录名就是可用的代号,照抄进配置文件即可。这一步我强烈建议做,因为版本号和代号之间经常不是直觉上的一一对应。
2.2 备份 + 连通性自检,五分钟省下五小时
改配置文件之前先备份,这话谁都知道,但真出事的时候有备份的人不多。麒麟的源配置涉及的文件不多,一条命令全打包:
# 桌面版 sudo cp -a /etc/apt/sources.list /root/sources.list.bak.$(date +%Y%m%d) sudo cp -a /etc/apt/sources.list.d /root/sources.list.d.bak.$(date +%Y%m%d) # 服务器版 sudo cp -a /etc/yum.repos.d /root/yum.repos.d.bak.$(date +%Y%m%d)用date拼时间戳是我个人的偏好,因为有时候一天之内会改好几版,出问题要回滚到具体某一版。
改之前还要确认目标源站真的能通。这一步别偷懒,直接在改配置之前用 curl 打一下:
# 桌面版:看 Release 文件存不存在 curl -I http://10.10.20.30/kylin/KYLIN-ALL/dists/10.1/Release # 服务器版:看 repodata 目录 curl -I http://10.10.20.30/NS/V10/V10SP3/os/adv/lic/base/x86_64/repodata/repomd.xml返回200 OK才说明地址和路径都对,404说明目录不对,超时说明网络不通。我见过有人改完源直接apt update,卡在那里转圈十分钟,最后发现是 IP 写错了一位。先 curl 一下,两秒钟的事。
2.3 内网镜像地址从哪来,怎么判断它是不是完整
内网镜像的地址一般有两个来源:一是问运维要,二是从机器原有的配置里翻。有些单位做系统镜像的时候已经预置了内网源地址,只是后来被业务改乱了,这时候去/etc/apt/sources.list.d/或/etc/yum.repos.d/里翻历史配置,往往能找到正确地址。还有一个办法是看/etc/hosts,很多内网源会用域名而不是 IP。
判断一个镜像是不是完整,看三个东西:dists/代号/Release文件能不能下、Packages.gz能不能下、以及里面包的数量够不够。第三条有个简单的验证方法:
# 桌面版:看看源里到底有多少个包 curl -s http://10.10.20.30/kylin/KYLIN-ALL/dists/10.1/main/binary-amd64/Packages.gz | zcat | grep -c '^Package:' # 服务器版 curl -s http://10.10.20.30/NS/V10/V10SP3/os/adv/lic/base/x86_64/repodata/repomd.xml | head如果包数量只有个位数,那这个源基本是残的,同步没做完。正常的桌面版完整源,包数量在几万个量级,服务器版 base 仓库也有大几千个。
3. 桌面版 V10:apt 软件源配置全流程
桌面版这块我改得最多,因为业务同事的办公机基本都是麒麟桌面版,隔三差五就有装不上软件的情况找过来。下面从配置文件的结构开始,一层层讲。
3.1 sources.list 一行配置里每个字段的含义
打开/etc/apt/sources.list或/etc/apt/sources.list.d/kylin.list,你会看到类似这样的一行:
deb http://archive.kylinos.cn/kylin/KYLIN-ALL 10.1 main restricted universe multiverse这一行拆成四段来看。第一段deb表示这是一个二进制包源,如果写成deb-src就是源码包源,源码源在正常使用中完全可以注释掉。第二段是仓库的根地址,注意这里填到KYLIN-ALL这一级就够了,apt 会自己在后面拼dists/10.1/main/binary-amd64/Packages.gz这样的路径。第三段10.1是套件代号,前面说过要实际去源站确认。第四段main restricted universe multiverse是组件列表。
组件这块值得展开。这套命名是从 Debian 沿用过来的,main是官方支持的自由软件,系统的核心包基本都在这里;restricted是官方支持的专有软件,显卡驱动、固件这类东西通常归在这里;universe是社区维护的自由软件;multiverse是社区维护的专有软件。麒麟的归档对这套划分有自己的调整,但大体遵循这个逻辑。实际配置的时候建议四个组件全写,少写一个就可能出现某个依赖找不到的情况,而且报错往往很隐蔽——比如装 A 包的时候提示依赖 B,而 B 在universe里,你却只写了main。
3.2 把公网源换成内网镜像的三种写法
第一种是 sed 替换,适合批量机器操作:
sudo sed -i 's|archive.kylinos.cn|10.10.20.30|g' /etc/apt/sources.list.d/kylin.list sudo sed -i 's|archive.kylinos.cn|10.10.20.30|g' /etc/apt/sources.listsed 的坑在于容易漏文件,也容易把注释行里的地址一起改掉。所以我会加-i.bak参数留一份原文件:
sudo sed -i.bak 's|archive.kylinos.cn|10.10.20.30|g' /etc/apt/sources.list.d/*.list第二种是直接重写文件,适合机器数量少、想一次搞干净的情况。用 tee 写 heredoc 是最省心的方式:
sudo tee /etc/apt/sources.list.d/kylin.list > /dev/null <<'EOF' deb http://10.10.20.30/kylin/KYLIN-ALL 10.1 main restricted universe multiverse EOF注意 heredoc 用单引号的'EOF',这样里面的$不会被 shell 展开,对服务器版写$basearch的时候很关键。
第三种是用 apt 的-o参数临时指定源,不写文件,只在当次命令生效:
sudo apt -o Dir::Etc::sourcelist="my.list" -o Dir::Etc::sourceparts="-" update这种方式适合做验证——先确认新源能用,再决定要不要写进配置文件。我自己在切换源的时候基本都走这条路:先临时指一次,update通过了再去改文件。
改完之后清理缓存重新拉索引,这三步是固定动作:
sudo rm -rf /var/lib/apt/lists/* sudo apt clean sudo apt update3.3 apt update 报错逐条对号入座
apt update的报错信息虽然看着唬人,但常见的就那么几种,各有各的病因。
404 Not Found出现最多,基本是路径或代号写错了。把报错里的完整 URL 复制出来,用 curl 打一遍,能立刻定位是仓库根地址错了还是代号错了。还有一种情况是镜像同步不完整,源站上dists/里有这个代号,但main/binary-amd64/下面没东西。
Could not resolve host是 DNS 问题。内网源如果用的是域名,检查/etc/resolv.conf和/etc/hosts。我比较推荐在内网源上用 IP,少一层解析少一个故障点。
Connection timed out是网络层面的,防火墙策略、路由、端口都要查。有时候源服务器是通的但只开了 443 没开 80,或者反过来,这种细节很容易忽略。
NO_PUBKEY是签名验证失败,说明源里的 Release 文件用了一个本机没有的公钥签名。正规做法是把公钥文件放进/etc/apt/trusted.gpg.d/:
sudo cp kylin-archive-keyring.gpg /etc/apt/trusted.gpg.d/ sudo chmod 644 /etc/apt/trusted.gpg.d/kylin-archive-keyring.gpgapt-key adv这种老写法在新版本上会提示弃用警告,能用但别长期依赖。内网自建源如果实在搞不定签名,可以在源行前面加[trusted=yes],相当于跳过校验:
deb [trusted=yes] http://10.10.20.30/kylin/KYLIN-ALL 10.1 main restricted universe multiverse代价是失去了校验保护,只在完全可控的内网环境里用。
Hash Sum mismatch通常是本地缓存脏了,或者镜像正在同步导致索引和包不一致。删掉/var/lib/apt/lists/重来一次,如果还是不行就换台机器试试,能排除是镜像本身的问题。
Release file is expired说明索引过期了,一般是镜像很久没同步。临时绕过可以加参数:
sudo apt -o Acquire::Check-Valid-Until=false update但这只是权宜之计,正解是催运维同步镜像。生产环境上长期用Check-Valid-Until=false不是个好习惯,我是吃过教训的。
3.4 图形界面和麒麟应用商店的那套逻辑
麒麟桌面版有图形化的软件源设置界面,也有自带的应用商店。这两个东西的底层其实还是 apt,但它们各自维护自己的配置。应用商店用的是kylin-software-center或者新版的kylin-app-store,它读的配置可能和/etc/apt/sources.list不完全一致,所以在终端里apt update已经正常了,商店里却还在转圈,这种情况很常见。
排查思路是:先用apt update && apt install验证源本身没问题,然后看商店进程的日志。商店的服务一般叫kylin-software-center-service之类,重启一下往往能解决:
systemctl --user restart kylin-software-center-service 2>/dev/null # 或者 pkill -f kylin-software-center图形界面的源设置入口一般藏在"设置 - 更新"或者"软件源"里。我不太推荐用图形界面改源,因为它写文件的格式和你手写的不完全一样,来回切换容易乱。终端里改完,图形界面刷新一下就行。
4. 服务器版 V10:yum/dnf 仓库配置全流程
服务器版这边的情况比桌面版稍微复杂一点,因为 repo 文件的字段更多,多源并存的时候还要考虑优先级。但整体逻辑是一样的。
4.1 .repo 文件的字段拆解与命名规律
一个典型的 repo 文件长这样:
[ks10-adv-os] name = Kylin Linux Advanced Server 10 - Os baseurl = http://10.10.20.30/NS/V10/V10SP3/os/adv/lic/base/$basearch/ gpgcheck = 0 enabled = 1[ks10-adv-os]是仓库 ID,全局唯一,起冲突的时候 yum 会报 duplicate repo 的错。name是给人看的描述。baseurl是仓库地址,这里的$basearch是个变量,yum 执行的时候会自动替换成当前架构,x86_64 机器上就变成x86_64,ARM 机器上变成aarch64。用$basearch而不是写死架构,是让同一份 repo 文件能跨架构复用的关键。
gpgcheck控制是否校验 RPM 包的签名,内网自建源一般设 0。enabled不用多说。另外还有几个常用的字段:gpgkey指定公钥地址,mirrorlist用列表文件替代 baseurl,priority控制优先级,cost影响负载均衡时的选择,exclude和includepkgs做包级别的过滤。
命名上,麒麟服务器版的仓库通常分几类:base是基础包,updates是更新包,addons是扩展包,extras是附加包。对应到目录路径上,大概是os/adv/lic/base/、os/adv/lic/updates/这样的结构。只配 base 不配 updates,后果是有些安全补丁装不上,有些包的依赖也在 updates 里,这个坑我踩过。
4.2 多源并存时的优先级控制
内网环境里经常出现"内网源 + 一个应急的公网源"这种混合配置。这时候如果不控制优先级,同一个包可能被公网源抢先,导致版本混乱。控制方法是在 repo 文件里加priority:
[ks10-adv-os] name = Kylin Linux Advanced Server 10 - Os baseurl = http://10.10.20.30/NS/V10/V10SP3/os/adv/lic/base/$basearch/ gpgcheck = 0 enabled = 1 priority = 1 [ks10-public-emergency] name = Public Emergency Repo baseurl = http://public-mirror.example.com/NS/V10/V10SP3/os/adv/lic/base/$basearch/ gpgcheck = 0 enabled = 0 priority = 99yum 的 priority 插件遵循"数字越小优先级越高"的规则。上面的配置里,内网源 priority 是 1,公网应急源是 99,正常情况下所有包都从内网源来。应急源enabled = 0平时关着,真缺包的时候临时--enablerepo打开。
yum-plugin-priorities这个插件在某些麒麟版本上需要单独装,如果发现 priority 不生效,先确认插件在不在:
rpm -qa | grep -i prioritdnf 从某个版本开始内置了优先级支持,配置方式一样。
比 priority 更精细的控制是includepkgs和exclude。比如某个仓库只允许用它里面的两个包,其他一律不许:
[thirdparty] name = Third Party Repo baseurl = http://10.10.20.30/thirdparty/ gpgcheck = 0 enabled = 1 includepkgs = libfoo,libbar但说实话,includepkgs写多了之后维护成本很高,包名一变就得改配置。我更推荐用 priority 加 enabled 组合来做粗粒度控制,简单可靠。
4.3 缓存重建与验证的固定动作
改完 repo 文件,固定执行这几条:
# 清缓存 sudo yum clean all # 或者 dnf sudo dnf clean all # 重建元数据缓存 sudo yum makecache sudo dnf makecache # 查看仓库列表和状态 sudo yum repolist -vrepolist -v的输出里能看到每个仓库的 ID、名称、状态、包数量、更新时间。包数量是零的仓库肯定有问题,要么路径错,要么 repodata 没生成。这一步输出正常了,再试装一个小包验证:
sudo yum install -y treetree这个包体积小、依赖少,非常适合做冒烟测试。装完tree --version能输出就说明整条链路通了。
5. 完全断网的场景:用 ISO 和本地目录搭一个源
前面讲的都是"内网有镜像服务器"的情况。但还有一种更极端的场景:机器完全物理隔离,连内网都没有,只能靠 U 盘拷文件。这种时候就得用 ISO 或者自己攒的包目录搭一个本地源。
5.1 挂载安装 ISO,先看清里面的目录结构
桌面版和服务器版的安装 ISO 里都带了完整的包仓库,挂载上就能当源用。先挂载:
sudo mkdir -p /mnt/kylin-iso sudo mount -o loop /opt/iso/Kylin-Desktop-V10-SP1-Release-xxxx.iso /mnt/kylin-iso挂上之后别急着配源,先看清楚目录结构,因为不同版本的 ISO 布局不完全一样:
# 桌面版:找 Release 文件,它的上级两级就是仓库根 find /mnt/kylin-iso -maxdepth 4 -name "Release" 2>/dev/null # 服务器版:找 repodata find /mnt/kylin-iso -maxdepth 5 -name "repomd.xml" 2>/dev/null假设桌面版 ISO 里找到的是/mnt/kylin-iso/kylin/dists/10.1/Release,那么仓库根就是/mnt/kylin-iso/kylin,源行写成:
deb [trusted=yes] file:///mnt/kylin-iso/kylin 10.1 main restricted universe multiversefile://协议后面必须跟绝对路径,三个斜杠一个都不能少。[trusted=yes]是必须的,因为 ISO 里的包通常没有对应当前机器的签名配置。
服务器版 ISO 的 repo 文件写法:
[iso-local] name = ISO Local Repo baseurl = file:///mnt/kylin-iso enabled = 1 gpgcheck = 0baseurl要指到包含repodata目录的那一层,不是指到repodata里面。
还有一个细节:ISO 挂载重启之后就没了。如果是长期使用的机器,得写进/etc/fstab:
/opt/iso/Kylin-Desktop-V10-SP1-Release-xxxx.iso /mnt/kylin-iso iso9660 loop,ro 0 0或者更稳妥的做法是把 ISO 里的文件完整拷到本地磁盘的一个目录,直接指过去,省掉挂载这一层。
5.2 用 dpkg-scanpackages 把一堆 deb 变成仓库
如果手上没有 ISO,只有一堆散落的.deb包,可以用dpkg-scanpackages把它们组织成一个 apt 能识别的仓库。先装工具:
sudo apt install -y dpkg-dev然后把所有 deb 包拷到一个目录,生成索引:
sudo mkdir -p /opt/localrepo/packages sudo cp /path/to/debs/*.deb /opt/localrepo/packages/ cd /opt/localrepo sudo dpkg-scanpackages packages /dev/null | gzip -9c > packages/Packages.gz sudo dpkg-scanpackages packages /dev/null > packages/Packagesdpkg-scanpackages的第一个参数是包目录,第二个参数是 override 文件,用/dev/null表示不需要。生成的Packages.gz就是索引文件。
然后写源:
deb [trusted=yes] file:///opt/localrepo packages/注意这里的套件位置写的是packages/,组件位置留空,因为这种扁平结构没有dists/分层。这种写法和标准 apt 源结构不同,但 apt 是支持的。
生成完索引之后,apt update一下就能看到包了:
sudo apt update apt-cache search nginx如果搜不到,八成是路径写错了,用ls -R /opt/localrepo | head -30逐层核对。
5.3 createrepo_c 生成 RPM 元数据
服务器版对应的工具是createrepo_c(老版本叫createrepo):
# 如果系统里没有,从 ISO 里装 sudo yum install -y createrepo_c sudo mkdir -p /opt/localrepo/rpms sudo cp /path/to/rpms/*.rpm /opt/localrepo/rpms/ sudo createrepo_c /opt/localrepo/rpms执行完会生成repodata/目录,里面是元数据文件。repo 文件对应写:
[local-rpms] name = Local RPM Repo baseurl = file:///opt/localrepo/rpms enabled = 1 gpgcheck = 0每次往目录里加了新 RPM,都必须重新跑一次createrepo_c --update /opt/localrepo/rpms,否则新包不会出现在索引里,yum 找不到。这个--update参数只更新变化的部分,比全量重建快很多,包多了之后差别很明显。
5.4 离线装 nginx 的完整链路演示
把前面几节的工具串起来,走一遍离线装 nginx 的完整流程。
第一步,在一台能联网的、系统版本和架构与目标机完全一致的机器上下载包和依赖:
# 桌面版 mkdir -p /tmp/nginx-debs cd /tmp/nginx-debs apt-get install --download-only -o Dir::Cache::archives=/tmp/nginx-debs nginx或者用apt-get -d install nginx,包会进/var/cache/apt/archives/。第二种方式更常见,但要注意这个目录里可能混了之前的缓存,先清一下再下。
服务器版:
mkdir -p /tmp/nginx-rpms sudo yum install --downloadonly --downloaddir=/tmp/nginx-rpms nginx第二步,把下载好的包拷到目标机。用 U 盘、scp 都行,内网通的话直接 scp 最方便:
scp -r /tmp/nginx-debs user@target:/tmp/第三步,在目标机上建本地仓库并配源。桌面版:
sudo mkdir -p /opt/localrepo/packages sudo cp /tmp/nginx-debs/*.deb /opt/localrepo/packages/ cd /opt/localrepo sudo dpkg-scanpackages packages /dev/null | gzip -9c > packages/Packages.gz echo 'deb [trusted=yes] file:///opt/localrepo packages/' | sudo tee /etc/apt/sources.list.d/local.list sudo apt update sudo apt install -y nginx服务器版:
sudo mkdir -p /opt/localrepo/rpms sudo cp /tmp/nginx-rpms/*.rpm /opt/localrepo/rpms/ sudo createrepo_c /opt/localrepo/rpms sudo tee /etc/yum.repos.d/local.repo > /dev/null <<'EOF' [local-rpms] name = Local RPM Repo baseurl = file:///opt/localrepo/rpms enabled = 1 gpgcheck = 0 EOF sudo yum clean all && sudo yum makecache sudo yum install -y nginx这里有个特别容易翻车的点:下载依赖的源机器必须和目标是同一版本、同一架构。用 SP1 的机器下包给 SP3 装,或者用 x86_64 下包给 aarch64 装,结果就是一堆依赖版本冲突,而且报错信息往往只提某个底层库,根本看不出是版本不匹配。我在一个 ARM 服务器项目上就吃过这个亏,一开始图省事用了 x86 的包,折腾了两个小时才反应过来。
6. 软件源常见故障速查表
前面分散讲了不少报错,这里集中整理一遍,方便直接对照。
6.1 桌面版高频问题对照
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| apt update 报 404 | 仓库路径或套件代号写错 | 复制报错 URL 用 curl 验证,去源站列 dists 目录 |
| Could not resolve host | DNS 解析失败 | 检查 /etc/resolv.conf,内网源建议直接用 IP |
| Connection timed out | 防火墙或路由不通 | telnet 源站 80/443 端口测试 |
| NO_PUBKEY | 缺 GPG 公钥 | 公钥放 /etc/apt/trusted.gpg.d/,内网可加 [trusted=yes] |
| Hash Sum mismatch | 本地索引缓存脏或镜像半同步 | rm -rf /var/lib/apt/lists/* 后重试 |
| Release file is expired | 镜像长时间未同步 | 催运维同步,临时可加 Check-Valid-Until=false |
| 无法定位软件包 | 组件不全或包在别的仓库 | 补齐 main restricted universe multiverse |
| 应用商店一直转圈 | 商店独立配置未刷新 | 先验证 apt,再重启商店服务进程 |
| 包下载到一半失败 | 磁盘满或网络抖动 | df -h 看空间,apt clean 后重试 |
6.2 服务器版高频问题对照
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| yum repolist 里没有该仓库 | 文件后缀不是 .repo 或 enabled=0 | 检查文件名和 enabled 字段 |
| Error: Cannot retrieve repository metadata | baseurl 不可达或路径错 | curl 打 repomd.xml 验证 |
| duplicate repo 报错 | 两个文件里仓库 ID 相同 | 改掉其中一个的方括号 ID |
| 装包提示依赖版本冲突 | 多源混装,版本来源不一致 | 用 priority 控制,关闭多余源 |
| repolist 显示包数量为 0 | repodata 没生成或路径指错 | 重新 createrepo_c,核对 baseurl 层级 |
| 新加的 RPM 找不到 | 索引未更新 | createrepo_c --update 重新生成 |
| $basearch 没被替换 | baseurl 写错或转义问题 | 确认变量拼写,heredoc 用单引号 |
| 架构不匹配报错 | 混用了 x86_64 和 aarch64 的源 | 分离目录,按架构分别配置 |
6.3 几条排查通用思路
我处理源相关问题的顺序基本固定:先确认配置文件写对没有,再确认网络通不通,然后确认源站上文件存在不存在,最后才怀疑包本身。这个顺序从外到内,能把大部分问题挡在前两步。
具体一点:apt update或yum makecache的报错里,URL 是最有信息量的东西,直接复制出来 curl 一遍,能区分是"我写错了"还是"源站没有"。这一步做完,问题范围就缩小一半了。
还有个小技巧,curl -v比curl -I信息更全,能看到完整的请求头和响应头,涉及重定向、认证的问题一眼就能看出来。我排查 302 跳转导致的源不可用时全靠这个。
7. 这些年踩过的坑和几个小技巧
前面讲的都是方法和流程,这一节说几个文档里不会写、但实际运维中天天遇到的东西。
7.1 那些看起来无关其实很要命的细节
时间不同步会导致校验失败。这个坑很隐蔽,因为报错信息通常只说签名验证不通过,不会提时间。机器时间如果和源站差了太多,HTTPS 证书校验直接失败,GPG 签名的有效期判断也会出问题。内网机器尤其容易时间漂移,配源之前先看一眼:
date # 差得多的话 sudo ntpdate 内网NTP地址 # 或者 sudo chronyc sources代理配置会残留。有些机器之前配过代理,配置文件在/etc/apt/apt.conf.d/里或者环境变量里,后来代理不用了但配置没清。表现是明明已经换成内网源了,apt 还是往外网代理上撞。检查这几个地方:
env | grep -i proxy cat /etc/apt/apt.conf.d/* | grep -i proxy cat ~/.curlrc 2>/dev/nulldeb-src 会拖慢索引下载。源码源不是必须的,但很多模板配置里带着。源码索引文件比二进制索引大不少,下载慢一倍都有可能。用不到的话直接注释掉:
# deb-src http://... 10.1 main restricted universe multiverseISO 挂载重启失效。前面提过,写进 fstab 或者干脆把文件拷到磁盘上。我个人的习惯是拷到/opt/iso-contents/下面,虽然多占几十 G 空间,但省心。
不要随便对系统目录 chmod 777。这个跟软件源有点关系——我见过有人为了"解决权限问题",把/etc/apt整个改成 777,结果 apt 直接开始报签名相关的奇怪错误。Linux 的包管理工具对配置文件权限有隐含要求,改坏了很难查。真要排查权限问题,用ls -l对比正常机器的权限,然后chmod和chown精确恢复,别一把梭。
桌面版和服务器版的 SP 版本别混。SP1、SP2、SP3 的仓库目录结构有差异,$releasever变量解析出来的值也可能不一样。跨版本配源是排查成本最高的错误之一,因为大部分包能装,只有少数几个地方出问题,非常难定位。我现在的做法是每台机器配源之前先cat /etc/system-release拍照存档。
7.2 稳定运行期的维护习惯
源配好只是开始,后面还有维护的事。我总结了几个自己一直在用的习惯,分享一下。
第一,给每台机器留一份"源配置快照"。不用很复杂,就是把/etc/apt/sources.list.d/或者/etc/yum.repos.d/打包存到本地一个固定目录,命名带上日期和版本号。出问题的时候能快速看出改了什么。
第二,内网镜像定期做一致性检查。写个简单脚本,比对内网源和官方归档的文件数量和更新时间,差得多就报警。这个脚本用 shell 就能写,几十行的事:
#!/bin/bash REMOTE=$(curl -s http://public-mirror.example.com/kylin/KYLIN-ALL/dists/10.1/main/binary-amd64/Packages.gz | zcat | grep -c '^Package:') LOCAL=$(curl -s http://10.10.20.30/kylin/KYLIN-ALL/dists/10.1/main/binary-amd64/Packages.gz | zcat | grep -c '^Package:') echo "remote=$REMOTE local=$LOCAL" [ $((REMOTE - LOCAL)) -gt 50 ] && echo "WARN: local repo is behind"第三,每台机器只保留必要的源。源越多,makecache越慢,冲突概率越高。别为了"以防万一"把一堆源全开着,需要的时候再临时--enablerepo打开,比一直开着省事得多。
第四,装完包顺手记录一下来源。yum history info或者 apt 的/var/log/apt/history.log里都有记录,但主动记一份自己的包清单,在做环境迁移或者灾备重建的时候能省大量时间。
最后再分享一个我常干的小事:在每台机器的/root/下面放一个repo-recover.sh,里面就三行,内容是清缓存、重建索引、验证源可用。出问题的时候不用回忆命令,直接跑脚本,五分钟能恢复。这习惯是从一次半夜被叫起来处理线上问题之后养成的,那会儿脑子不清醒,连apt update都敲错了两遍。
软件源这件事,说到底就是把"去哪儿拿包"这件事安排明白。桌面版看 apt,服务器版看 yum,内网没源就用 ISO 和本地目录自己攒一个。真正花时间的从来不是改配置的那几行,而是出问题之后怎么快速定位——记住一点,报错里的 URL 永远是最值得先看的东西。