首页/新闻资讯/正文详情

Docker 多阶段构建把镜像从 1.2GB 压到 90MB,为什么 COPY --from 反而更容易踩权限坑

发布时间:2026/11/5 3:51:18 来源:云帆数科 栏目:资讯中心
Docker 多阶段构建把镜像从 1.2GB 压到 90MB,为什么 COPY --from 反而更容易踩权限坑
本文摘要文中命令与代码块可直接复制执行未实测的结论均已单独标注。文中给出了可复现的环境与操作步骤并标注了哪些结论已经验证、哪些仍属推测。一、问题与结论团队把 MySQL 从 5.7 升级到 8.0 后需要一个 Go 工具扫描所有表的 DDL确认每张表的编码已从utf8mb4MySQL 5.7 默认迁移到 8.0 引入的utf8mb4_0900_ai_ci排序规则。工具用 Docker 多阶段构建打包构建阶段基于golang:1.22约 1.2GB运行阶段基于alpine:3.19约 7MB最终镜像压到约 90MB。docker build全绿docker push成功CI 流水线没有任何告警——但部署后进程启动即退出2025/06/15 08:30:15 无法创建日志文件: open access.log: permission denied结论COPY --from复制的文件默认归属 UID:GID0:0rootUSER指令只影响其后跟随的RUN、CMD、ENTRYPOINT不追溯修改已存在文件的归属。非 root 进程在 root:root 755 的工作目录中写文件时内核返回 EACCES。二、排查与选择依据先画归属矩阵把每个路径的对象、归属和创建时机列清楚对象归属权限创建时机/app目录root:root755WORKDIR以 root 身份创建/app/server二进制root:root755COPY --from无--chown进程身份uid 1000appuser—USER指令崩溃机制四步走进程以 uid 1000 启动 → 工作目录为/app755非 root 无写权限→ 应用执行os.OpenFile(access.log, os.O_CREATE, ...)→ 内核检查 uid 1000 对/app无写权限返回 EACCES。hadolint 等 lint 工具不会报此问题——USER和COPY各自用法都没错问题在两者的交互效果。如果流水线只做到docker build docker push这个缺陷会一直潜伏到部署后才暴露。替代方案与取舍方案选择条件代价与边界--chown 目录chown通用 Linux 容器推荐默认--chown依赖 BuildKit用户名须在目标镜像/etc/passwd中存在数字 UID--chown1000:1000最终阶段极简如 scratch无/etc/passwd容器内whoami等工具可能返回unknown应用改写日志路径到/tmp仅临时文件/日志场景需改应用代码/tmp重启后数据丢失distroless 基础镜像内置 nonroot 用户生产安全基线要求高无 shell、无包管理器线上排查依赖kubectl debug等外部手段不该用本文方案的情况Windows 容器构建--chown不生效或 Docker Engine 23.0 且未设置DOCKER_BUILDKIT1classic builder 下--chown行为不完整。Docker Desktop 4.19 起默认启用 BuildKit。三、关键原理Dockerfile reference 对COPY的描述复制到目标路径的文件默认以 UID:GID0:0归属除非使用--chown参数。对USER的描述设置运行用户用于其后的RUN、CMD和ENTRYPOINT指令——不改变已有文件归属也不改变COPY的写入身份。--chown使用用户名时解析发生在目标镜像最终FROM的/etc/passwd中。如果RUN adduser在COPY --chown之后执行BuildKit 会因找不到用户名而构建失败。使用数字 UID如--chown1000:1000则不依赖/etc/passwd。关键陷阱叠加WORKDIR /app创建的目录归属为 root:root 755。COPY --chownappuser:appuser /build/server /app/server只改变/app/server的归属不改变/app目录本身。应用若需在工作目录下创建日志或临时文件仍然 EACCES。顺序约束为RUN adduser→chown目录 →COPY --chown三者不可颠倒。四、可运行示例环境Docker Engine ≥ 23.0BuildKit 默认启用Linux amd64。main.go模拟 MySQL 迁移校验服务packagemainimport(fmtlognet/httpos)funcmain(){logFile,err:os.OpenFile(access.log,os.O_CREATE|os.O_WRONLY|os.O_APPEND,0644)iferr!nil{log.Fatalf(无法创建日志文件: %v,err)}deferlogFile.Close()http.HandleFunc(/check,func(w http.ResponseWriter,r*http.Request){logFile.WriteString(fmt.Sprintf(%s %s\n,r.URL.Path,r.RemoteAddr))fmt.Fprintln(w,{status:ok,note:utf8mb4_0900_ai_ci verified})})log.Println(listening on :8080)log.Fatal(http.ListenAndServe(:8080,nil))}go.modmodule mysql-mig-checker go 1.22有 bug 的 Dockerfile构建成功运行时崩溃FROM golang:1.22-alpine AS builder WORKDIR /build COPY go.mod main.go ./ RUN CGO_ENABLED0 go build -o /build/server . FROM alpine:3.19 RUN adduser -D -u 1000 appuser WORKDIR /app COPY --frombuilder /build/server /app/server USER appuser EXPOSE 8080 CMD [/app/server]操作步骤dockerbuild-tmig-checker.dockerrun--rm-p8080:8080 mig-checker预期输出2025/06/15 08:30:15 无法创建日志文件: open access.log: permission denied实际输出与预期一致——构建成功进程因 EACCES 退出。常见失败先 COPY 后 adduser如果把RUN adduser移到COPY --chownappuser:appuser之后BuildKit 报错目标镜像/etc/passwd中没有appuser记录用户名无法解析。修复方法调整顺序先adduser再COPY --chown。修复后的 DockerfileFROM golang:1.22-alpine AS builder WORKDIR /build COPY go.mod main.go ./ RUN CGO_ENABLED0 go build -o /build/server . FROM alpine:3.19 RUN adduser -D -u 1000 appuser \ mkdir -p /app chown appuser:appuser /app WORKDIR /app COPY --frombuilder --chownappuser:appuser /build/server /app/server USER appuser EXPOSE 8080 CMD [/app/server]改动两处顺序有讲究RUN中增加chown appuser:appuser /app在adduser之后COPY增加--chownappuser:appuser。修复后重新执行docker run服务正常监听:8080访问[http://localhost:8080/check](http://localhost:8080/check)返回 JSON。五、验证结果与边界检查项修复前修复后docker build成功成功进程启动EACCES 退出正常监听:8080/app目录归属root:rootappuser:appuser/app/server归属root:rootappuser:appuser已知边界--chown在 classic builderEngine 23.0 且未设DOCKER_BUILDKIT1下行为不完整Windows 容器构建中--chown不生效极简镜像scratch中使用数字 UID--chown时容器内id命令可能不可用镜像从 1.2GB 压到 90MB 的收益依然成立多阶段构建本身没有问题——问题出在归属交接的细节上。建议在 CI 中增加一步docker run冒烟测试覆盖构建全绿但运行时崩溃这类延迟暴露的缺陷。参考资料Dockerfile reference — COPY 指令Dockerfile reference — USER 指令BuildKit 构建器文档

相关推荐

Flutter 可以更直接地调用原生 API 了,Dart Direct Native Interop
Flutter 可以更直接地调用原生 API 了,Dart Direct Native Interop

最近刚好有网友聊这个,就展开聊聊吧,严格来说,Direct Native Interop 确实不算是最近更新的, 整个时间线大概类似: 2024 年:Dart 3.5 开始在完善 C、Java、Kotlin、Objective-C 的直接互操作能力 2025 年 … · 2026/11/5 3:51:18

【资源自取】CraxsRat 7.4V3:远程桌面 3 步连上,跨平台远程控制工具完整指南
【资源自取】CraxsRat 7.4V3:远程桌面 3 步连上,跨平台远程控制工具完整指南

【资源自取】CraxsRat 7.4V3:远程桌面 3 步连上,跨平台远程控制工具完整指南 CraxsRat 7.4V3 是一款远程控制工具,帮你在本地远程操作另一台 Windows、Linux 或 macOS 机器。维护多台服务器、经常帮家人朋友远程修电脑的人,都值得… · 2026/11/5 3:51:18

SAP abap-cleaner 不是 Pretty Printer,而是一套可自动执行的 Clean ABAP 重构引擎
SAP abap-cleaner 不是 Pretty Printer,而是一套可自动执行的 Clean ABAP 重构引擎

2026 年 6 月,SAP 的 abap-cleaner 仓库增加了正式的 Visual Studio Code 扩展。到了 2026 年 7 月发布的 v1.29.0,独立应用和 Visual Studio Code 扩展又开始携带最小化 JRE,安装门槛进一步降低。回头看这个项目 2023 年 4 月第一次开源时,它只有 57 条 cleanup rule 和 1… · 2026/11/5 3:51:18

焊接还是压接?USB、DC 线焊点虚焊的判定与工艺边界
焊接还是压接?USB、DC 线焊点虚焊的判定与工艺边界

焊点是冶金连接,压接是冷变形机械连接,失效模式不同:压接坏了是电阻慢慢爬、通电发热;焊点坏了常常一次震动就断,而静态通电还是通的。判焊点好坏,第一判据是润湿角,不是「亮不亮」。大电流、强… · 2026/11/5 5:30:08

嵌入式 Linux 笔记:应用程序、设备驱动与内核之间的关系
嵌入式 Linux 笔记:应用程序、设备驱动与内核之间的关系

一、整体关系在典型嵌入式 Linux 系统中:应用程序运行在用户空间,负责实现产品业务功能。设备驱动通常运行在内核空间,负责控制具体硬件。Linux 内核负责进程调度、内存管理、文件系统、网络协议栈、设备管理,并提供系统调用和设备… · 2026/11/5 5:30:08

高精度计算入门与immense数据模型精讲(七)
高精度计算入门与immense数据模型精讲(七)

跳转链接 高精度计算入门与immense数据模型精讲(一)高精度计算入门与immense数据模型精讲(二)高精度计算入门与immense数据模型精讲(三)高精度计算入门与immense数据模型精讲(四)高… · 2026/11/5 5:30:08

OBIS 平台|二维码丢了,Matter 设备为什么可能再也配不上网?
OBIS 平台|二维码丢了,Matter 设备为什么可能再也配不上网?

Matter 设备用上几年,很容易遇到这样一个问题。用户换了路由器,或者把设备恢复了出厂设置,需要重新配网。打开 App,提示扫描设备上的二维码。结果把设备翻过来一看,二维码已经磨得看不清了。 联系客服,客服… · 2026/11/5 5:30:08

深度 | DeepSeek 融资 1000 亿落定:领投的不是 VC,是宁德时代
深度 | DeepSeek 融资 1000 亿落定:领投的不是 VC,是宁德时代

10 月 22 日,Reuters、Bloomberg、WSJ 三家通讯社几乎同时确认:DeepSeek 完成了约 150 亿美元融资,折合近 1000 亿元人民币,投前估值约 5000 亿元。这是中概公司最大的一笔单笔私募 AI 融资,也让它的估值在半年内从 6 … · 2026/11/5 5:30:08

CMake 实战指南:从基础语法到静态库/动态库制作与链接
CMake 实战指南:从基础语法到静态库/动态库制作与链接

目录 1. CMAKE 的基本使用 1.1 注释1.2 使用 set 命令在 cmake 中进行变量的定义1.3 CMAKE 中设置 C 标准1.4 可执行文件的输出路径1.5 文件的查找1.6 头文件的引入 2. 制作动态库和静态库 2.1 指定库文件的输出路径 3. 包含库文件 3.1 链接系统动态库 4. 总结与经典面试题 4.… · 2026/11/5 5:29:08

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码