ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

sudo apt-get update 深度解析:APT 索引刷新、换源与报错排查

sudo apt-get update 深度解析:APT 索引刷新、换源与报错排查 干了几年 Linux 运维和交付被同事、被群里新手问得最多的命令之一就是sudo apt-get update。有意思的是这条命令短到只有三个单词却几乎是最容易被误解的一条有人把它当成“一键更新软件”敲完发现软件版本没变转头就骂系统有人把它当成万能钥匙装不上包就狂敲一遍还有人看到sudo: a terminal is required这种报错直接怀疑自己 Linux 白学了。这篇文章就围绕 Linux 里这条sudo apt-get update把它拆到骨头缝里——它到底动了哪些文件、为什么必须有 sudo、apt-get 和 apt 该用哪个、源列表怎么写、镜像源怎么挑、报错怎么查。不管你是刚装完虚拟机的新手还是天天在服务器上写部署脚本的老手都能从里面挑到能直接抄的东西。1. 先把 update 这个词掰开它到底更新了什么1.1 一次真实的翻车现场暴露了最普遍的误解先说个我自己经历的场景。几年前帮一个团队排查“为什么代码在新服务器上编译不过”对方信誓旦旦说自己已经“更新过系统了”。我登上去一看gcc --version还是三年前的版本apt-get update也确实跑过输出一片绿没有任何报错。问题就出在这apt-get update从来就不负责升级任何软件它只负责去仓库把“现在有哪些包、每个包是什么版本”这份清单重新拉一遍回来。这个误解之所以普遍是因为update这个词在计算机领域被用得太泛滥了。SQL 里的UPDATE是改数据行Windows 的更新是装补丁手机上的系统更新是刷固件而在 Debian 系包管理器的语境里update特指“刷新元数据索引”。同一个单词三套完全不同的语义。你把它当成“升级”那自然就会得出“敲完没变化命令坏了”的结论。所以第一件事得先在心里立个规矩在apt-get的世界里凡是和“刷新”有关的活儿归update凡是和“真正改动系统里的软件”有关的活儿归install、upgrade、remove。这条界线分清楚了后面所有报错和困惑基本都能自己推出来。1.2 包管理器的工作模型仓库、索引、软件包三层要真正理解这条命令得先把 Debian 系包管理器的三层模型摆出来我习惯用书店来类比。第一层是仓库Repository相当于出版社的仓库。它是一个 HTTP/HTTPS 服务地址写在/etc/apt/sources.list里。你的机器并不直接和全世界的包打交道而是只和你在配置里列出的那几个地址打交道。第二层是索引Index / Package List相当于书店的目录册。仓库里真正存放软件包的位置是pool/目录结构又深又乱靠人去找是不可能的。所以仓库会额外提供一份目录文件也就是各种Packages、Sources文件里面记录了每个包的完整名字、版本号、依赖关系、文件大小、校验值、下载路径。apt-get update干的就是把这份目录册下载下来验证签名然后存到本地。第三层才是**软件包.deb 文件**本身相当于你要买的那本书。只有到了apt-get install或apt-get upgrade的阶段apt 才会拿着本地目录册去匹配、算依赖、下载具体的.deb然后交给dpkg去安装。这三层的关系一摆出来很多事情就自动清楚了目录册过期了你搜到的版本就是旧的install 自然装不到新东西目录册所在的路径变了比如发行版代号从 jammy 换到 noble但源列表还写着旧代号那下载目录册这一步就会 404目录册的签名验不过apt 会直接拒绝使用哪怕内容本身没问题。1.3 为什么 update 和 upgrade 必须分成两步经常有人问既然最终目标是让系统更新为什么不干脆合成一条命令这个设计其实是刻意的而且很有道理。第一步apt-get update是只读操作——它下载文件、写缓存但不碰系统里已安装的任何软件。这个操作理论上你在任何时候跑都不会把系统搞坏磁盘满了另说。第二步apt-get upgrade是写操作——它会真的替换掉系统里的二进制文件、配置文件可能重启服务可能改变依赖关系。写操作是有风险窗口的。把两者分开等于给了你两次决策机会。你可以先在 update 之后用apt list --upgradable看看这次到底有多少包可以升级、都升级到什么版本评估一下是不是动到了关键组件比如内核、glibc、openssl、数据库再决定要不要 go。如果合成一条命令那这个评估窗口就没有了。另一个实际原因是失败隔离。update 阶段最常见的失败是网络和源的问题upgrade 阶段最常见的失败是依赖冲突和磁盘空间。分开跑你能一眼看出这次失败到底属于哪一类。我在脚本里也从来都是分开写而且分开处理返回值这样日志里能直接定位。注意update之后没做upgrade是完全正常的状态服务器长期只 update 不 upgrade 是常见做法尤其是生产环境追求版本稳定的时候。2. 命令三段式解剖sudo / apt-get / update 各管一段2.1 sudo不是“提权开关”而是“以他人身份执行”很多人把sudo理解成“管理员模式开关”这个理解不算错但太粗了。sudo的字面意思是 substitute user do即“切换成某个用户去执行一条命令”默认切换目标是 root。它本身是一个 setuid root 的二进制程序普通用户执行它的时候会临时获得 root 权限去读取配置并完成认证。认证流程是这样的sudo 读取/etc/sudoers以及/etc/sudoers.d/下的片段匹配当前用户、当前主机、要执行的命令如果匹配上并且该规则要求密码就用 PAM 走一次密码校验。校验通过后会在/run/sudo/ts/用户名写一个时间戳文件默认 15 分钟内再次执行 sudo 就不用输密码了。sudo -v可以主动刷新这个时间戳sudo -k可以立即让它失效。为什么要用sudo而不是直接su三个原因。一是审计sudo 默认会把谁在什么时间执行了什么命令记进 syslogsu没有这么细的粒度。二是最小权限sudoers 可以写成“允许这个用户只执行 apt-get 这一条命令”而su一旦切过去就是完整的 root shell。三是不用交出 root 密码这对多人的运维团队非常重要。这里必须提一个真实存在的坑。如果你为了图方便在 sudoers 里写了lucky ALL(ALL) NOPASSWD: /usr/bin/apt-get update以为这样就“只放行了一条安全命令”那就太天真了。apt-get支持-o参数注入任意配置项攻击者可以构造sudo apt-get update -o APT::Update::Pre-Invoke::/bin/sh直接拿到 root shell。所有支持配置注入或能启动子进程的命令做单命令白名单时都要格外小心。真正要限制的话得配合NOEXEC标签或者干脆别给。另一个绕不开的报错是sudo: a terminal is required to read the password。这个报错出现的场景很固定你在一个没有分配 TTY 的上下文里执行 sudo比如 CI 的流水线、cron 任务、某些远程执行框架、或者 WSL 里通过非交互方式调用。sudo 默认要求必须有一个终端才能接收密码输入防止密码被管道劫持。处理方式有四种我按推荐程度排一下用ssh -t userhost sudo apt-get update-t会强制分配伪终端最干净。用sudo -S它从标准输入读密码配合echo $PASS | sudo -S apt-get update使用。但密码会出现在命令历史里必须配合环境变量和history屏蔽。在 sudoers 里针对特定命令配置NOPASSWD仅限确实无人值守的场景。检查 sudoers 里有没有Defaults requiretty有的话去掉。这个选项在老版本 RHEL 上是默认开的Debian 系一般不开。2.2 apt-get 与 apt同一个内核两套皮apt和apt-get经常让人迷惑其实它们共用同一套底层库apt是后来做的面向人的前端。差异主要在这几点上。输出风格不同。apt有彩色输出、进度条会额外提示“N 个软件包可以升级”还会提示你运行apt list --upgradable。apt-get输出朴素、稳定只有Hit、Get、Ign、Err这种前缀。接口稳定性不同。这是最关键的一点。你在脚本里敲apt它会打印一行警告W: apt 没有稳定的 CLI 接口不推荐在脚本中使用。因为apt的输出格式和提示文案可能随版本变化而apt-get的输出被认为是相对稳定的解析起来更安全。所以我的习惯很简单手动操作时用apt图个舒服写进脚本和文档一律用apt-get。功能覆盖上apt覆盖了apt-get和apt-cache的常用部分比如apt search对应apt-cache search但有些冷门开关还是apt-get更全比如apt-get download单独下载 deb 包、apt-get source拉源码包这些在apt里没有对应命令。2.3 update 子命令的执行链路其实是六步把sudo apt-get update拆到执行层面大致是这么六步理解了这个链路排查问题就能按图索骥。第一步收集源配置。apt 会读取/etc/apt/sources.list、/etc/apt/sources.list.d/目录下所有.list文件以及新版格式的.sources文件合并成一份源清单。如果同一个源被写了两次会有重复告警。第二步组装 URI。根据源地址、发行版代号suite、组件名component和本机架构拼出每个索引文件的确切下载地址。比如dists/jammy/main/binary-amd64/Packages.xz。第三步下载并验证 Release 描述文件。apt 先去拉InRelease文件它是Release和Release.gpg的合并体里面包含各索引文件的哈希值和签名。apt 用本地/usr/share/keyrings/里的公钥验签签名不对直接终止。第四步比对哈希。把 Release 里记录的哈希和实际下载下来的索引文件哈希做比对也就是Hash Sum mismatch这个报错的来源。第五步下载各组件索引。按组件、按架构下载Packages文件优先下.xz压缩版因为体积最小。第六步解析并落盘。把解压后的内容写入/var/lib/apt/lists/同时重建pkgcache.bin和srcpkgcache.bin这两个二进制缓存供后续查询加速。中间任何一步失败整个 update 都会返回非零退出码但已经下好的部分会保留在/var/lib/apt/lists/partial/下次跑能续上一部分。3. 数据落到了哪里源配置与索引缓存的目录结构3.1 sources.list 的加载顺序与书写规则源配置分两代格式。老格式是每行一条deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse一行四个字段包类型deb是二进制包deb-src是源码包、仓库地址、发行版代号、组件列表。少一个字段 apt 就会报格式错误。新格式叫 deb822从 Ubuntu 24.04 开始成为主流一个文件里可以描述多个源Types: deb URIs: https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ Suites: jammy jammy-updates jammy-security Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg这种格式的好处是字段化、可读性高、支持一行写多个 suite也避免了老格式里[archamd64]这种方括号选项容易写错的问题。关于加载顺序有个细节值得注意sources.list.d/里的文件是按文件名字典序加载的而且 apt 会做去重合并——同一个 URI 加同一个 suite 只会保留一份。如果你在sources.list和sources.list.d里都写了同一个源update 时会出现Target ... is configured multiple times的告警。这个告警不影响结果但看着烦而且暗示你的配置管理可能有问题。还有一个常见问题是文件后缀。sources.list.d/目录下只有以.list和.sources结尾的文件会被读取其他后缀一律忽略。很多人把备份文件命名为xxx.list.bak放在同目录下这恰好避开了被读取——但如果命名成xxx.list.old.list就会被当成有效源进而引发一堆莫名报错。备份文件建议直接挪到别的目录。3.2 /var/lib/apt/lists 里存的东西/var/lib/apt/lists/是 update 之后索引的落地目录。进去看一眼你会看到类似这样的文件mirrors.tuna.tsinghua.edu.cn_ubuntu_dists_jammy_InRelease mirrors.tuna.tsinghua.edu.cn_ubuntu_dists_jammy_main_binary-amd64_Packages mirrors.tuna.tsinghua.edu.cn_ubuntu_dists_jammy_universe_binary-amd64_Packages文件名规则是“源域名 路径”里的斜杠全换成下划线。这种命名方式的好处是不同源、不同组件的索引天然隔离不会互相覆盖。这个目录的体积通常是几十到两百兆之间取决于你启用了多少组件和架构。多架构比如同时开了 amd64 和 i386会翻倍。用du -sh /var/lib/apt/lists可以看一下如果发现体积异常大多半是残留了多个发行版代号的索引——比如从 22.04 升级到 24.04 之后旧代号的索引文件可能还躺在那里。/var/cache/apt/archives/是另一个容易被混淆的目录它存放的是下载下来的 .deb 包不是索引。apt-get clean清的是这里rm -rf /var/lib/apt/lists/*清的才是索引。两者别搞混了前者清了顶多下次重下包后者清了必须重新 update 才能装东西。3.3 镜像源怎么选三个可量化的指标镜像源的选择不是“哪个快就用哪个”这么简单尤其在企业环境里。我一般看三个指标。同步延迟。镜像站从上游同步是有周期的常见是每小时一次也有每 6 小时甚至每天一次的。同步延迟大的源在新版本发布后的一段时间内会出现索引和实际包不一致的情况表现出来就是Hash Sum mismatch或者 404。这个信息一般镜像站首页会公布。下行带宽与稳定性。这个可以实测。用 curl 拉一个索引文件测速curl -o /dev/null -s -w %{speed_download} %{time_total}\n \ https://mirrors.tuna.tsinghua.edu.cn/ubuntu/dists/jammy/InRelease单位是字节/秒和秒。以 Ubuntu 22.04 四个组件单架构为例索引压缩后合计在几十兆这个量级如果实测 2 MB/s理论上十几秒能完成如果只有 200 KB/s那就要一两分钟。这个量级心里有数之后就能判断某次 update 卡住到底是慢还是挂了。覆盖完整性。有些小镜像站只镜像main和restricted不镜像universe和multiverse。你把四个组件都写上update 时就会在缺失的组件上吃 404。判断方法很直接去镜像站的目录列表里看有没有dists/代号/universe/。顺带说一个优化点apt 默认会下载所有语言的翻译文件如果你只用中文或英文可以在/etc/apt/apt.conf.d/下加一个配置Acquire::Languages none;这能明显减少每次 update 的下载量尤其是第一次全量更新的时候。我在空间紧张的容器镜像里基本都会加上。3.4 离线与内网场景的替代方案有些机器根本连不上外网比如实验室的内网集群、工控环境、隔离网段。这时候apt-get update的原生用法就废了得换思路。第一种是本地目录源。把需要的.deb及其索引放到一个本地目录然后在 sources.list 里写deb [trustedyes] file:/srv/offline-repo ./配合dpkg-scanpackages生成Packages索引文件。这种方式适合包数量固定的场景比如只需装几个特定工具。第二种是先下载后带走。在有网的机器上用apt-get download 包名单独下载 deb 包连同它的依赖一起下下来apt-get download nginx apt-cache depends nginx依赖需要手动递归整理麻烦但可控。更省事的做法是用apt-get install --download-only -o Dir::Cache::archives/tmp/pkgs nginx它会把 nginx 和全部依赖一次性下载到指定目录然后你把整个目录拷到目标机用dpkg -i *.deb装上。第三种是内网自建源。用 nginx 或 python 的 http.server 把同步下来的目录暴露成 HTTP 服务其他机器指向这个内网地址。这是规模稍大的环境下最省心的方案一次同步全内网受益。提示离线场景下apt-get update依然需要跑只是源地址指向了本地或内网逻辑链路完全一样。4. 手把手实操从一台脏环境到一次干净的 update4.1 执行前的四项体检我养成习惯在任何一台不熟悉的机器上跑 update 之前先做四项检查。这四项耗不了两分钟但能挡掉绝大多数莫名其妙的报错。第一项看系统版本和代号。直接用lsb_release -a或者读/etc/os-release。输出里的Codename比如 jammy、noble就是 sources.list 里该写的那个词。这一步的意义在于很多人是照着网上的教程复制源列表的而教程可能是三年前写的代号早就过期了。第二项看网络和 DNS。先 ping 一下网关再测域名解析ping -c 2 223.5.5.5 getent hosts mirrors.tuna.tsinghua.edu.cn第二条如果没输出说明 DNS 有问题。这是Temporary failure resolving报错的直接来源而且很多时候不是源站的问题是/etc/resolv.conf里的 DNS 服务器地址不对或者被某个网络管理工具覆盖掉了。第三项看系统时间。时间偏差超过一定范围会导致 Release 文件的签名校验失败报错通常是Release file ... is not valid yet或者直接被判定为过期。检查一下timedatectl status如果显示没同步直接sudo timedatectl set-ntp true等半分钟再看。第四项看磁盘空间。重点看/var和根分区df -h /var /索引解压后比压缩包大好几倍/var/lib/apt/lists空间不够会让 update 在中途失败报错还不太直观。4.2 备份与换源确认没问题之后换源一定要先备份。这个动作看起来多余但真出问题时能省下大量时间sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak.$(date %F)如果系统是 deb822 格式对应备份/etc/apt/sources.list.d/ubuntu.sources。备份文件建议放到/root/下而不是原地加后缀原因前面说过避免被 apt 误读。换源时我一般用sed做批量替换而不是手写整个文件这样能保留原有的组件和选项设置sudo sed -i s|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g /etc/apt/sources.list sudo sed -i s|http://security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g /etc/apt/sources.list改完先别急着跑用grep -v ^# /etc/apt/sources.list看一眼实际生效的行确认没有语法错误、没有重复行、代号没写错。这一步花十秒钟能省掉一次失败重试。4.3 执行 update 并读懂每一行输出现在可以正式跑了sudo apt-get update输出的每一行前缀都携带信息值得逐个认识一下前缀含义是否需要处理Hit本地索引已是最新无需下载否Get正在下载新索引否Ign忽略该条目如不存在的可选文件一般否Err该源出错是一次正常的输出大概长这样命中:1 https://mirrors.tuna.tsinghua.edu.cn/ubuntu jammy InRelease 获取:2 https://mirrors.tuna.tsinghua.edu.cn/ubuntu jammy-updates InRelease [119 kB] 获取:3 https://mirrors.tuna.tsinghua.edu.cn/ubuntu jammy-security InRelease [110 kB] 已下载 229 kB耗时 1秒 (152 kB/s) 正在读取软件包列表... 完成最后那行“正在读取软件包列表... 完成”很关键它对应前面说的第六步——解析并生成二进制缓存。如果这行没出现或者出现的是“E:”开头的错误说明流程没走完。想看得更细可以加-o Debug::Acquire::httptrue会打印 HTTP 请求细节排查代理和重定向问题时很有用。日常不用开。跑完之后用一条命令确认“目录册”确实刷新了apt-get -s upgrade | tail -5-s是模拟执行不会真的改动系统能安全地看看有多少可升级的包。4.4 验证、清理与收尾update 成功后有几件收尾的事值得做但每件都有边界别越界。看可升级列表。apt list --upgradable列出所有可升级包和版本跨度。我习惯扫一眼有没有内核、systemd、openssl、数据库这类关键组件如果有在正式环境里会先安排维护窗口。清理索引残留。如果之前换过发行版代号/var/lib/apt/lists里会留着旧代号的索引白白占空间。可以这样清sudo rm -rf /var/lib/apt/lists/* sudo apt-get update注意顺序是先删再 update不能反过来。清理下载缓存。apt-get clean清空/var/cache/apt/archives/的全部 deb 包apt-get autoclean只清已经无法再从源里下载到的旧版本包。在磁盘紧张的环境里autoclean 更温和我一般用它。关于 autoremove这里要泼一盆冷水。apt-get autoremove会删除被标记为“自动安装”且当前不再被任何包依赖的包。听起来很合理但实际用起来有几个风险。它会删掉旧内核正常情况下没事但如果当前运行的内核就是它认为“不必要”的那个重启后就起不来了——虽然 apt 一般会保护正在运行的内核但多内核场景下这个保护不是万无一失的。它还可能删掉你手动用apt install装过、后来又忘了的依赖链末端包导致某些软件出问题。至于apport这个包它是崩溃报告收集工具在桌面版上通常被元包依赖服务器上删了也不影响核心功能但它会在某些升级路径里被重新拉回来来回折腾没意义。我的做法是autoremove 之前先apt-get -s autoremove模拟一遍把要删的列表逐条看完再决定。4.5 让它自动跑定时任务与无人值守手动跑 update 太累自动化是必然的。最朴素的方式是 cron# 每天凌晨 4 点静默刷新索引 0 4 * * * /usr/bin/apt-get update -qq /var/log/apt/update.log 21-qq会大幅减少输出只保留错误信息适合写日志。注意这里不要加-y也不要顺手接 upgrade——自动升级在生产环境是需要单独评估的事情别和索引刷新混在一起。Ubuntu 系其实自带了一套机制apt-daily.timer和apt-daily-upgrade.timer由 systemd 驱动。查看状态systemctl status apt-daily.timer systemctl list-timers | grep aptapt-daily负责定期 updateapt-daily-upgrade配合unattended-upgrades负责安全更新。这套机制默认开启但触发的具体时间带有随机延迟避免全网机器同时打满镜像站。在容器环境里这套机制往往被禁用因为容器生命周期短刷新索引没意义。如果你在容器里发现 update 特别慢先看看是不是有残留的 apt 进程在后台跑。5. 常见报错与排查技巧实录5.1 报错速查表下面这张表是我这些年攒下来的按报错关键词索引遇到时可以直接对号入座。报错关键词大概率原因处理方向Temporary failure resolvingDNS 不可用或写错检查/etc/resolv.conf测getent hostsCould not resolve host同上或网络未通先 ping IP 再 ping 域名404 Not Found发行版代号过时或写错镜像未同步用lsb_release -c核对代号Hash Sum mismatch镜像同步中或中间有缓存层等同步完成、换源、清 lists 重来NO_PUBKEY/GPG error缺少对应仓库公钥导入公钥到/etc/apt/keyrings并用signed-by引用Release file is not valid yet系统时间不对timedatectl set-ntp trueCould not get lock /var/lib/dpkg/lock-frontend有其他 apt/dpkg 进程在跑ps auxE: Unable to locate package没 update或源里确实没有先 update再apt-cache search确认包名is configured multiple times同一源被写了多次清理sources.list.d里的重复文件Unsupported file ... on TP某些虚拟化/容器环境下的 dtrace 提示一般可忽略不影响功能5.2 六个高频场景的排查复盘场景一换完源之后 404。这是新手最高频的问题九成是发行版代号对不上。Ubuntu 20.04 是 focal22.04 是 jammy24.04 是 noble很多人凭印象写。排查方法就一条. /etc/os-release echo $VERSION_CODENAME拿这个输出和源列表里的字段逐字比对。还有一种情况是镜像站已经停止维护某个老版本比如某些源不再提供已经 EOL 的发行版目录这时候得换一个有存档的源。场景二报NO_PUBKEY之后怎么处理。以前流行apt-key add但这个方法在现代发行版上已经被移除或废弃了因为它把密钥加到全局信任域里任何一个源都能用这把钥匙签名安全性很差。正确做法是把密钥下载成一个独立的 keyring 文件然后在源配置里用signed-by指定curl -fsSL https://example.com/repo-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/example.gpgdeb [signed-by/etc/apt/keyrings/example.gpg] https://example.com/repo stable main这样做的好处是密钥信任范围被限制在单个源上符合最小权限思路。场景三Hash Sum mismatch反复出现。这个报错有三种可能。第一种是镜像站正在同步索引文件和 Release 文件版本不一致等十几分钟再试就好。第二种是中间有 HTTP 缓存层缓存了旧文件却带着新的元信息这种在加了企业出口网关的环境里常见处理办法是清空本地 lists 后重试或者临时切一个不同的源验证一下。第三种最隐蔽——本地的/var/lib/apt/lists目录权限或磁盘有问题导致文件写入不完整。可以试试sudo rm -rf /var/lib/apt/lists/* sudo apt-get update。场景四锁文件被占用。报错长这样E: 无法获得锁 /var/lib/dpkg/lock-frontend。锁正由进程 12345apt-get持有第一反应别是删锁文件那是最后手段。先看是谁在占用ps -fp 12345如果是你自己的另一个终端在跑升级等着就行。如果是unattended-upgrades自动任务也建议等。只有在确认进程已经死掉、锁文件残留的情况下才考虑手动清理。清理的顺序是先删/var/lib/dpkg/lock-frontend再删/var/lib/dpkg/lock最后sudo dpkg --configure -a修复可能中断的状态。场景五时间不对导致验签失败。虚拟机快照恢复之后特别容易出现因为快照里的时间是旧的。除了timedatectl set-ntp true如果机器不能访问外部时间服务器也可以手动设定sudo date -s 2025-01-01 10:00:00不过手动设定只是应急长期还是得接上内网的时间源。场景六需要重新生成 initramfs 时怎么办。有些内核模块配置改了之后需要重建 initramfs这条链路平时是 apt 装内核时自动触发的。如果手动改配置后要重建可以用sudo update-initramfs -u -k all它和 apt 的关系是apt 在安装linux-image-*包时会调用触发器自动执行它所以你不需要单独手动跑。如果发现装完内核没重建通常是触发器没跑用sudo dpkg --configure -a补一下。另外mkinitramfs是更底层的工具一般不用直接调。5.3 我踩过的坑与避坑清单最后把一些零散但很值钱的经验集中列一下都是真金白银换来的。别在容器镜像里保留 apt 缓存。构建 Docker 镜像时apt-get update和apt-get install要写在同一个RUN层里并在同层内清理RUN apt-get update apt-get install -y --no-install-recommends curl \ rm -rf /var/lib/apt/lists/*分开写会导致 lists 被固化进中间层镜像白白大几十兆。加上--no-install-recommends能显著减少不必要的推荐包。生产环境不要开无人值守全量升级。安全补丁自动打是合理的全量升级不是。unattended-upgrades的配置文件/etc/apt/apt.conf.d/50unattended-upgrades里可以限定只允许安全源Unattended-Upgrade::Allowed-Origins { ${distro_id}:${distro_codename}-security; };ssh 里跑 sudo 记得用-t。前面说过的a terminal is required报错最省事的解法就是加-t。用自动化工具跑批量任务时如果工具本身不支持分配 TTY就改用sudo -S加密码环境变量的方式同时确保密码不会落进日志。定期看一眼索引目录体积。du -sh /var/lib/apt/lists超过两百兆就值得查一下原因通常是残留了多个代号的索引或者启用了用不到的架构。换源之前一定先测速再决定。很多人换了源反而更慢是因为那个源对当前网络位置的连通性不好。用前面给的 curl 命令测三次取平均比凭感觉靠谱。保留一份能用的原始源配置。改坏 sources.list 之后如果备份也没了可以从/etc/apt/sources.list.d/里的默认文件恢复或者从同版本的其他机器上拷一份。我在每台新机器初始化时都会把原始配置存一份到/root/下。我自己在实际操作中的体会是sudo apt-get update这条命令的坑几乎全部来自于“把它当成了别的东西”。把它当升级命令就会困惑为什么版本没变把它当万能钥匙就会在真正该查包名的时候浪费时间把它当无风险操作就会忽略 DNS、时间、磁盘这些前置条件。真正把它理解成“刷新本地目录册”之后每一次报错都能顺着仓库、索引、软件包这三层往下推八九不离十。下次再遇到 update 报错先别急着搜报错原文问自己两句索引这一层是配置写错了、网络断了还是签名没验过答案基本就在这两问里。
返回列表