主要改动: - Docker Compose 配置优化: * 为所有环境的 MySQL 服务添加 stop_grace_period: 60s(增加优雅关闭时间) * 添加 stop_signal: SIGTERM(使用 SIGTERM 信号优雅停止) * 添加 init: true(使用 init 进程管理子进程,避免僵尸进程) - Makefile 改进: * 所有 docker-down-* 命令添加自动重试机制 * 自动检测权限错误并重启 rootless Docker 服务 * 显示完整的 Docker Compose 进度信息(包括容器状态变化) - README.md 更新: * 添加 Docker 权限问题的详细解决方案 * 包括 rootless Docker 的特殊处理方法和自动重试机制说明 问题原因: MySQL 容器在 rootless Docker 环境下停止时遇到权限问题,需要更长的优雅关闭时间来处理 InnoDB 数据文件。 解决方案: 1. 增加 stop_grace_period 到 60 秒,给 MySQL 足够时间优雅关闭 2. 使用 init 进程管理子进程,避免权限问题 3. 在 Makefile 中添加自动检测和重试机制,无需手动重启 Docker 服务
770 lines
21 KiB
Markdown
770 lines
21 KiB
Markdown
# Yinli API
|
||
|
||
基于 Golang Gin 框架构建的高性能 RESTful API 服务,集成了 JWT 认证、Redis 缓存、频率限制、CORS 等安全特性。
|
||
|
||
## 🚀 技术架构
|
||
|
||
### 核心技术栈
|
||
|
||
- **Web 框架**: [Gin](https://gin-gonic.com/) - 高性能的 HTTP Web 框架
|
||
- **数据库**: [MySQL 8.0](https://dev.mysql.com/doc/) - 关系型数据库
|
||
- **缓存**: [Redis](https://redis.io/) - 内存数据库,用于缓存和频率限制
|
||
- **ORM**: [GORM](https://gorm.io/) - Go 语言 ORM 库
|
||
- **配置管理**: [Viper](https://github.com/spf13/viper) - 配置文件管理
|
||
- **认证**: [JWT](https://jwt.io/) - JSON Web Token 认证
|
||
- **文档**: [Swagger](https://swagger.io/) - API 文档自动生成
|
||
- **测试**: [Testify](https://github.com/stretchr/testify) - 测试框架
|
||
- **容器化**: [Docker](https://www.docker.com/) - 容器化部署
|
||
|
||
### 安全特性
|
||
|
||
- **JWT 认证**: 基于 JSON Web Token 的用户认证
|
||
- **CORS 支持**: 跨域资源共享配置
|
||
- **频率限制**: 基于 Redis 的 API 频率限制
|
||
- **密码加密**: 使用 bcrypt 加密用户密码
|
||
- **中间件保护**: 多层中间件安全防护
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
yinli-api/
|
||
├── src/ # 源代码目录
|
||
│ ├── main.go # 应用程序入口
|
||
│ ├── handler/ # HTTP 处理器
|
||
│ ├── middleware/ # 中间件
|
||
│ ├── model/ # 数据模型
|
||
│ ├── repository/ # 数据访问层
|
||
│ ├── service/ # 业务逻辑层
|
||
│ └── pkg/ # 可复用的包
|
||
│ ├── auth/ # 认证相关
|
||
│ ├── cache/ # 缓存操作
|
||
│ ├── config/ # 配置管理
|
||
│ └── database/ # 数据库连接
|
||
├── config/ # 配置文件
|
||
│ ├── dev.yaml # 开发环境配置
|
||
│ ├── stage.yaml # 预发布环境配置
|
||
│ └── prod.yaml # 生产环境配置
|
||
├── docker/ # Docker 相关文件
|
||
├── doc/ # API 文档
|
||
├── sql/ # 数据库脚本
|
||
├── test/ # 测试文件
|
||
├── build/ # 构建输出
|
||
├── Dockerfile # Docker 镜像构建文件
|
||
├── Makefile # 构建脚本
|
||
└── README.md # 项目说明
|
||
```
|
||
|
||
## 🛠️ 快速开始
|
||
|
||
### 环境要求
|
||
|
||
- Go 1.21+
|
||
- MySQL 8.0+
|
||
- Redis 6.0+
|
||
- Docker & Docker Compose (可选)
|
||
|
||
### 本地开发
|
||
|
||
1. **克隆项目**
|
||
```bash
|
||
git clone <repository-url>
|
||
cd yinli-api
|
||
```
|
||
|
||
2. **安装依赖**
|
||
```bash
|
||
make deps
|
||
```
|
||
|
||
3. **配置数据库**
|
||
```bash
|
||
# 创建数据库
|
||
mysql -u root -p < sql/init.sql
|
||
```
|
||
|
||
4. **启动 Redis**
|
||
```bash
|
||
redis-server
|
||
```
|
||
|
||
5. **启动开发环境**
|
||
```bash
|
||
make dev
|
||
```
|
||
|
||
### Docker 部署
|
||
|
||
项目支持三种环境的 Docker Compose 部署:dev(开发)、stage(预发布)、prod(生产)。
|
||
|
||
#### Docker 镜像配置(中国大陆用户)
|
||
|
||
如果在中国大陆使用 Docker,建议配置镜像加速器以提高镜像拉取速度。项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速拉取。
|
||
|
||
**方法1:配置 Docker 镜像加速器(推荐)**
|
||
|
||
根据 Docker 运行模式选择配置位置:
|
||
|
||
**标准 Docker(需要 root 权限):**
|
||
|
||
编辑或创建 `/etc/docker/daemon.json` 文件:
|
||
|
||
```bash
|
||
sudo mkdir -p /etc/docker
|
||
sudo tee /etc/docker/daemon.json <<-'EOF'
|
||
{
|
||
"registry-mirrors": [
|
||
"https://docker.m.daocloud.io",
|
||
"https://dockerproxy.com",
|
||
"https://docker.nju.edu.cn"
|
||
]
|
||
}
|
||
EOF
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl restart docker
|
||
```
|
||
|
||
**Rootless Docker(无需 root 权限):**
|
||
|
||
编辑或创建 `~/.config/docker/daemon.json` 文件:
|
||
|
||
```bash
|
||
mkdir -p ~/.config/docker
|
||
cat > ~/.config/docker/daemon.json <<-'EOF'
|
||
{
|
||
"registry-mirrors": [
|
||
"https://docker.m.daocloud.io",
|
||
"https://dockerproxy.com",
|
||
"https://docker.nju.edu.cn"
|
||
]
|
||
}
|
||
EOF
|
||
```
|
||
|
||
然后重启 rootless Docker(**重要:配置后必须重启才能生效**):
|
||
|
||
```bash
|
||
# 方法1:重启 rootless Docker 服务
|
||
systemctl --user restart docker
|
||
|
||
# 方法2:如果使用 dockerd-rootless,需要重启用户服务
|
||
pkill -HUP dockerd
|
||
# 或者重启整个 rootless Docker
|
||
systemctl --user stop docker.socket
|
||
systemctl --user start docker.socket
|
||
```
|
||
|
||
验证配置:
|
||
|
||
```bash
|
||
docker info | grep -A 10 "Registry Mirrors"
|
||
```
|
||
|
||
如果看到配置的镜像源列表,说明配置成功。
|
||
|
||
**方法2:使用环境变量(临时)**
|
||
|
||
```bash
|
||
# 设置 Docker 镜像代理
|
||
export DOCKER_REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
|
||
```
|
||
|
||
**常用国内镜像源(按推荐顺序):**
|
||
- DaoCloud:`https://docker.m.daocloud.io` ⭐ 推荐
|
||
- Docker 代理:`https://dockerproxy.com`
|
||
- 南京大学:`https://docker.nju.edu.cn`
|
||
- 上海交大:`https://docker.mirrors.sjtug.sjtu.edu.cn`
|
||
- 阿里云:`https://registry.cn-hangzhou.aliyuncs.com`(需要登录)
|
||
- 中科大:`https://docker.mirrors.ustc.edu.cn`(可能不稳定)
|
||
- 网易:`https://hub-mirror.c.163.com`(可能不稳定)
|
||
|
||
**重要提示:**
|
||
- 项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速
|
||
- 如果镜像加速器配置正确,Docker 会自动从配置的镜像源拉取镜像
|
||
- 如果遇到镜像拉取失败,请确保已重启 Docker 服务使配置生效:`sudo systemctl restart docker`
|
||
- **Go 模块下载**:Dockerfile 中已配置使用国内 Go 代理(`GOPROXY=https://goproxy.cn,direct`),无需额外配置
|
||
|
||
#### 开发环境部署
|
||
|
||
1. **生成 Docker Compose 文件(可选,文件已存在)**
|
||
```bash
|
||
make docker-compose-dev
|
||
```
|
||
|
||
2. **启动开发环境服务**
|
||
```bash
|
||
make docker-up-dev
|
||
```
|
||
|
||
3. **查看日志**
|
||
```bash
|
||
make docker-logs
|
||
```
|
||
|
||
4. **停止服务**
|
||
```bash
|
||
make docker-down-dev
|
||
```
|
||
|
||
#### 预发布环境部署
|
||
|
||
1. **启动预发布环境服务**
|
||
```bash
|
||
make docker-up-stage
|
||
```
|
||
|
||
2. **查看日志**
|
||
```bash
|
||
make docker-logs-stage
|
||
```
|
||
|
||
3. **停止服务**
|
||
```bash
|
||
make docker-down-stage
|
||
```
|
||
|
||
**注意:** 预发布环境使用不同的端口映射(MySQL: 3307, Redis: 6380),避免与开发环境冲突。
|
||
|
||
#### 生产环境部署
|
||
|
||
1. **设置环境变量(重要!)**
|
||
```bash
|
||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||
export REDIS_PASSWORD=your_redis_password
|
||
```
|
||
|
||
2. **启动生产环境服务**
|
||
```bash
|
||
make docker-up-prod
|
||
```
|
||
|
||
3. **查看日志**
|
||
```bash
|
||
make docker-logs-prod
|
||
```
|
||
|
||
4. **停止服务**
|
||
```bash
|
||
make docker-down-prod
|
||
```
|
||
|
||
**注意:**
|
||
- 生产环境使用不同的端口映射(MySQL: 3308, Redis: 6381)
|
||
- 生产环境配置了健康检查和自动重启策略
|
||
- 请务必在生产环境部署前修改配置文件中的敏感信息(JWT密钥、数据库密码等)
|
||
|
||
## 📋 可用命令
|
||
|
||
### 开发命令
|
||
|
||
```bash
|
||
make dev # 启动开发环境
|
||
make stage # 启动预发布环境
|
||
make prod # 启动生产环境
|
||
```
|
||
|
||
### 构建命令
|
||
|
||
```bash
|
||
make build # 构建 Linux 版本
|
||
make build-all # 构建所有平台版本
|
||
make clean # 清理构建文件
|
||
```
|
||
|
||
### 测试命令
|
||
|
||
```bash
|
||
make test # 运行测试
|
||
make test-coverage # 运行测试并生成覆盖率报告
|
||
make benchmark # 运行基准测试
|
||
```
|
||
|
||
### 代码质量
|
||
|
||
```bash
|
||
make fmt # 格式化代码
|
||
make vet # 静态检查
|
||
make lint # 代码规范检查
|
||
make check # 执行所有检查
|
||
```
|
||
|
||
### 文档生成
|
||
|
||
```bash
|
||
make docs # 生成 API 文档
|
||
make docs-serve # 启动文档服务器
|
||
```
|
||
|
||
### Docker 操作
|
||
|
||
```bash
|
||
make docker-build # 构建 Docker 镜像
|
||
make docker-compose-dev # 生成开发环境 Docker Compose 文件
|
||
make docker-up-dev # 启动开发环境容器
|
||
make docker-up-stage # 启动预发布环境容器
|
||
make docker-up-prod # 启动生产环境容器
|
||
make docker-down # 停止所有容器
|
||
make docker-down-dev # 停止开发环境容器
|
||
make docker-down-stage # 停止预发布环境容器
|
||
make docker-down-prod # 停止生产环境容器
|
||
make docker-logs # 查看开发环境容器日志
|
||
make docker-logs-stage # 查看预发布环境容器日志
|
||
make docker-logs-prod # 查看生产环境容器日志
|
||
make docker-ps # 查看所有容器状态
|
||
```
|
||
|
||
## 🔧 配置说明
|
||
|
||
### 环境配置
|
||
|
||
项目支持三种环境配置:
|
||
|
||
- `dev` - 开发环境
|
||
- `stage` - 预发布环境
|
||
- `prod` - 生产环境
|
||
|
||
配置文件位于 `config/` 目录下,可通过环境变量 `APP_ENV` 或命令行参数 `-env` 指定。
|
||
|
||
### 主要配置项
|
||
|
||
```yaml
|
||
server:
|
||
port: 1234 # 服务端口
|
||
mode: debug # 运行模式 (debug/release)
|
||
|
||
database:
|
||
host: localhost # 数据库地址
|
||
port: 3306 # 数据库端口
|
||
username: root # 数据库用户名
|
||
password: sasasasa # 数据库密码
|
||
dbname: yinli # 数据库名称
|
||
|
||
redis:
|
||
host: localhost # Redis 地址
|
||
port: 6379 # Redis 端口
|
||
password: "" # Redis 密码
|
||
db: 0 # Redis 数据库
|
||
|
||
jwt:
|
||
secret: your-secret-key # JWT 密钥
|
||
expireHours: 24 # 令牌过期时间(小时)
|
||
|
||
rateLimit:
|
||
enabled: true # 是否启用频率限制
|
||
requests: 100 # 每个时间窗口的请求数
|
||
window: 60 # 时间窗口(秒)
|
||
```
|
||
|
||
## 📡 API 接口
|
||
|
||
### 认证接口
|
||
|
||
| 方法 | 路径 | 描述 | 认证 |
|
||
|------|------|------|------|
|
||
| POST | `/api/auth/register` | 用户注册 | ❌ |
|
||
| POST | `/api/auth/login` | 用户登录 | ❌ |
|
||
|
||
### 用户接口
|
||
|
||
| 方法 | 路径 | 描述 | 认证 |
|
||
|------|------|------|------|
|
||
| GET | `/api/user/profile` | 获取用户资料 | ✅ |
|
||
| PUT | `/api/user/profile` | 更新用户资料 | ✅ |
|
||
| PUT | `/api/user/password` | 修改密码 | ✅ |
|
||
|
||
### 管理员接口
|
||
|
||
| 方法 | 路径 | 描述 | 认证 |
|
||
|------|------|------|------|
|
||
| GET | `/api/admin/users` | 获取用户列表 | ✅ (管理员) |
|
||
| DELETE | `/api/admin/users/{id}` | 删除用户 | ✅ (管理员) |
|
||
| PUT | `/api/admin/users/{id}/status` | 更新用户状态 | ✅ (管理员) |
|
||
|
||
### 系统接口
|
||
|
||
| 方法 | 路径 | 描述 | 认证 |
|
||
|------|------|------|------|
|
||
| GET | `/health` | 健康检查 | ❌ |
|
||
| GET | `/swagger/*` | API 文档 | ❌ |
|
||
|
||
## 🧪 接口测试
|
||
|
||
### 使用 curl 测试
|
||
|
||
1. **用户注册**
|
||
```bash
|
||
curl -X POST http://localhost:1234/api/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"name": "testuser",
|
||
"password": "password123"
|
||
}'
|
||
```
|
||
|
||
2. **用户登录**
|
||
```bash
|
||
curl -X POST http://localhost:1234/api/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"name": "testuser",
|
||
"password": "password123"
|
||
}'
|
||
```
|
||
|
||
3. **获取用户资料**
|
||
```bash
|
||
curl -X GET http://localhost:1234/api/user/profile \
|
||
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||
```
|
||
|
||
### 使用 Postman
|
||
|
||
1. 导入 Postman 集合文件(如果有)
|
||
2. 设置环境变量 `base_url` 为 `http://localhost:1234`
|
||
3. 在认证接口获取 JWT token
|
||
4. 在需要认证的接口中添加 `Authorization: Bearer {token}` 头
|
||
|
||
## 🔍 开发调试
|
||
|
||
### 日志查看
|
||
|
||
```bash
|
||
# 查看应用日志
|
||
tail -f logs/app.log
|
||
|
||
# 查看 Docker 容器日志
|
||
make docker-logs
|
||
```
|
||
|
||
### 数据库调试
|
||
|
||
```bash
|
||
# 连接数据库
|
||
mysql -h localhost -u root -p yinli
|
||
|
||
# 查看用户表
|
||
SELECT * FROM user;
|
||
```
|
||
|
||
### Redis 调试
|
||
|
||
```bash
|
||
# 连接 Redis
|
||
redis-cli
|
||
|
||
# 查看所有键
|
||
KEYS *
|
||
|
||
# 查看频率限制
|
||
KEYS rate_limit:*
|
||
```
|
||
|
||
### 性能监控
|
||
|
||
```bash
|
||
# 查看应用性能
|
||
go tool pprof http://localhost:1234/debug/pprof/profile
|
||
|
||
# 内存使用情况
|
||
go tool pprof http://localhost:1234/debug/pprof/heap
|
||
```
|
||
|
||
### 端口进程管理
|
||
|
||
在 Ubuntu 环境中,如果端口被占用,可以使用以下命令查找并终止进程:
|
||
|
||
```bash
|
||
# 方法1: 使用 netstat 查找端口对应的进程
|
||
netstat -tuln | grep :1234
|
||
|
||
# 方法2: 使用 lsof 查找端口对应的进程(需要安装: sudo apt install lsof)
|
||
lsof -i :1234
|
||
|
||
# 方法3: 使用 ss 查找端口对应的进程
|
||
ss -tulnp | grep :1234
|
||
|
||
# 获取进程 ID (PID) 后,使用以下命令终止进程
|
||
kill <PID>
|
||
|
||
# 如果进程无法正常终止,可以使用强制终止
|
||
kill -9 <PID>
|
||
|
||
# 或者使用一行命令直接终止占用端口的进程
|
||
kill $(lsof -t -i:1234)
|
||
|
||
# 如果 lsof 不可用,可以使用 fuser(需要安装: sudo apt install psmisc)
|
||
sudo fuser -k 1234/tcp
|
||
```
|
||
|
||
**示例:**
|
||
```bash
|
||
# 1. 查找端口 1234 对应的进程
|
||
$ netstat -tulnp | grep :1234
|
||
tcp6 0 0 :::1234 :::* LISTEN 449736/main
|
||
|
||
# 2. 或者使用 lsof 获取更详细信息
|
||
$ lsof -i :1234
|
||
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
||
main 449736 table 9u IPv6 903989 0t0 TCP *:1234 (LISTEN)
|
||
|
||
# 3. 终止进程(PID 为 449736)
|
||
$ kill 449736
|
||
|
||
# 4. 如果进程无法正常终止,使用强制终止
|
||
$ kill -9 449736
|
||
```
|
||
|
||
## 📊 测试报告
|
||
|
||
运行测试并生成报告:
|
||
|
||
```bash
|
||
make test-coverage
|
||
```
|
||
|
||
测试报告将生成在 `build/coverage.html`,可在浏览器中查看详细的覆盖率信息。
|
||
|
||
## 🚀 部署指南
|
||
|
||
### 生产环境部署
|
||
|
||
1. **构建生产版本**
|
||
```bash
|
||
make build
|
||
```
|
||
|
||
2. **配置生产环境**
|
||
```bash
|
||
# 修改 config/prod.yaml
|
||
# 设置正确的数据库和 Redis 连接信息
|
||
# 更改 JWT 密钥
|
||
```
|
||
|
||
3. **使用 Docker 部署**
|
||
```bash
|
||
# 设置环境变量
|
||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||
export REDIS_PASSWORD=your_redis_password
|
||
|
||
# 启动生产环境
|
||
make docker-up-prod
|
||
|
||
# 查看日志
|
||
make docker-logs-prod
|
||
```
|
||
|
||
### 环境变量
|
||
|
||
生产环境建议使用环境变量覆盖敏感配置:
|
||
|
||
```bash
|
||
export YINLI_DATABASE_PASSWORD=your_db_password
|
||
export YINLI_JWT_SECRET=your_jwt_secret
|
||
export YINLI_REDIS_PASSWORD=your_redis_password
|
||
```
|
||
|
||
## 📚 主要依赖库
|
||
|
||
### 核心依赖
|
||
|
||
- [Gin Web Framework](https://github.com/gin-gonic/gin) - HTTP Web 框架
|
||
- [GORM](https://github.com/go-gorm/gorm) - ORM 库
|
||
- [Viper](https://github.com/spf13/viper) - 配置管理
|
||
- [JWT-Go](https://github.com/golang-jwt/jwt) - JWT 实现
|
||
- [Go-Redis](https://github.com/go-redis/redis) - Redis 客户端
|
||
|
||
### 中间件
|
||
|
||
- [Gin-CORS](https://github.com/gin-contrib/cors) - CORS 中间件
|
||
- [Gin-Swagger](https://github.com/swaggo/gin-swagger) - Swagger 文档
|
||
|
||
### 测试工具
|
||
|
||
- [Testify](https://github.com/stretchr/testify) - 测试断言库
|
||
- [HTTP Test](https://golang.org/pkg/net/http/httptest/) - HTTP 测试工具
|
||
|
||
### 开发工具
|
||
|
||
- [Air](https://github.com/cosmtrek/air) - 热重载工具
|
||
- [GolangCI-Lint](https://github.com/golangci/golangci-lint) - 代码检查工具
|
||
|
||
## 🤝 贡献指南
|
||
|
||
1. Fork 项目
|
||
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
|
||
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
|
||
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
||
5. 开启 Pull Request
|
||
|
||
## 📄 许可证
|
||
|
||
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。
|
||
|
||
## 🆘 常见问题
|
||
|
||
### Q: 如何修改数据库连接?
|
||
A: 修改 `config/{env}.yaml` 文件中的 `database` 配置项。
|
||
|
||
### Q: 如何添加新的 API 接口?
|
||
A: 1. 在 `src/handler` 中添加处理函数
|
||
2. 在 `src/handler/router.go` 中注册路由
|
||
3. 添加相应的测试用例
|
||
|
||
### Q: 如何自定义中间件?
|
||
A: 在 `src/middleware` 目录下创建新的中间件文件,参考现有中间件的实现。
|
||
|
||
### Q: 如何部署到生产环境?
|
||
A:
|
||
1. 设置环境变量:
|
||
```bash
|
||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||
export REDIS_PASSWORD=your_redis_password
|
||
```
|
||
2. 修改 `config/prod.yaml` 中的敏感配置(JWT密钥等)
|
||
3. 启动生产环境:
|
||
```bash
|
||
make docker-up-prod
|
||
```
|
||
4. 查看日志:
|
||
```bash
|
||
make docker-logs-prod
|
||
```
|
||
|
||
### Q: Docker Compose 支持哪些环境?
|
||
A: 项目支持三种环境的 Docker Compose 部署:
|
||
- **dev**: 开发环境,端口映射 MySQL:3306, Redis:6379
|
||
- **stage**: 预发布环境,端口映射 MySQL:3307, Redis:6380
|
||
- **prod**: 生产环境,端口映射 MySQL:3308, Redis:6381,包含健康检查和自动重启
|
||
|
||
### Q: Docker 镜像拉取失败怎么办?
|
||
A: 如果在中国大陆遇到镜像拉取超时或失败,可以:
|
||
1. **配置 Docker 镜像加速器**(推荐):
|
||
```bash
|
||
sudo mkdir -p /etc/docker
|
||
sudo tee /etc/docker/daemon.json <<-'EOF'
|
||
{
|
||
"registry-mirrors": [
|
||
"https://docker.m.daocloud.io",
|
||
"https://dockerproxy.com",
|
||
"https://docker.nju.edu.cn"
|
||
]
|
||
}
|
||
EOF
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl restart docker
|
||
```
|
||
|
||
**重要:配置后必须重启 Docker 服务才能生效!**
|
||
|
||
验证配置:
|
||
```bash
|
||
docker info | grep -A 10 "Registry Mirrors"
|
||
```
|
||
如果看到镜像源列表,说明配置成功。
|
||
|
||
2. **Rootless Docker 配置**:
|
||
- 如果使用 rootless Docker(`docker version` 显示 `Context: rootless`),配置文件位置为 `~/.config/docker/daemon.json`
|
||
- 配置后重启:`systemctl --user restart docker`
|
||
- 验证:`docker info | grep -A 10 "Registry Mirrors"`
|
||
|
||
3. **使用官方镜像名称**:项目使用官方镜像名称(如 `mysql:8.0`、`redis:7-alpine`),通过配置的 Docker 镜像加速器自动加速拉取
|
||
|
||
4. **Go 模块下载失败**:
|
||
- Dockerfile 中已配置使用国内 Go 代理(`GOPROXY=https://goproxy.cn,direct`)
|
||
- 如果仍然失败,可以在 Dockerfile 中修改 GOPROXY 环境变量:
|
||
```dockerfile
|
||
ENV GOPROXY=https://goproxy.cn,https://goproxy.io,direct
|
||
```
|
||
- 常用 Go 代理:`https://goproxy.cn`、`https://goproxy.io`、`https://mirrors.aliyun.com/goproxy/`
|
||
|
||
5. **检查网络连接**:确保能够访问镜像仓库
|
||
- 测试镜像源:`curl -I https://docker.m.daocloud.io/v2/`
|
||
- 如果镜像加速器配置已生效但仍失败,可能是网络问题,可以稍后重试
|
||
|
||
6. **如果镜像加速器仍未生效**:
|
||
- 检查配置文件格式是否正确(JSON 格式)
|
||
- 标准 Docker:检查 `/etc/docker/daemon.json`
|
||
- Rootless Docker:检查 `~/.config/docker/daemon.json`
|
||
- 确认已重启 Docker 服务
|
||
- 检查 Docker 服务状态:`sudo systemctl status docker` 或 `systemctl --user status docker`
|
||
|
||
### Q: Docker 权限错误(permission denied)怎么办?
|
||
A: 如果遇到 `Error response from daemon: cannot stop container: permission denied` 错误,可能的原因和解决方法:
|
||
|
||
1. **Docker 上下文不匹配**(常见原因):
|
||
如果系统同时安装了标准 Docker 和 rootless Docker,容器可能由不同的上下文创建。
|
||
|
||
```bash
|
||
# 查看当前 Docker 上下文
|
||
docker context show
|
||
|
||
# 查看所有可用的上下文
|
||
docker context ls
|
||
|
||
# 如果容器是由标准 Docker 创建的,切换到 default 上下文
|
||
docker context use default
|
||
|
||
# 然后尝试停止容器
|
||
docker stop docker-mysql-1
|
||
|
||
# 如果需要切换回 rootless
|
||
docker context use rootless
|
||
```
|
||
|
||
**提示**:如果容器是通过 `sudo docker compose` 创建的,通常需要使用 `default` 上下文;如果通过普通用户创建的,可能使用 `rootless` 上下文。
|
||
|
||
2. **临时解决方案(使用 sudo)**:
|
||
```bash
|
||
# 停止并删除容器
|
||
sudo docker stop docker-mysql-1
|
||
sudo docker rm docker-mysql-1
|
||
|
||
# 或使用 docker compose
|
||
sudo docker compose -f docker/docker-compose.stage.yml down
|
||
```
|
||
|
||
3. **永久解决方案(推荐)**:将用户添加到 `docker` 组
|
||
```bash
|
||
# 将当前用户添加到 docker 组
|
||
sudo usermod -aG docker $USER
|
||
|
||
# 重新登录或执行以下命令使组权限生效
|
||
newgrp docker
|
||
|
||
# 验证是否成功
|
||
groups | grep docker
|
||
```
|
||
|
||
**注意**:添加到 docker 组后,需要:
|
||
- 重新登录系统,或
|
||
- 执行 `newgrp docker` 命令,或
|
||
- 重新打开终端
|
||
|
||
之后就可以不使用 `sudo` 直接操作 Docker 了。
|
||
|
||
4. **检查 Docker socket 权限**:
|
||
```bash
|
||
ls -la /var/run/docker.sock
|
||
```
|
||
应该显示类似:`srw-rw---- 1 root docker`,表示 `docker` 组有读写权限。
|
||
|
||
5. **如果使用 rootless Docker**:
|
||
- Rootless Docker 不需要 sudo,但需要确保 Docker 服务正在运行
|
||
- 检查服务状态:`systemctl --user status docker`
|
||
- 启动服务:`systemctl --user start docker`
|
||
- 注意:rootless Docker 和标准 Docker 创建的容器是隔离的,不能互相管理
|
||
- **如果遇到权限错误,可以尝试**:
|
||
```bash
|
||
# 方法1:重启 rootless Docker 服务(推荐)
|
||
systemctl --user restart docker
|
||
# 等待几秒后,再尝试停止容器
|
||
docker stop docker-mysql-1
|
||
|
||
# 方法2:使用 docker kill 强制停止
|
||
docker kill docker-mysql-1
|
||
docker rm docker-mysql-1
|
||
|
||
# 方法3:检查并修复 rootless Docker socket 权限
|
||
ls -la /run/user/$(id -u)/docker.sock
|
||
# 应该显示类似:srw-rw---T 1 table ...
|
||
```
|