AnolisOS 8.x 内网本地源配置与 DNF 排错指南
内网里折腾 AnolisOS 8.x最容易卡住新手的不是内核参数也不是服务配置而是最基础的那一步——配本地 repo 源。我前阵子接手一批只连内网的机器AnolisOS 8.8 装完第一件事想装个 nginx敲下去直接回一句cannot find a valid baseurl for repo当场就知道外网源指望不上了。说白了本地源就是把安装镜像或者内网的文件服务挂在本地让 dnf 从自己的硬盘上找包彻底断掉对外网的依赖。这篇东西适合三类人看一是要在离线机房里做初始化部署的运维二是准备批量装机、想先把源规划好的实施人员三是刚接触 AnolisOS、还分不清它和 CentOS 7 仓库结构差异的同行。顺带提一句看到“repo”这个词别急着往代码仓库那边想在系统运维语境里它说的就是软件包仓库跟 Git 那个 repo 是两码事虽然热词里两个都在飘。1. 从一条 baseurl 报错说起AnolisOS 8.x 本地源到底在解决什么1.1 那条 cannot find a valid baseurl 到底在抱怨什么很多人第一次遇到这个报错第一反应是网络不通于是去 ping 网关、去查 DNS折腾半天发现网络好得很。其实 dnf 的意思非常直白它按配置文件里的baseurl去取仓库元数据取不到。取不到的原因有且只有几种——域名解析不了、HTTP 请求被拦、地址写错了、或者那个地址后面压根没有repodata目录。CentOS 7 时代那句经典的cannot find a valid baseurl for repo: base/7/x86_64就是典型仓库 ID 叫base指向的 mirrorlist 地址失效了。AnolisOS 8 的写法不一样仓库 ID 通常是BaseOS、AppStream这种报错信息里会直接带出对应的 ID比如for repo: BaseOS。看到 ID 就能立刻定位到是哪个.repo文件里的哪个[section]出问题这比漫无目的地猜要高效得多。我习惯的处理顺序是先dnf repolist --all把当前所有仓库和状态打出来看清楚哪些是enabled、哪些是disabled再cat一遍/etc/yum.repos.d/下所有文件确认没有一个失效的地址在里面。这两步做完问题基本就浮出来了。1.2 真正需要本地源的三种现场不是所有人都需要本地源。如果你的机器能正常访问公共镜像站那配个外网源就够了本地源纯属多此一举。但下面这三种场景本地源几乎是唯一解。第一种是纯离线机房。生产网段和办公网物理隔离机器连公网 DNS 都没有任何指向互联网的baseurl都是死地址。这种环境里你不配本地源机器就等于没有包管理能力只能靠手工传 rpm 包一个个rpm -ivh依赖关系能把人逼疯。第二种是批量初始化。五十台、一百台机器要装同一套软件如果每台都去外网拉包带宽和镜像站的压力是小事速度参差不齐、中途断流导致的失败才是麻烦。挂一份 ISO 到本地装包速度直接按磁盘 IO 走而且每台机器拿到的包版本完全一致不会出现 A 机器装了nginx-1.20.1-1、B 机器装成nginx-1.20.1-2这种版本漂移。第三种是公共源临时抽风或版本下线。上游镜像站调整目录结构、某个版本的仓库被归档都会让原本好好的baseurl突然失效。这种情况下把 ISO 挂在本地作为兜底源能保证你手头的故障处理流程不被打断。我在一次紧急排障时就吃过这个亏半夜公共源响应极慢dnf install一直转圈最后靠本地挂载的 ISO 把工具装上才把问题解决。1.3 AnolisOS 8 的仓库结构跟 CentOS 7 完全不是一回事这是最容易踩的一个认知坑。CentOS 7 的 DVD ISO 挂载后包全都堆在根目录下的Packages/里repodata也在根目录所以你配一个baseurlfile:///mnt/iso就完事了。AnolisOS 8 走的是 RHEL 8 那一套ISO 挂载后根目录下是两个并列的目录BaseOS和AppStream。前者放的是核心系统组件、基础命令、内核、glibc 这类必须存在的包后者放的是应用流、开发工具、语言运行时还有那个让人又爱又恨的 module模块流机制。两个目录各自带独立的repodata也就意味着你必须写两个[section]分别指向这两个路径一个都不能少。漏写 AppStream 的后果很典型dnf install一个普通的开发库会提示找不到包但系统基础包又能装让人误以为是包名写错了。实际上包就在 AppStream 里躺着只是你没告诉 dnf 去哪儿找。理解这一点后面所有配置都会顺理成章。2. 镜像选型与挂载本地源的地基必须在动手前打牢2.1 DVD、everything、minimal 三种镜像的取舍镜像选错后面全白搭。AnolisOS 8.x 官方提供的镜像种类不少跟本地源强相关的就三种差异很大。镜像类型体积量级包覆盖范围适合做本地源吗DVD约 8-10 GBBaseOS 全量 AppStream 全量适合最常用everything约 15 GB 以上全量包含大量可选组件适合覆盖最全minimal约 2 GB 以内仅够完成最小化安装不适合装不了额外软件boot几百 MB仅引导安装时联网取包完全不适合结论很直接做本地源请用 DVD 或 everything。minimal 镜像装系统够用但它里面根本没有完整的Packages集合你拿它当源等于开了个空仓库。我见过有人拿 boot 镜像挂上去当源然后反复检查 repo 文件写了十几遍问题其实出在镜像本身。选 everything 还是 DVD如果内网机器需要装容器工具链、多种语言运行时、图形化组件everything 更省心一次挂载全都有。如果只是常规服务器角色DVD 完全够体积还小一半传输和挂载都更快。2.2 下载后先校验别等装到一半才发现镜像坏了这一步很多人跳过然后在配置阶段被各种莫名其妙的现象折磨repodata读不出来、元数据校验失败、包解压报错。镜像传输过程中出错的概率并不低尤其是用 U 盘拷贝或者内网 FTP 中转的时候。校验方式就是用官方给出的校验值比对 SHA256sha256sum AnolisOS-8.8-x86_64-dvd.iso拿到的结果跟官方发布页上的值逐位比对一致才继续。别嫌这一步慢一个 9 GB 的镜像算校验值也就一两分钟比后面花两小时排查一个坏镜像划算得多。还有个容易被忽略的点ISO 文件本身要放在一个不会被清理的目录里比如/opt/iso/或者独立的数据盘千万别随手扔在/tmp或者某个用户的家目录里。系统一重启清空/tmp你的本地源就凭空消失了而且因为fstab里还留着挂载项开机时还会卡住报错。2.3 挂载点怎么选以及怎么让它开机自动挂挂载点我用得最多的是/mnt/iso简单直观。也有同行喜欢放/media/dvd无所谓只要路径后续在 repo 文件里写对就行。关键动作是建目录、挂载、验证三步mkdir -p /mnt/iso mount -o loop,ro -t iso9660 /opt/iso/AnolisOS-8.8-x86_64-dvd.iso /mnt/iso ls /mnt/isols的输出应该能看到BaseOS、AppStream、EFI、isolinux、images这些东西。如果只看到Packages和repodata说明你挂的是 CentOS 7 系的镜像拿错盘了。-o loop是把普通文件当块设备用ro是只读挂载这个参数建议一定加上避免误写损坏镜像。重点是持久化。mount命令只在当前开机周期有效重启就没了。要开机自动挂得写进/etc/fstabecho /opt/iso/AnolisOS-8.8-x86_64-dvd.iso /mnt/iso iso9660 loop,ro 0 0 /etc/fstab注意改完fstab之后一定要执行mount -a验证一遍。fstab 写错会导致系统启动时进入紧急模式而离线机房里往往没有带外管理恢复起来非常痛苦。mount -a无报错输出才算真正安全。还有一个细节fstab里最好用绝对路径写 ISO 文件位置别用相对路径或者带变量的写法。另外如果镜像放在 NFS 或者 iSCSI 挂载的盘上fstab里还要加_netdev选项否则开机顺序不对本地源同样会挂载失败。3. repo 文件怎么写从 file:// 到局域网 HTTP 源3.1 最小可用的本地源配置挂载点稳了之后配置文件就是水到渠成的事。在/etc/yum.repos.d/下新建一个文件名字随便起但最好能一眼看出用途比如anolis-local.repo[anolis-local-BaseOS] nameAnolisOS 8 Local BaseOS baseurlfile:///mnt/iso/BaseOS enabled1 gpgcheck0 [anolis-local-AppStream] nameAnolisOS 8 Local AppStream baseurlfile:///mnt/iso/AppStream enabled1 gpgcheck0这里有个必须记住的书写规则file://后面跟绝对路径时是三个斜杠。第一个和第二个斜杠是协议本身的一部分第三个才是路径的起始斜杠。写成file://mnt/iso/BaseOS是错的dnf 会把它当成主机名叫mnt的地址去访问报错时还很不直观。这个坑我见过太多人踩包括我自己早期也踩过。3.2 为什么 BaseOS 和 AppStream 必须写两个 section前面提过 ISO 是两个并列目录这里展开说说为什么不能偷懒合二为一。dnf 的每个[section]代表一个独立的仓库它只认你这个 section 指向的baseurl下面的repodata。如果你只写一个 section 指向/mnt/isodnf 会去找/mnt/iso/repodata/repomd.xml而这个文件在 AnolisOS 8 的 ISO 上是不存在的它藏在BaseOS/和AppStream/里面。结果就是元数据获取失败仓库直接被标记为不可用。两个 section 的分工也很清晰BaseOS负责基础系统AppStream负责应用和模块。它们之间是有依赖关系的比如你装php包本体在 AppStream但它依赖的一些底层库可能在 BaseOS。两个仓库同时启用dnf 才能完整地解析依赖树。只启用其中一个会出现包找得到但依赖解不开的诡异现象。命名上的建议是前缀加个标识比如anolis-local-BaseOS别直接叫BaseOS。原因很简单如果这台机器上还残留着指向外网的官方 repo 文件ID 撞车会引起混乱dnf repolist输出里两个同名仓库谁生效说不清楚。加前缀是最省事的规避方式。3.3 逐字段拆解baseurl、gpgcheck、enabled、cost、priority配置文件里能写的字段不少常用的这么几个搞懂含义比死记模板有用。baseurl仓库根地址可以直接用file://也可以是http://、ftp://。支持写多条dnf 会依次尝试。name仓库的人类可读名称出现在dnf repolist的输出里写得清楚点将来自己或者同事排障的时候能省不少事。enabled1启用0禁用。这个字段的最大价值在于临时切换需要的时候改一下就能把一个仓库摘出去不用删文件。gpgcheck是否对包做 GPG 签名校验。本地 ISO 源通常图省事关掉但生产环境更稳妥的做法是开启并指定gpgkey。gpgkey签名密钥文件路径AnolisOS 通常在/etc/pki/rpm-gpg/下具体文件名建议先ls看一眼确认。cost多个仓库提供同一个包时的成本权重默认 1000值越小优先级越高。priority需要装dnf-plugins-core才能生效的优先级字段数值越小越优先用来防止某个仓库的包覆盖掉另一个仓库的版本。module_hotfixes处理模块流冲突时用的一般场景用不上遇到模块包被过滤才需要开。如果开启 GPG 校验写法是这样的[anolis-local-BaseOS] nameAnolisOS 8 Local BaseOS baseurlfile:///mnt/iso/BaseOS enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-anolis关掉校验的理由很实际ISO 是你自己校验过哈希值的来源可信再走一遍签名校验只是增加配置复杂度。但如果本地源是通过内网 HTTP 共享的多台机器都在用那还是打开校验更稳能防止文件在传输过程中被意外改动。3.4 把本地源升级成内网共享源单机挂 ISO 只解决了自己如果你手上是二十台机器一台台传 ISO 既不现实也浪费磁盘。这时候更好的做法是选一台机器当源服务器把 ISO 里的内容发布出去其他机器通过 HTTP 访问。标准做法是用 Apachednf install -y httpd mkdir -p /var/www/html/anolis8 mount -o loop,ro -t iso9660 /opt/iso/AnolisOS-8.8-x86_64-dvd.iso /mnt/iso cp -a /mnt/iso/BaseOS /mnt/iso/AppStream /var/www/html/anolis8/ restorecon -Rv /var/www/html/anolis8 systemctl enable --now httpd这里有个特别容易被忽略的点restorecon。SELinux 在 Enforcing 模式下Apache 只能读取带有httpd_sys_content_t标签的目录。你用cp复制过去的文件继承的是源目录的标签Apache 会返回 403而客户端看到的报错是cannot find a valid baseurl完全没有提权限二字排查方向极其容易被带偏。执行一次restorecon -Rv把标签重置问题立刻消失。防火墙如果开着还要放行 HTTPfirewall-cmd --permanent --add-servicehttp firewall-cmd --reload客户端那边的 repo 文件就换成服务器的地址[anolis-net-BaseOS] nameAnolisOS 8 Shared BaseOS baseurlhttp://10.0.0.10/anolis8/BaseOS enabled1 gpgcheck0用 IP 而不是主机名是为了避免去依赖 DNS 解析内网环境下这一步能省掉很多麻烦。共享源的另一个好处是后续更新只改服务器一份客户端不用动。4. 生效验证clean、makecache、repolist 的顺序不能乱4.1 旧缓存是最大的干扰源repo 文件写完了很多人直接dnf install结果报错说找不到包然后开始怀疑配置文件。实际情况往往是 dnf 还在用之前的缓存元数据。dnf 会把仓库元数据缓存在/var/cache/dnf/下面按仓库 ID 分目录存放。你改了baseurl但缓存里还是旧地址的数据dnf 在缓存有效期内不会重新去拉。所以改完配置的第一步永远是dnf clean all dnf makecacheclean all会清掉元数据和包缓存makecache则按当前配置重新生成。执行makecache时最好盯着输出它会逐个仓库打印状态。看到某个仓库报Failed to synchronize cache就说明这个仓库还是有问题需要回头查配置。顺序千万别倒过来makecache之后再clean all等于白干。这个顺序我一开始也搞反过当时还纳闷为什么清完缓存再装包反而变慢了。4.2 屏蔽原来的外网源AnolisOS 8 装完之后/etc/yum.repos.d/里通常已经有一批指向公共镜像的 repo 文件。这些文件在离线环境里全是死地址保留它们的后果是每次dnf操作都要先等超时——每个失效仓库都要等 HTTP 连接超时几十秒就这么耗掉了体验极差。处理办法有两种。简单粗暴的是把它们挪走mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ mv /etc/yum.repos.d/backup/anolis-local.repo /etc/yum.repos.d/注意最后一行要把自己的本地源文件挪回来否则连本地源一起被移走了。更稳妥一点的做法是保留文件把里面的enabled全改成0sed -i s/^enabled1/enabled0/g /etc/yum.repos.d/*.repo这个命令有个副作用它会连你自己的本地源一起关掉执行完记得手动把anolis-local.repo里的enabled改回1。我一般会在执行前先把自己那个文件挪出去处理完再挪回来逻辑上更清晰。还有个更精准的方式是用dnf config-manager单独禁用某个仓库dnf config-manager --set-disabled anolis* dnf config-manager --set-enabled anolis-local-*这个工具来自dnf-plugins-core没装的话先装上。它的好处是不动文件内容纯靠配置状态切换回滚也方便。4.3 module 元数据带来的额外一层坑AnolisOS 8 的 AppStream 里有 module 机制同一个软件可以有不同的模块流比如不同版本的 PHP、Node.js。这一层机制会在本地源上多出一个坑如果repodata里的模块元数据没有正确读取某些包会被默认过滤掉表现出来就是包明明在 ISO 里但 dnf 就是找不到。验证模块元数据是否正常用这个命令dnf module list正常的话会打出一堆模块名、流版本和状态。如果输出为空或者报错说明模块元数据没加载成功多数情况下是 AppStream 的 repo 配置有问题回去检查baseurl是不是精确指向了/mnt/iso/AppStream。安装带模块的包时如果遇到多个流冲突的提示可以显式指定流dnf module install php:7.4具体有哪些流可选dnf module list php一看便知。本地源和模块机制配合本身没有问题关键是两个仓库都要启用元数据都要能读到。4.4 实测验证与结果判读配置全部做完该验证的还是要验证。三个命令就够dnf repolist dnf repolist --all dnf install -y treednf repolist显示的是当前启用且可用的仓库输出里应该只有你配的本地源仓库数量、包数量都有统计。如果某个仓库的包数量显示为 0说明元数据读到了但内容是空的八成是baseurl指到了上一层目录。dnf repolist --all会把禁用的仓库也列出来用来确认没有遗漏的失效源。最后用一个无足轻重的小包做实际安装测试tree就挺合适体积小、依赖简单。装完再rpm -q tree确认一下整个链路就算跑通了。我习惯再补一个dnf remove tree清场避免给基础镜像留下多余包。5. 配完装不上包一条完整的排查链路5.1 挂载丢了是第一嫌疑排障要从最外层往里查第一站永远是挂载点。ls /mnt/iso如果输出为空或者报No such file or directory后面的配置再完美也没用。挂载丢失最常见的原因是重启后fstab没生效。检查两件事fstab里那一行是不是还在执行mount -a有没有报错。还有一种情况是 ISO 文件被移动或者删除了fstab里的路径变成死路径开机时挂载失败。这种问题在/var/log/boot.log或者dmesg里能翻到线索。我给自己定过一条规矩所有涉及本地源的机器交付前必须做一次重启验证。不重启你永远不知道fstab写对没写对而离线机房重启一次的代价可能是一趟现场。5.2 GPG 校验失败要不要关gpgcheck1但gpgkey没配或者路径写错时装包会报Public key for xxx.rpm is not installed。这时候有两个选择。关闭校验最快gpgcheck0但更正确的做法是找到密钥文件并指定。先看看系统里有哪些ls /etc/pki/rpm-gpg/AnolisOS 的密钥文件名里通常带 anolis 字样确认之后写进配置。如果系统里没有ISO 的根目录下一般也放了一份可以复制过来。生产环境我倾向于打开校验多一层保障而且配置一次就长期有效。5.3 repodata 缺失与路径细节如果报的是Failed to download metadata for repo或者repomd.xml not found问题基本锁定在路径上。手动验证一下ls /mnt/iso/BaseOS/repodata/repomd.xml文件存在说明源侧没问题那就回头检查 repo 文件里的baseurl。常见的书写错误有这么几个三斜杠写成两斜杠、路径大小写不对Linux 是大小写敏感的baseos和BaseOS完全不同、路径末尾多加了斜杠导致拼接出双斜杠、把/mnt/iso当成了baseurl而不是/mnt/iso/BaseOS。这些都是低级错误但在深夜排障的时候特别容易犯。我的习惯是把baseurl那一行复制出来用ls把file://前缀去掉后粘贴验证一分钟确认比反复读配置快得多。5.4 排查速查表把上面的经验整理成一张表出问题的时候按顺序过一遍。报错或现象最可能的原因处理方式cannot find a valid baseurl挂载丢失或 baseurl 写错检查ls /mnt/iso核对三斜杠与路径Failed to download metadata指向目录无 repodata确认路径到BaseOS/AppStream这一层Public key is not installedgpgkey 未配置指定密钥路径或临时gpgcheck0包在 ISO 里但找不到AppStream 未启用或模块未加载检查两个 section跑dnf module listrepolist 包数量为 0baseurl 指到了上一层逐级ls确认 repodata 位置命令执行长时间卡住存在失效的外网源禁用或移走旧 repo 文件HTTP 共享源报 403SELinux 上下文不对执行restorecon -Rv /var/www/html这张表基本上覆盖了九成以上的现场问题。剩下的疑难杂症去/var/log/dnf.log和/var/log/dnf.rpm.log里翻日志信息比终端提示详细得多。6. 运维视角的长期维护让这套源活得更久6.1 版本升级时的处理方式AnolisOS 8.x 的小版本迭代比如 8.6 到 8.8会带来包版本更新如果内网机器需要跟着升级本地源也要同步替换。处理思路有两套。保守方案是换盘把新的 ISO 传进服务器改/opt/iso/下的文件名同时更新fstab里的路径重新挂载dnf clean all dnf makecache。这套流程简单回滚也容易出问题把旧 ISO 换回来就行。激进方案是保留多个版本的源同时提供用priority字段控制优先级让 dnf 优先用新版本同时在某个包出兼容问题时还能退回旧版本。这个方案适合有严格版本控制需求的场景但配置复杂度明显上升仓库数量翻倍元数据加载也变慢。中小规模环境我一般不推荐简单可靠比灵活更重要。有一点必须强调小版本升级时gpgkey文件有可能跟着变。升级之后如果突然冒出签名校验失败先去看密钥文件是不是被替换了。6.2 一个自用的检查脚本重复操作多了就该脚本化。我给自己写了个检查脚本放在/usr/local/bin/check-local-repo.sh跑一遍就能知道本地源的状态是否健康#!/bin/bash ISO/opt/iso/AnolisOS-8.8-x86_64-dvd.iso MNT/mnt/iso echo 1. ISO 文件 [ -f $ISO ] echo OK: 镜像存在 || { echo FAIL: 镜像不存在; exit 1; } echo 2. 挂载状态 mountpoint -q $MNT echo OK: 已挂载 || echo FAIL: 未挂载 echo 3. repodata for d in BaseOS AppStream; do [ -f $MNT/$d/repodata/repomd.xml ] \ echo OK: $d repodata 正常 \ || echo FAIL: $d repodata 缺失 done echo 4. 仓库列表 dnf repolist 2/dev/null | tail -n 1脚本本身不复杂价值在于把检查动作固化下来。排查故障最怕漏项有了脚本每次按同一套流程走不会因为着急而跳过某一步。这个脚本我也一起交给过同事反馈是交接和巡检的时候确实省事。6.3 多机统一源的下发思路最后一件事是怎么让几十台机器用上同一份源配置。手工一台台改是不现实的思路有三种。最简单的是把 repo 文件放到内网 HTTP 服务器上客户端用一条命令拉下来wget -O /etc/yum.repos.d/anolis-local.repo http://10.0.0.10/repo/anolis-local.repo dnf clean all dnf makecache这套流程可以直接写进装机后的初始化脚本配合自动化工具批量执行。稍微规范一点的做法是做成一个 rpm 包把 repo 文件和fstab配置一起打进包里装机后dnf install一下源配置和挂载全部到位。这种方式的好处是能纳入版本管理每次变更都有记录出问题可以回滚到上一个版本。再进一步就是把这一整套东西纳入配置管理工具的管控范围每台机器的 repo 文件状态可以随时查询和纠正。规模上百台之后人工核对状态的成本会迅速上升早点把这层自动化做起来后面的维护量是断崖式下降的。我自己是从第二个方案过渡到第三个的。中间踩过的坑是早期用 wget 拉文件服务器上的文件被误改了一行没发现结果所有新装机器都拿到了一份错误的配置等到有人反馈装不上包才发现。加了校验值比对之后就再没出过类似问题所以无论用哪种下发方式都建议在脚本里对文件做一次校验。最后分享一个实操中的小体会本地源的配置文件和挂载信息最好单独记录下来放在内网文档里包括 ISO 的完整文件名、存放路径、挂载点、SELinux 相关处理。这些东西在半年后回头看的时候如果没有记录光靠翻服务器上的配置文件是拼不出完整上下文的。我吃过这个亏一台老机器的 ISO 路径被人挪过fstab里的记录又没更新接手的人查了大半天才搞明白。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →