mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 12:21:17 +00:00
Use a better structure
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# USER 指定当前用户
|
||||
## USER 指定当前用户
|
||||
|
||||
## 基本语法
|
||||
### 基本语法
|
||||
|
||||
```docker
|
||||
USER <用户名>[:<用户组>]
|
||||
@@ -11,7 +11,7 @@ USER <UID>[:<GID>]
|
||||
|
||||
---
|
||||
|
||||
## 为什么要使用 USER
|
||||
### 为什么要使用 USER
|
||||
|
||||
> 笔者强调:以非 root 用户运行容器是最重要的安全实践之一。
|
||||
|
||||
@@ -33,52 +33,52 @@ root 用户运行的风险:
|
||||
|
||||
---
|
||||
|
||||
## 基本用法
|
||||
### 基本用法
|
||||
|
||||
### 创建并切换用户
|
||||
#### 创建并切换用户
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
|
||||
# 1. 创建用户和组
|
||||
## 1. 创建用户和组
|
||||
RUN addgroup -g 1001 appgroup && \
|
||||
adduser -u 1001 -G appgroup -D appuser
|
||||
|
||||
# 2. 设置目录权限
|
||||
## 2. 设置目录权限
|
||||
WORKDIR /app
|
||||
COPY --chown=appuser:appgroup . .
|
||||
|
||||
# 3. 切换用户
|
||||
## 3. 切换用户
|
||||
USER appuser
|
||||
|
||||
# 4. 后续命令以 appuser 身份运行
|
||||
## 4. 后续命令以 appuser 身份运行
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
### 使用 UID/GID
|
||||
#### 使用 UID/GID
|
||||
|
||||
```docker
|
||||
# 也可以使用数字
|
||||
## 也可以使用数字
|
||||
USER 1001:1001
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 用户必须已存在
|
||||
### 用户必须已存在
|
||||
|
||||
`USER` 指令只能切换到**已存在**的用户:
|
||||
|
||||
```docker
|
||||
# ❌ 错误:用户不存在
|
||||
## ❌ 错误:用户不存在
|
||||
USER nonexistent
|
||||
# Error: unable to find user nonexistent
|
||||
## Error: unable to find user nonexistent
|
||||
|
||||
# ✅ 正确:先创建用户
|
||||
## ✅ 正确:先创建用户
|
||||
RUN useradd -r -s /bin/false appuser
|
||||
USER appuser
|
||||
```
|
||||
|
||||
### 创建用户的方式
|
||||
#### 创建用户的方式
|
||||
|
||||
**Debian/Ubuntu**:
|
||||
|
||||
@@ -104,19 +104,19 @@ RUN addgroup -g 1001 -S appgroup && \
|
||||
|
||||
---
|
||||
|
||||
## 运行时切换用户
|
||||
### 运行时切换用户
|
||||
|
||||
### 使用 gosu(推荐)
|
||||
#### 使用 gosu(推荐)
|
||||
|
||||
在 ENTRYPOINT 脚本中切换用户时,不要使用 `su` 或 `sudo`,应使用 [gosu](https://github.com/tianon/gosu):
|
||||
|
||||
```docker
|
||||
FROM debian:bookworm
|
||||
|
||||
# 创建用户
|
||||
## 创建用户
|
||||
RUN groupadd -r redis && useradd -r -g redis redis
|
||||
|
||||
# 安装 gosu
|
||||
## 安装 gosu
|
||||
RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
@@ -130,14 +130,14 @@ CMD ["redis-server"]
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 以 root 执行初始化
|
||||
## 以 root 执行初始化
|
||||
chown -R redis:redis /data
|
||||
|
||||
# 用 gosu 切换到 redis 用户运行服务
|
||||
## 用 gosu 切换到 redis 用户运行服务
|
||||
exec gosu redis "$@"
|
||||
```
|
||||
|
||||
### 为什么不用 su/sudo
|
||||
#### 为什么不用 su/sudo
|
||||
|
||||
| 问题 | su/sudo | gosu |
|
||||
|------|---------|------|
|
||||
@@ -148,38 +148,38 @@ exec gosu redis "$@"
|
||||
|
||||
---
|
||||
|
||||
## 运行时覆盖用户
|
||||
### 运行时覆盖用户
|
||||
|
||||
使用 `-u` 或 `--user` 参数:
|
||||
|
||||
```bash
|
||||
# 以指定用户运行
|
||||
## 以指定用户运行
|
||||
$ docker run -u 1001:1001 myimage
|
||||
|
||||
# 以 root 运行(调试时)
|
||||
## 以 root 运行(调试时)
|
||||
$ docker run -u root myimage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文件权限处理
|
||||
### 文件权限处理
|
||||
|
||||
切换用户后,确保应用有权访问文件:
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
|
||||
# 创建用户
|
||||
## 创建用户
|
||||
RUN adduser -D -u 1001 appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 方式1:使用 --chown
|
||||
## 方式1:使用 --chown
|
||||
COPY --chown=appuser:appuser . .
|
||||
|
||||
# 方式2:手动 chown(减少层数)
|
||||
# COPY . .
|
||||
# RUN chown -R appuser:appuser /app
|
||||
## 方式2:手动 chown(减少层数)
|
||||
## COPY . .
|
||||
## RUN chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
CMD ["node", "server.js"]
|
||||
@@ -187,41 +187,41 @@ CMD ["node", "server.js"]
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
### 最佳实践
|
||||
|
||||
### 1. 始终使用非 root 用户
|
||||
#### 1. 始终使用非 root 用户
|
||||
|
||||
```docker
|
||||
# ✅ 推荐
|
||||
## ✅ 推荐
|
||||
RUN adduser -D appuser
|
||||
USER appuser
|
||||
CMD ["myapp"]
|
||||
|
||||
# ❌ 避免
|
||||
## ❌ 避免
|
||||
CMD ["myapp"] # 以 root 运行
|
||||
```
|
||||
|
||||
### 2. 使用固定 UID/GID
|
||||
#### 2. 使用固定 UID/GID
|
||||
|
||||
便于在宿主机和容器间共享文件:
|
||||
|
||||
```docker
|
||||
# 使用常见的非 root UID
|
||||
## 使用常见的非 root UID
|
||||
RUN addgroup -g 1000 -S appgroup && \
|
||||
adduser -u 1000 -S -G appgroup appuser
|
||||
USER 1000:1000
|
||||
```
|
||||
|
||||
### 3. 多阶段构建中的 USER
|
||||
#### 3. 多阶段构建中的 USER
|
||||
|
||||
```docker
|
||||
# 构建阶段可以用 root
|
||||
## 构建阶段可以用 root
|
||||
FROM node:20 AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install && npm run build
|
||||
|
||||
# 生产阶段用非 root
|
||||
## 生产阶段用非 root
|
||||
FROM node:20-alpine
|
||||
RUN adduser -D appuser
|
||||
WORKDIR /app
|
||||
@@ -232,9 +232,9 @@ CMD ["node", "server.js"]
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
### 常见问题
|
||||
|
||||
### Q: 权限被拒绝
|
||||
#### Q: 权限被拒绝
|
||||
|
||||
```bash
|
||||
permission denied: '/app/data.log'
|
||||
@@ -246,7 +246,7 @@ permission denied: '/app/data.log'
|
||||
RUN mkdir -p /app/data && chown appuser:appuser /app/data
|
||||
```
|
||||
|
||||
### Q: 无法绑定低于 1024 的端口
|
||||
#### Q: 无法绑定低于 1024 的端口
|
||||
|
||||
非 root 用户无法绑定 80、443 等端口。
|
||||
|
||||
@@ -256,7 +256,7 @@ RUN mkdir -p /app/data && chown appuser:appuser /app/data
|
||||
|
||||
---
|
||||
|
||||
## 本章小结
|
||||
### 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -266,8 +266,8 @@ RUN mkdir -p /app/data && chown appuser:appuser /app/data
|
||||
| **运行时覆盖** | `docker run -u` |
|
||||
| **切换工具** | 使用 gosu,不用 su/sudo |
|
||||
|
||||
## 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [安全](../../security/README.md):容器安全实践
|
||||
- [ENTRYPOINT](entrypoint.md):入口脚本中的用户切换
|
||||
- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 安全
|
||||
- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 安全
|
||||
|
||||
Reference in New Issue
Block a user