USER 指令是什么
USER 指定其后指令以及容器运行进程的默认身份。安全基线要求应用不以 root 运行,一旦进程被突破,影响面会小很多。正确顺序是先完成系统级安装,再创建用户、调整文件属主,最后切到非 root 身份。
基本信息
| 作用 | 影响其后的 RUN 指令与容器启动进程的身份 |
|---|---|
| 前置 | 先用 groupadd 与 useradd 建用户,或直接写数字 UID |
| 文件归属 | USER 之后 RUN 生成的文件归该用户所有 |
| 复制归属 | COPY 用 --chown 一步设定,比事后 chown 更省层 |
| 运行时覆盖 | docker run -u 可临时改用其他身份 |
| 基础镜像 | 部分官方镜像已内置非 root 用户,可直接引用 |
常见权限问题
| 现象 | 原因 | 处置 |
|---|---|---|
| 启动即退出且日志很少 | 目录属主仍是 root | 用 COPY --chown 或 chown 修正 |
| 写日志报权限拒绝 | 日志目录由 root 创建 | 把目录属主改成运行用户 |
| 装包失败 | USER 之后执行了系统级命令 | 把安装步骤移到 USER 之前 |
| 挂载宿主目录后无权限 | 宿主目录权限与容器用户不匹配 | 调整宿主目录属主或权限 |
非 root 运行示例
非 root 运行示例
FROM node:20-alpine
WORKDIR /app
RUN addgroup -S app && adduser -S app -G app # 先建系统用户与组
COPY --chown=app:app package*.json ./ # 复制时就设好属主
RUN npm ci --omit=dev
COPY --chown=app:app . .
USER app # 之后以非 root 运行
CMD ["node","server.js"]典型使用场景
- 满足安全基线,用非 root 身份运行应用进程
- 多阶段构建的运行阶段切换身份,且不带构建工具
- 与只读根文件系统配合,把可写路径收到最小
- 交付前按等保或合规要求收紧运行身份
USER 之后的 RUN 不再拥有 root 权限:装系统包、写系统目录都会失败,系统级操作必须全部放在切换之前。
使用数字 UID 可以不依赖镜像内是否创建了同名用户,在只读根文件系统或受限权限策略下更省事。
切了 USER 却没调整文件属主,应用可能直接启动失败,而日志里往往只看到笼统的权限错误,排查成本很高。