fix: 修复 MySQL 容器在 rootless Docker 环境下无法正常停止的问题
主要改动: - 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 服务
This commit is contained in:
parent
d343ceca39
commit
7e5572344b
12
Dockerfile
12
Dockerfile
@ -1,5 +1,10 @@
|
||||
# 多阶段构建
|
||||
FROM golang:1.21-alpine AS builder
|
||||
# 使用阿里云镜像加速(如需使用官方镜像,请配置 Docker 镜像加速器)
|
||||
FROM golang:1.24-alpine AS builder
|
||||
|
||||
# 设置 Go 代理(中国大陆用户)
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV GOSUMDB=sum.golang.google.cn
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
@ -20,6 +25,7 @@ COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main src/main.go
|
||||
|
||||
# 最终镜像
|
||||
# 使用阿里云镜像加速(如需使用官方镜像,请配置 Docker 镜像加速器)
|
||||
FROM alpine:latest
|
||||
|
||||
# 安装必要的包
|
||||
@ -47,11 +53,11 @@ RUN chown -R appuser:appgroup /app
|
||||
USER appuser
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8080
|
||||
EXPOSE 1234
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:1234/health || exit 1
|
||||
|
||||
# 启动应用
|
||||
CMD ["./main"]
|
||||
|
||||
106
Makefile
106
Makefile
@ -14,7 +14,7 @@ GOVET := go vet
|
||||
|
||||
# Docker 相关变量
|
||||
DOCKER := docker
|
||||
DOCKER_COMPOSE := docker-compose
|
||||
DOCKER_COMPOSE := $(DOCKER) compose
|
||||
|
||||
# 默认目标
|
||||
.PHONY: help
|
||||
@ -133,15 +133,13 @@ docker-build: ## 构建Docker镜像
|
||||
docker-compose-dev: ## 生成开发环境Docker Compose文件
|
||||
@echo "生成开发环境Docker Compose文件..."
|
||||
@mkdir -p $(DOCKER_DIR)
|
||||
@echo "version: '3.8'" > $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo "services:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo "services:" > $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " yinli-api:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " build:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " context: .." >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " dockerfile: Dockerfile" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " ports:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " - \"8080:8080\"" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " - \"1234:1234\"" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " environment:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " - APP_ENV=dev" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@echo " depends_on:" >> $(DOCKER_DIR)/docker-compose.dev.yml
|
||||
@ -188,15 +186,103 @@ docker-up-dev: docker-compose-dev ## 启动开发环境Docker容器
|
||||
@echo "启动开发环境Docker容器..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.dev.yml up -d
|
||||
|
||||
.PHONY: docker-up-stage
|
||||
docker-up-stage: ## 启动预发布环境Docker容器
|
||||
@echo "启动预发布环境Docker容器..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.stage.yml up -d
|
||||
|
||||
.PHONY: docker-up-prod
|
||||
docker-up-prod: ## 启动生产环境Docker容器
|
||||
@echo "启动生产环境Docker容器..."
|
||||
@echo "警告: 请确保已设置 MYSQL_ROOT_PASSWORD 和 REDIS_PASSWORD 环境变量"
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.prod.yml up -d
|
||||
|
||||
.PHONY: docker-down
|
||||
docker-down: ## 停止并移除Docker容器
|
||||
docker-down: ## 停止并移除所有Docker容器
|
||||
@echo "停止并移除Docker容器..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) down
|
||||
@cd $(DOCKER_DIR) && \
|
||||
OUTPUT=$$($(DOCKER_COMPOSE) -f docker-compose.dev.yml -f docker-compose.stage.yml -f docker-compose.prod.yml down --remove-orphans 2>&1); \
|
||||
echo "$$OUTPUT"; \
|
||||
if echo "$$OUTPUT" | grep -q "permission denied"; then \
|
||||
echo ""; \
|
||||
echo "⚠️ 检测到权限错误,自动重启 rootless Docker 服务并重试..."; \
|
||||
systemctl --user restart docker >/dev/null 2>&1 || true; \
|
||||
sleep 3; \
|
||||
echo "重试停止容器..."; \
|
||||
$(DOCKER_COMPOSE) -f docker-compose.dev.yml -f docker-compose.stage.yml -f docker-compose.prod.yml down --remove-orphans 2>&1 || { \
|
||||
echo ""; \
|
||||
echo "❌ 仍然失败,请手动执行: systemctl --user restart docker && make docker-down"; \
|
||||
exit 0; \
|
||||
}; \
|
||||
fi
|
||||
|
||||
.PHONY: docker-down-dev
|
||||
docker-down-dev: ## 停止并移除开发环境Docker容器
|
||||
@echo "停止并移除开发环境Docker容器..."
|
||||
@cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.dev.yml down --remove-orphans 2>&1 || { \
|
||||
echo ""; \
|
||||
echo "⚠️ 如果遇到权限错误(permission denied),容器可能由 root 用户创建。"; \
|
||||
echo " 请手动执行: sudo docker compose -f docker/docker-compose.dev.yml down"; \
|
||||
exit 0; \
|
||||
}
|
||||
|
||||
.PHONY: docker-down-stage
|
||||
docker-down-stage: ## 停止并移除预发布环境Docker容器
|
||||
@echo "停止并移除预发布环境Docker容器..."
|
||||
@cd $(DOCKER_DIR) && \
|
||||
OUTPUT=$$($(DOCKER_COMPOSE) -f docker-compose.stage.yml down --remove-orphans 2>&1); \
|
||||
echo "$$OUTPUT"; \
|
||||
if echo "$$OUTPUT" | grep -q "permission denied"; then \
|
||||
echo ""; \
|
||||
echo "⚠️ 检测到权限错误,自动重启 rootless Docker 服务并重试..."; \
|
||||
systemctl --user restart docker >/dev/null 2>&1 || true; \
|
||||
sleep 3; \
|
||||
echo "重试停止容器..."; \
|
||||
$(DOCKER_COMPOSE) -f docker-compose.stage.yml down --remove-orphans 2>&1 || { \
|
||||
echo ""; \
|
||||
echo "❌ 仍然失败,请手动执行: systemctl --user restart docker && make docker-down-stage"; \
|
||||
exit 0; \
|
||||
}; \
|
||||
fi
|
||||
|
||||
.PHONY: docker-down-prod
|
||||
docker-down-prod: ## 停止并移除生产环境Docker容器
|
||||
@echo "停止并移除生产环境Docker容器..."
|
||||
@cd $(DOCKER_DIR) && \
|
||||
if ! $(DOCKER_COMPOSE) -f docker-compose.prod.yml down --remove-orphans 2>&1 | tee /dev/stderr | grep -q "permission denied"; then \
|
||||
:; \
|
||||
else \
|
||||
echo ""; \
|
||||
echo "⚠️ 检测到权限错误,自动重启 rootless Docker 服务并重试..."; \
|
||||
systemctl --user restart docker >/dev/null 2>&1 || true; \
|
||||
sleep 3; \
|
||||
echo "重试停止容器..."; \
|
||||
$(DOCKER_COMPOSE) -f docker-compose.prod.yml down --remove-orphans 2>&1 || { \
|
||||
echo ""; \
|
||||
echo "❌ 仍然失败,请手动执行: systemctl --user restart docker && make docker-down-prod"; \
|
||||
exit 0; \
|
||||
}; \
|
||||
fi
|
||||
|
||||
.PHONY: docker-logs
|
||||
docker-logs: ## 查看Docker容器日志
|
||||
@echo "查看Docker容器日志..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) logs -f
|
||||
docker-logs: ## 查看开发环境Docker容器日志
|
||||
@echo "查看开发环境Docker容器日志..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.dev.yml logs -f
|
||||
|
||||
.PHONY: docker-logs-stage
|
||||
docker-logs-stage: ## 查看预发布环境Docker容器日志
|
||||
@echo "查看预发布环境Docker容器日志..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.stage.yml logs -f
|
||||
|
||||
.PHONY: docker-logs-prod
|
||||
docker-logs-prod: ## 查看生产环境Docker容器日志
|
||||
@echo "查看生产环境Docker容器日志..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.prod.yml logs -f
|
||||
|
||||
.PHONY: docker-ps
|
||||
docker-ps: ## 查看所有Docker容器状态
|
||||
@echo "查看所有Docker容器状态..."
|
||||
cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.dev.yml -f docker-compose.stage.yml -f docker-compose.prod.yml ps
|
||||
|
||||
# 清理
|
||||
.PHONY: clean
|
||||
|
||||
@ -81,12 +81,48 @@ make dev
|
||||
```
|
||||
|
||||
### 2. Docker 启动
|
||||
|
||||
#### 开发环境
|
||||
```bash
|
||||
# 生成 Docker Compose 文件
|
||||
# 生成 Docker Compose 文件(可选,文件已存在)
|
||||
make docker-compose-dev
|
||||
|
||||
# 启动 Docker 容器
|
||||
# 启动开发环境容器
|
||||
make docker-up-dev
|
||||
|
||||
# 查看日志
|
||||
make docker-logs
|
||||
|
||||
# 停止服务
|
||||
make docker-down-dev
|
||||
```
|
||||
|
||||
#### 预发布环境
|
||||
```bash
|
||||
# 启动预发布环境容器
|
||||
make docker-up-stage
|
||||
|
||||
# 查看日志
|
||||
make docker-logs-stage
|
||||
|
||||
# 停止服务
|
||||
make docker-down-stage
|
||||
```
|
||||
|
||||
#### 生产环境
|
||||
```bash
|
||||
# 设置环境变量(重要!)
|
||||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||||
export REDIS_PASSWORD=your_redis_password
|
||||
|
||||
# 启动生产环境容器
|
||||
make docker-up-prod
|
||||
|
||||
# 查看日志
|
||||
make docker-logs-prod
|
||||
|
||||
# 停止服务
|
||||
make docker-down-prod
|
||||
```
|
||||
|
||||
### 3. 运行测试
|
||||
@ -204,9 +240,15 @@ make dev
|
||||
|
||||
### 生产环境
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||||
export REDIS_PASSWORD=your_redis_password
|
||||
|
||||
# 使用 Docker 部署
|
||||
make docker-compose-prod
|
||||
make docker-up-prod
|
||||
|
||||
# 查看日志
|
||||
make docker-logs-prod
|
||||
```
|
||||
|
||||
## 📝 下一步建议
|
||||
|
||||
335
README.md
335
README.md
@ -94,16 +94,164 @@ make dev
|
||||
|
||||
### Docker 部署
|
||||
|
||||
1. **生成 Docker Compose 文件**
|
||||
项目支持三种环境的 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. **启动服务**
|
||||
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密钥、数据库密码等)
|
||||
|
||||
## 📋 可用命令
|
||||
|
||||
### 开发命令
|
||||
@ -149,12 +297,19 @@ make docs-serve # 启动文档服务器
|
||||
### Docker 操作
|
||||
|
||||
```bash
|
||||
make docker-build # 构建 Docker 镜像
|
||||
make docker-up-dev # 启动开发环境容器
|
||||
make docker-up-stage # 启动预发布环境容器
|
||||
make docker-up-prod # 启动生产环境容器
|
||||
make docker-down # 停止容器
|
||||
make docker-logs # 查看容器日志
|
||||
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 # 查看所有容器状态
|
||||
```
|
||||
|
||||
## 🔧 配置说明
|
||||
@ -386,8 +541,15 @@ make build
|
||||
|
||||
3. **使用 Docker 部署**
|
||||
```bash
|
||||
make docker-compose-prod
|
||||
# 设置环境变量
|
||||
export MYSQL_ROOT_PASSWORD=your_secure_password
|
||||
export REDIS_PASSWORD=your_redis_password
|
||||
|
||||
# 启动生产环境
|
||||
make docker-up-prod
|
||||
|
||||
# 查看日志
|
||||
make docker-logs-prod
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
@ -451,4 +613,157 @@ A: 1. 在 `src/handler` 中添加处理函数
|
||||
A: 在 `src/middleware` 目录下创建新的中间件文件,参考现有中间件的实现。
|
||||
|
||||
### Q: 如何部署到生产环境?
|
||||
A: 使用 `make docker-compose-prod` 生成生产环境配置,然后使用 `make docker-up-prod` 部署。
|
||||
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 ...
|
||||
```
|
||||
|
||||
@ -3,7 +3,7 @@ server:
|
||||
mode: release
|
||||
|
||||
database:
|
||||
host: localhost
|
||||
host: mysql # Docker环境使用服务名,本地环境使用localhost
|
||||
port: 3306
|
||||
username: root
|
||||
password: sasasasa
|
||||
@ -15,7 +15,7 @@ database:
|
||||
maxOpenConns: 500
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
host: redis # Docker环境使用服务名,本地环境使用localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 2
|
||||
|
||||
@ -3,7 +3,7 @@ server:
|
||||
mode: release
|
||||
|
||||
database:
|
||||
host: localhost
|
||||
host: mysql # Docker环境使用服务名,本地环境使用localhost
|
||||
port: 3306
|
||||
username: root
|
||||
password: sasasasa
|
||||
@ -15,7 +15,7 @@ database:
|
||||
maxOpenConns: 200
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
host: redis # Docker环境使用服务名,本地环境使用localhost
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 1
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
yinli-api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "1234:1234"
|
||||
environment:
|
||||
- APP_ENV=dev
|
||||
depends_on:
|
||||
@ -29,6 +27,9 @@ services:
|
||||
- ../sql:/docker-entrypoint-initdb.d:ro
|
||||
networks:
|
||||
- yinli-network
|
||||
stop_grace_period: 60s
|
||||
stop_signal: SIGTERM
|
||||
init: true
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
|
||||
71
docker/docker-compose.prod.yml
Normal file
71
docker/docker-compose.prod.yml
Normal file
@ -0,0 +1,71 @@
|
||||
services:
|
||||
yinli-api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "1234:1234"
|
||||
environment:
|
||||
- APP_ENV=prod
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
volumes:
|
||||
- ../config:/app/config:ro
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:1234/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: yinli
|
||||
ports:
|
||||
- "3308:3306"
|
||||
volumes:
|
||||
- mysql_prod_data:/var/lib/mysql
|
||||
- ../sql:/docker-entrypoint-initdb.d:ro
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: always
|
||||
stop_grace_period: 60s
|
||||
stop_signal: SIGTERM
|
||||
init: true
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6381:6379"
|
||||
volumes:
|
||||
- redis_prod_data:/data
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: always
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-}
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
mysql_prod_data:
|
||||
redis_prod_data:
|
||||
|
||||
networks:
|
||||
yinli-network:
|
||||
driver: bridge
|
||||
|
||||
55
docker/docker-compose.stage.yml
Normal file
55
docker/docker-compose.stage.yml
Normal file
@ -0,0 +1,55 @@
|
||||
services:
|
||||
yinli-api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "1234:1234"
|
||||
environment:
|
||||
- APP_ENV=stage
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
volumes:
|
||||
- ../config:/app/config:ro
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: unless-stopped
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-sasasasa}
|
||||
MYSQL_DATABASE: yinli
|
||||
ports:
|
||||
- "3307:3306"
|
||||
volumes:
|
||||
- mysql_stage_data:/var/lib/mysql
|
||||
- ../sql:/docker-entrypoint-initdb.d:ro
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 60s
|
||||
stop_signal: SIGTERM
|
||||
init: true
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6380:6379"
|
||||
volumes:
|
||||
- redis_stage_data:/data
|
||||
networks:
|
||||
- yinli-network
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
volumes:
|
||||
mysql_stage_data:
|
||||
redis_stage_data:
|
||||
|
||||
networks:
|
||||
yinli-network:
|
||||
driver: bridge
|
||||
|
||||
Loading…
Reference in New Issue
Block a user