> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/docker_practice/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.11_user.md).

# 7.11 USER 指定当前用户

## 7.11.1 基本语法

```docker
USER <用户名>[:<用户组>]
USER <UID>[:<GID>]
```

`USER` 指令切换后续指令 (RUN、CMD、ENTRYPOINT) 的执行用户。

***

## 7.11.2 为什么要使用 USER

> 笔者强调：以非 root 用户运行容器是最重要的安全实践之一。

```mermaid
flowchart LR
    subgraph Root ["root 用户运行的风险："]
        direction TB
        R_C["容器内 root"] -- 可能逃逸 --> R_H["宿主机 root"]
        R_C -- 漏洞利用 --> R_Control["完全控制宿主机"]
    end

    subgraph NonRoot ["非 root 用户运行："]
        direction TB
        NR_C["容器内普通用户"] -- 逃逸后 --> NR_H["宿主机普通用户"]
        NR_C -- 权限受限，危害降低 --> NR_Safe["无法控制系统"]
    end
```

***

## 7.11.3 基本用法

### 创建并切换用户

```docker
FROM node:22-alpine

## 1. 创建用户和组

RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -D appuser

## 2. 设置目录权限

WORKDIR /app
COPY --chown=appuser:appgroup . .

## 3. 切换用户

USER appuser

## 4. 后续命令以 appuser 身份运行

CMD ["node", "server.js"]
```

### 使用 UID/GID

```docker
## 也可以使用数字

USER 1001:1001
```

***

## 7.11.4 用户必须已存在

`USER` 指令只能切换到 **已存在** 的用户：

```docker
## ❌ 错误：用户不存在

USER nonexistent

## Error: unable to find user nonexistent

## ✅ 正确：先创建用户

RUN useradd -r -s /bin/false appuser
USER appuser
```

### 创建用户的方式

**Debian/Ubuntu**：

```docker
RUN groupadd -r appgroup && \
    useradd -r -g appgroup appuser
```

**Alpine**：

```docker
RUN addgroup -g 1001 -S appgroup && \
    adduser -u 1001 -S -G appgroup appuser
```

| 选项                              | 说明         |
| ------------------------------- | ---------- |
| `-r` (useradd) / `-S` (adduser) | 创建系统用户     |
| `-g`                            | 指定主组       |
| `-G`                            | 指定附加组      |
| `-u`                            | 指定 UID     |
| `-s /bin/false`                 | 禁用登录 shell |

***

## 7.11.5 运行时切换用户

### 使用 gosu：推荐

在 ENTRYPOINT 脚本中切换用户时，不要使用 `su` 或 `sudo`，应使用 [gosu](https://github.com/tianon/gosu)：

```docker
FROM debian:bookworm

## 创建用户

RUN groupadd -r redis && useradd -r -g redis redis

## 安装 gosu

RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*

COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["redis-server"]
```

**docker-entrypoint.sh**：

```bash
#!/bin/bash
set -e

## 以 root 执行初始化

chown -R redis:redis /data

## 用 gosu 切换到 redis 用户运行服务

exec gosu redis "$@"
```

### 为什么不用 su/sudo

| 问题     | su/sudo | gosu    |
| ------ | ------- | ------- |
| TTY 要求 | 需要      | 不需要     |
| 信号传递   | 不正确     | 正确      |
| 子进程    | 是       | exec 替换 |
| 容器中使用  | ❌       | ✅       |

***

## 7.11.6 运行时覆盖用户

使用 `-u` 或 `--user` 参数：

```bash
## 以指定用户运行

$ docker run -u 1001:1001 myimage

## 以 root 运行（调试时）

$ docker run -u root myimage
```

***

## 7.11.7 文件权限处理

切换用户后，确保应用有权访问文件：

```docker
FROM node:22-alpine

## 创建用户

RUN adduser -D -u 1001 appuser

WORKDIR /app

## 方式1：使用 --chown

COPY --chown=appuser:appuser . .

## 方式2：手动 chown（减少层数）

## COPY . .

## RUN chown -R appuser:appuser /app

USER appuser
CMD ["node", "server.js"]
```

***

## 7.11.8 最佳实践

### 1. 始终使用非 root 用户

```docker
## ✅ 推荐

RUN adduser -D appuser
USER appuser
CMD ["myapp"]

## ❌ 避免

CMD ["myapp"]  # 以 root 运行
```

### 2. 使用固定 UID/GID

便于在宿主机和容器间共享文件：

```docker
## 使用常见的非 root UID

RUN addgroup -g 1000 -S appgroup && \
    adduser -u 1000 -S -G appgroup appuser
USER 1000:1000
```

### 3. 多阶段构建中的 USER

```docker
## 构建阶段可以用 root

FROM node:22 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build

## 生产阶段用非 root

FROM node:22-alpine
RUN adduser -D appuser
WORKDIR /app
COPY --from=builder --chown=appuser:appuser /app/dist .
USER appuser
CMD ["node", "server.js"]
```

***

## 7.11.9 常见问题

### Q：权限被拒绝

```bash
permission denied: '/app/data.log'
```

**解决**：确保目录权限正确

```docker
RUN mkdir -p /app/data && chown appuser:appuser /app/data
```

### Q：无法绑定低于 1024 的端口

非 root 用户无法绑定 80、443 等端口。

**解决**：

1. 使用高端口 (如 8080)
2. 在运行时映射端口：`docker run -p 80:8080`

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.11_user.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
