DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Compose 运行时能读取 Secret,Dockerfile 构建却找不到

区分服务运行时 secrets 与 build.secrets 的授权范围,为构建步骤显式提供 Secret,并验证 ID、后端和实际执行结果。

Compose 启动的容器能读到 /run/secrets/build_token,同一项目的 Dockerfile 却在 RUN --mount=type=secret 处提示找不到 Secret。这通常值得先检查 YAML 层级:服务的 secrets 授权运行中的容器,build.secrets 才授权镜像构建。只在顶层声明文件,或只在服务下授权,都不会自动把它交给构建步骤。

下面限定 Linux 容器、Docker Engine、BuildKit 和支持构建 Secret 的 Docker Compose,Compose 的这项支持从 2.5.0 起提供。命令采用 docker compose。连接 Podman 兼容接口、使用其他构建后端或旧版 Compose 时,不能仅凭版本字符串认定行为相同;需要先确认实际后端。

先区分缺少授权、ID 不同和文件不可读

例如下面的配置只给运行时容器提供文件,构建没有得到授权:

services:
  app:
    build: .
    secrets:
      - build_token

secrets:
  build_token:
    file: /secure/build/token

/secure/build/token 是运行 Compose 的构建客户端上的占位路径。文件应由现有凭据管理流程提供,放在构建上下文之外,并限制访问;不要为复现问题把真实令牌提交到项目。

核对 Dockerfile 的 Secret ID,再对照配置。id=build_token 应对应 build.secrets 里的授权项。长语法的 source 是顶层 Secret 名称,target 是交给 Dockerfile 的 ID,两者可以不同;这里用短语法让名称保持一致。

如果错误发生在 required=true 的挂载准备阶段,表示所需 Secret 没有提供。若挂载已经存在,只是应用读文件时报权限错误,应检查该条 RUN 的用户、目标路径和文件模式,那是另一个分支。先不要用 chmod 777 或把构建改成特权模式处理“没有这个 ID”。

把授权放到 build 下,按实际用途保留运行时授权

将构建部分改成长语法,并在其中声明 Secret:

services:
  app:
    build:
      context: .
      secrets:
        - build_token

secrets:
  build_token:
    file: /secure/build/token

这里没有服务级 secrets,因为示例只验证构建使用。若应用启动后也确实需要同一个凭据,可以另外保留服务级授权;如果只是构建下载依赖需要它,就不应为了构建成功给运行时容器增加访问权。

用独立测试目录里的 Dockerfile 验证这一层配置。先使用受保护的、非空的测试文件,不要直接接入真实生产凭据:

# syntax=docker/dockerfile:1
FROM busybox:1.37
RUN --mount=type=secret,id=build_token,required=true \
    test -s /run/secrets/build_token

这份 Dockerfile 只检查文件存在且非空,不输出内容,也不是可直接部署的业务镜像。required=true 会在需要执行该指令却没有 Secret 时失败;test -s 进一步拒绝空文件。默认文件路径是 /run/secrets/ 加 ID,改变挂载 target 后也必须同步实际读取路径。

在项目中应保留原来的基础镜像、用户和构建步骤,把挂载加到真正需要凭据的那条 RUN。Secret 仅在该指令执行期间可用;分成后面的另一条 RUN 使用时,需要再次显式挂载,不能依靠前一层留下凭据。

验证必须让检查步骤真正执行

确认测试目录、Compose 文件和后端后,仅构建指定服务:

docker compose version
docker compose build --no-cache app

这里使用 --no-cache 是为了让测试步骤实际执行。构建缓存命中不会重新检查文件或认证;Secret 内容变化本身也不会让缓存失效。验证结束后按原项目的缓存策略构建,不需要把每次构建都改成无缓存,更不需要清空所有缓存。

成功条件是测试 RUN 被执行并返回成功。之后再在受控构建环境恢复实际下载或认证命令,验证它按预期取得依赖。文件非空只证明这次挂载可读,不证明令牌有效、权限足够或远端仓库正常。

若仍失败,沿着配置链逐项核对:实际使用的是哪份 Compose 文件;授权是否写在同一服务的 build 下;顶层名称和 Dockerfile ID 是否一致;客户端能否访问源文件;当前连接的是否为支持该功能的构建后端。不要输出整份凭据或完整进程环境来做检查。

避免把缺失问题变成凭据泄露

Secret 挂载不会自动把文件保存进镜像,但读取它的命令仍有能力输出内容、复制到产物或写进安装日志。只给可信的构建步骤授权,不要把 test -s 换成 cat 来证明文件存在,也不要用 ARG、ENV 或 COPY 临时绕过授权层级。

合入业务配置前保存原 Compose 文件、Dockerfile 和已验证镜像。回退时恢复构建定义或使用原镜像,不必停止当前服务来验证这份最小构建。若此前已经把秘密打印到日志或写进镜像,配置修复不会删除那些副本,应按凭据管理流程处理暴露记录并轮换凭据。