Ubuntu 24.04 添加 Docker 仓库 GPG 密钥错误全解析
升级到 Ubuntu 24.04Noble之后我做的第一件事就是给测试机配上 Docker 官方仓库。按官网文档复制那几行命令结果sudo apt update还没跑完屏幕上就铺满了 GPG 密钥错误。这种报错在 Ubuntu 20.04、22.04 上并不常见但到了 Noble 这一代系统把仓库签名密钥的信任机制改成了更严格的模型很多从旧版本升上来、或者习惯照抄旧教程的人都会撞进同一个坑要么是一串NO_PUBKEY加十六进制编号要么是gpg: no valid OpenPGP data found还有一堆关于legacy trusted.gpg keyring的警告。这篇内容就把 Ubuntu 24.04 添加 Docker 官方仓库时遇到的 GPG 密钥缺失错误一次讲透先说它为什么会出现再给出一套完全可复现的正确流程最后把高频报错逐条拆解方便你对照排查。1. 先弄清报错本质apt 凭什么卡在 GPG 密钥上1.1 一个典型报错现场我先贴一段模拟的报错输出关键指纹做了脱敏处理$ sudo apt update Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease Hit:2 http://security.ubuntu.com/ubuntu noble-security InRelease Err:3 https://download.docker.com/linux/ubuntu noble InRelease The following signatures couldnt be verified because the public key is not available: NO_PUBKEY 1A2B3C4D5E6F7A8B W: GPG error: https://download.docker.com/linux/ubuntu noble InRelease: The following signatures couldnt be verified because the public key is not available: NO_PUBKEY 1A2B3C4D5E6F7A8B E: The repository https://download.docker.com/linux/ubuntu noble InRelease is not signed. E: apt cannot update the repository. Please check its configuration.这段信息量其实很大。NO_PUBKEY表示 apt 在本地信任的密钥环境里找不到能匹配仓库签名所用的公钥The repository is not signed是 apt 面对无法验证签名的仓库时的保守策略宁可不更新也不让未经身份验证的内容进入。最要命的是整个软件源更新会随之中断其他仓库可能也会被一起拖住。如果你看到的是Err:3 ... public key is not available问题几乎可以肯定出在密钥导入环节而不是仓库地址写错。1.2 apt 为什么坚持验证 GPG 签名理解这个报错得先清楚 apt 的签名验证机制。apt 更新软件源时网络上拿到的是 Packages 索引文件。你当然不希望别人修改这个索引让 apt 把恶意软件包装成正常包推给你。所以官方仓库会对索引的元数据文件做签名签名用私钥生成apt 用已经信任的公钥去验证。这就像收快递时快递员出示工作证你验过证件才收件没有对应的工作证也就是没有公钥apt 自然拒绝收件。具体流程上apt 会下载仓库的InRelease文件里面带有 OpenPGP 签名验证通过后才采用其中记录的哈希值去校验 Packages 索引。如果签名无法确认整个仓库更新就处于不可信状态apt 会直接报错并中断执行。所以 GPG 密钥缺失并不是 apt 的小脾气而是它保护系统安全的基本手段。1.3 Ubuntu 24.04 的信任模型变化为什么这个错误在 Ubuntu 24.04 上格外多因为 24.04 的仓库管理方式变了。旧版 Ubuntu 把第三方源的密钥放进全局信任库/etc/apt/trusted.gpg和/etc/apt/trusted.gpg.d/用apt-key add导入系统里所有软件源都会无条件信任这些密钥。但这种方式在安全上有个隐患一旦某个第三方仓库密钥被攻破攻击者可以拿它签名任何包欺骗这台机器上的任意仓库。所以从 22.04 开始apt-key就被标记为弃用24.04 更是彻底走向了 deb822 格式的.sources文件默认的/etc/apt/sources.list.d/ubuntu.sources就是一个典型例子。新模型要求每个软件源通过Signed-By明确指定自己信任的 keyring 文件不再搞全局信任。这带来三个直接影响旧教程里curl ... | sudo apt-key add -的写法在 24.04 上已经走不通apt-key命令通常不可用密钥要放到独立 keyring 文件里常见位置是/etc/apt/keyrings/或/usr/share/keyrings/源条目里必须写signed-by或Signed-By指向这个文件apt 才会使用它。正是这三处变化让不少照着旧文章操作的人一头撞上 GPG 密钥错误。这也是为什么网上关于这个问题的求助贴突然变多——不是大家操作变差了而是系统规则变了。2. 一次正确添加 Docker 官方仓库的完整操作2.1 先确认系统状态和依赖开工之前先确认系统版本确保代号确实是 noblecat /etc/os-release输出里能看到VERSION_CODENAMEnoble就可以了。如果你系统还停在 jammy那不是 Ubuntu 24.04错误模型也会略有不同先把系统升上来再继续。接着安装必要工具sudo apt update sudo apt install -y ca-certificates curl gnupg这三个包各司其职ca-certificates提供 HTTPS 证书链curl负责把 GPG 公钥文件从 Docker 官方仓库拉下来gnupg则用来处理 OpenPGP 公钥的格式转换。缺了gnupg后面执行gpg --dearmor会直接报 command not found缺了curl下载那一步就没法做。顺手把 ca-certificates 装上也能避免后续出现证书类报错。2.2 下载 GPG 密钥并转成二进制 keyring这一步是避免NO_PUBKEY的关键。推荐命令如下sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg几个点容易忽略。install -m 0755 -d确保目录存在且权限正确避免后面写入时遇到问题。下载下来的原始内容是 ASCII armored 格式开头是-----BEGIN PGP PUBLIC KEY BLOCK-----而 apt 官方推荐把它转成二进制 keyring 文件gpg --dearmor正是干这个的。最后chmod ar很重要apt 进程读取 keyring 文件时如果权限是600而只有某个用户可读就会出现权限类报错报错信息里通常带着permission denied字样。步骤执行完可以用下面这条命令验证文件已经是合法的 keyringsudo gpg --show-keys /etc/apt/keyrings/docker.gpg输出会列出公钥算法、创建时间和完整指纹。指纹的内容建议与 Docker 官方文档公布的一致确认你拿到的不是某个奇怪来源替换过的文件。这一步虽然多花十秒但能省下后面大量排查时间。2.3 在独立源文件中挂载 docker 仓库不要把 Docker 源直接塞进/etc/apt/sources.list而是放到独立的/etc/apt/sources.list.d/docker.list文件里。这样做有两个理由一是便于排查和移除二是单个仓库故障不会污染主 sources.list。24.04 也推荐这种模块化管理方式。传统单行格式echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable | sudo tee /etc/apt/sources.list.d/docker.list其中arch$(dpkg --print-architecture)自动展开为 amd64 或 arm64signed-by指向刚才生成的 keyring 文件noble是发行版代号stable是 Docker 仓库的组件名。24.04 也完全支持 deb822 格式的.sources文件可读性更好sudo tee /etc/apt/sources.list.d/docker.sources /dev/null EOF Types: deb URIs: https://download.docker.com/linux/ubuntu Suites: noble Components: stable Signed-By: /etc/apt/keyrings/docker.gpg EOF两种写法效果等价。如果你系统的其他源已经在用.sources格式那我建议统一用 deb822 风格看起来更清晰也更能融入 Ubuntu 24.04 的风格。2.4 更新并验证安装结果执行sudo apt update正常情况会看到 docker 仓库的InRelease被 Get 下来不再有签名错误。随后检查包是否可见apt-cache policy docker-ce输出里如果能出现候选版本号说明仓库添加成功之后执行sudo apt install docker-ce docker-ce-cli containerd.io就能顺利装上。如果apt-cache policy里什么都查不到大概率是源条目没有被 apt 读取或者仓库地址本身有问题继续看后面的章节。3. 高频 GPG 错误逐个拆解与修复3.1 NO_PUBKEY密钥根本没有落进系统这个报错最常见。除了完全没有执行密钥导入步骤外还有几个隐藏原因keyring 文件路径写错源条目里的signed-by指向了不存在的文件密钥文件虽然存在但内容不是真正的公钥而是一个 HTML 错误页或空文件系统时间偏差太大导致 apt 在验证签名时产生了异常表现。排查步骤很简单ls -l /etc/apt/keyrings/docker.gpg sudo gpg --show-keys /etc/apt/keyrings/docker.gpg如果ls显示文件不存在就去检查是不是当初写错了目录名比如写成了/etc/apt/keys而不是/etc/apt/keyrings。如果gpg --show-keys报 No public key 或类似提示说明文件损坏直接重新生成即可。修复手段sudo rm -f /etc/apt/keyrings/docker.gpg curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg sudo apt update这里提醒一句不要只删 keyring 文件而忘了修正源文件里的signed-by路径。路径写错是NO_PUBKEY的温床。3.2 gpg: no valid OpenPGP data found下载到的内容是错的这个错误出现在gpg --dearmor一步意思是 gpg 收到的东西根本不是 ASCII armored 公钥。最常见的情况是 curl 成功返回了 HTTP 200但内容是 HTML 页面比如网关、防火墙的拦截页或者 CDN 临时返回的错误页。curl -fsSL的-f只对 HTTP 错误码生效不会拦截内容本身所以 gpg 拿到 HTML 后照样会抱怨。怎么确认执行curl -fsSL https://download.docker.com/linux/ubuntu/gpg | head -n 5正常应该看到-----BEGIN PGP PUBLIC KEY BLOCK-----如果看到!DOCTYPE html或一段 JSON那就是网络出口有问题。这个场景多发生在某些办公网络、公共 WiFi 或网络服务商对 download.docker.com 做了特殊处理的环境里。处理办法换个能正常访问该域名的网络出口手机热点通常最快稍等片刻重试CDN 抖动过一会儿会恢复找一台能正常下载 gpg 文件的机器把文件合法传输回本机再使用。这类问题排查到最后会发现根本不是 apt 的配置错误而是拿不到正确的源头文件。别在那条命令上反复重试先看内容。3.3 Key is stored in legacy trusted.gpg keyring 警告很多从旧版本升级到 24.04 的系统以前用apt-key add导入过 Docker 密钥升级后每次apt update都会刷出一条很长的警告内容大致是Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.这个警告不直接影响安装但说明系统处于一种不规范且存在风险的信任状态密钥被全局信任任何使用该密钥签名的包都能通过验证。修复的方向是把密钥搬到独立 keyring并在 Docker 源条目里写signed-by。实际操作时要注意24.04 上apt-key del这种命令已经不可靠了。正确方向是先把 Docker 源条目改成 2.3 里带signed-by的写法再把原来全局信任的密钥文件移除。旧系统里密钥可能出现在/etc/apt/trusted.gpg.d/目录下也可能直接写在/etc/apt/trusted.gpg这个二进制文件里。操作前先备份sudo cp -a /etc/apt/trusted.gpg /etc/apt/trusted.gpg.bak 2/dev/null || true sudo cp -a /etc/apt/trusted.gpg.d /etc/apt/trusted.gpg.d.bak 2/dev/null || true备份后找出属于 docker 的密钥文件并删除再按 2.2 和 2.3 重新导入和配置警告就会消失。如果你确认这台机器上 Docker 密钥只存在于/etc/apt/trusted.gpg.d/docker.gpg直接删除那个文件是最快的。3.4 The repository ... does not have a Release file这个报错虽然不直接带 GPG 字样但经常和 GPG 问题混在一起出现。它通常意味着仓库 URL 指向的 dists 目录里没有你要找的发行版代号。比如系统明明是 noble但sources.list.d里写的是deb [archamd64 signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu focal stableDocker 仓库明明支持 noble你却被旧教程带着写了 focalapt 去访问不存在的目录自然找不到 Release 文件于是判定仓库无效。排查方式很直接curl -fsSL -o /dev/null -w %{http_code}\n https://download.docker.com/linux/ubuntu/dists/noble/Release返回200说明 noble 在 Docker 仓库里存在返回404说明代号写错。还有一个隐蔽场景.sources文件里Suites: noble stable这种写法会把stable误当成套件名语法上不成立。按 2.3 的模板写最省心不要自己加料。3.5 证书类错误unknown authority 和证书失效报错里如果出现Certificate is signed by an unknown authority通常不是 GPG 密钥问题而是系统信任链或时间问题。我排查这类报错的固定顺序date sudo timedatectl set-ntp true systemctl restart systemd-timesyncd sudo apt install --reinstall ca-certificates如果系统时间比真实时间差了好几天OpenPGP 签名验证会受公钥有效期影响而失败apt 对 HTTPS 证书的校验也会一起异常。先校正时间再看签名错误是否消失。对于已经装有 ca-certificates 的机器强制重装一遍还能把可能损坏的证书链文件补回来。4. 不要盲猜用一套流程把问题定位出来4.1 快速核对 keyring 与仓库条目遇到任何 GPG 错误我都建议先做一次信息收集。最常看的三个位置是 keyring 文件、Docker 源文件和 apt 日志sudo gpg --show-keys /etc/apt/keyrings/docker.gpg cat /etc/apt/sources.list.d/docker.list sudo tail -n 30 /var/log/apt/term.loggpg --show-keys确认密钥文件可解析cat确认signed-by路径与实际一致日志里能看到 apt 到底在哪一步失败。有时候错误已经写在日志里只是apt update的终端输出把它吞掉了一部分。日志文件记录的信息比终端更完整值得养成先看日志的习惯。4.2 用 apt-cache 和 curl 交叉验证如果仓库配置看着没问题但apt update依旧报错用 curl 直接访问源地址能快速区分是本地还是远端问题curl -fsSL https://download.docker.com/linux/ubuntu/dists/noble/Release | head -n 5 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | head -n 3第一个应该输出 Release 文件头部第二个应该输出BEGIN PGP PUBLIC KEY BLOCK。任何一个不像预期问题大概率在网络层或仓库地址本身。如果仓库访问正常再清理一次 apt 的缓存状态sudo rm -rf /var/lib/apt/lists/*docker* 2/dev/null sudo apt clean sudo apt update清理 lists 目录有时能解决因缓存了错误签名元数据而导致的顽固报错。这类问题不是每次都出现遇到一次就能体会到先清缓存的好处。4.3 常见 GPG 错误速查表报错关键字直接原因最快定位修复方向NO_PUBKEY xxxx本地没有对应公钥gpg --show-keys /etc/apt/keyrings/docker.gpg重建并导入 keyringno valid OpenPGP data下载到 HTML 或空文件curl .../gpg | head -n 5换网络出口重试legacy trusted.gpg keyring密钥放进了全局信任区检查/etc/apt/trusted.gpg*迁移到独立 keyringdoes not have a Release file代号或组件名错误curl -I .../dists/noble/Release修正源条目中的代号unknown authorityCA 缺失或时间不准date 重装 ca-certificates校准时间并重装 CA 包permission deniedkeyring 文件不可读ls -l .../docker.gpgchmod ar修复表格里是浓缩后的常见场景。实际排查时不要拘泥于单个报错文本要把源条目、keyring 文件、网络环境、系统时间放在一起看。绝大多数情况下一件事做好了——密钥正确导入到独立 keyring 并被signed-by引用——GPG 类错误会消失大半。5. 关于密钥管理我踩过几次坑之后的一些习惯5.1 每个仓库一个专用 keyring不要全局信任我在很长一段时间里都习惯把所有第三方 GPG 密钥一股脑导进/etc/apt/trusted.gpg.d/因为早年教程都这么写。后来改成独立 keyring 后才真正意识到全局信任的风险边界有多大一个被攻陷或误用的密钥可以给这台机器上所有仓库的包开绿灯而独立 keyring 配合signed-by只是把这个仓库的信任范围圈在一个文件里。哪怕要维护 Docker 和其他多个第三方源我也坚持每个源一个.gpg文件。后续发现某个第三方仓库不再维护移除时也很干净删掉 keyring 和源文件什么都不剩。5.2 升级系统后先确认上游仓库支持新代号Ubuntu 发布新版本后第三方仓库不一定立刻跟进。Ubuntu 24.04 发布时多数主流软件都已经补上 noble 目录但总有个别仓库会慢几周。如果你在apt update时看到仓库不可用的报错先别急着怀疑自己的操作拿 curl 去访问一下dists/noble/Release返回 404 就是上游还没跟上来。这种情况只能等上游更新或者暂时用旧版本源过渡但不要在新系统里长期混用旧代号源依赖解析迟早出问题。5.3 把配置固化成脚本避免重复踩坑我现在装新机器的时候会把密钥导入、源文件写入整理成一个简短脚本每次直接运行sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable | sudo tee /etc/apt/sources.list.d/docker.list sudo apt update脚本里刻意不用旧的apt-key写法也不把源塞进主sources.list这样即使半年后再跑也没问题。有个小技巧可以让脚本在不同版本间通用直接取当前系统的代号而不是写死 noble。CODENAME$(. /etc/os-release echo $VERSION_CODENAME) echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $CODENAME stable | sudo tee /etc/apt/sources.list.d/docker.list只要上游仓库已经支持当前系统这个脚本就能自动适配版本省去每次手改代号的麻烦。这也是我在反复遇到 GPG 错误后最终沉淀下来的习惯与其每次修不如把正确流程固定下来。