run指令在构建镜像时执行命令并创建新层,需合并命令减少层数、避免硬编码敏感信息、通过user切换非root用户、利用--mount=type=secret传递密钥,且推荐使用buildkit增强网络与权限控制。

RUN 指令的基本用法
RUN 在镜像构建过程中执行 shell 命令,每条 RUN 都会创建一个新的中间层(layer),并提交结果。常见写法有两种:
-
Shell 形式(默认):
RUN apt-get update && apt-get install -y curl -
Exec 形式(推荐用于规避 shell 解析问题):
RUN ["apt-get", "update"]—— 注意:不能直接链式执行,需用脚本或分多行
构建时的权限控制
Docker 构建默认以 root 用户身份运行所有 RUN 指令,但可通过以下方式限制或切换权限:
-
使用非 root 用户执行后续 RUN(需先创建用户):
RUN groupadd -g 1001 -r appgroup && useradd -u 1001 -r -g appgroup -s /bin/bash appuserUSER appuser
后续的RUN(如果仍需)必须显式切回 root,例如:RUN sudo apt-get install ...(前提是已安装并配置 sudo) -
避免在 RUN 中硬编码密码或密钥:不要写
RUN echo "secret=xxx" > .env—— 这些会留在镜像层中,可被docker history查看 -
用 --mount=type=secret 传递敏感数据(Docker BuildKit):
开启 BuildKit 后,可在 RUN 中安全挂载临时密钥:RUN --mount=type=secret,id=mytoken cat /run/secrets/mytoken > /app/token.txt
构建完成后,该 secret 不会保留在镜像里
安全与最佳实践
构建阶段的权限限制本质是减少攻击面和误操作风险:
-
合并 RUN 指令减少层数:把多个 apt 安装写成一行,避免残留缓存:
✅RUN apt-get update && apt-get install -y python3-pip && rm -rf /var/lib/apt/lists/*
❌ 分成多条 RUN,中间层可能含未清理的包索引 -
禁用不必要的能力:虽然 RUN 本身不支持 cap-drop,但可通过构建时参数限制(如
docker build --security-opt=no-new-privileges),防止 RUN 中提权 -
限制网络访问(BuildKit 支持):
RUN --network=none pip install flask可禁用构建时网络,强制离线依赖管理 - 用 .dockerignore 排除敏感文件:防止意外 COPY 进源码目录里的配置、密钥,间接影响 RUN 行为











