# 资产管理系统后端骨架 - 技术需求 V1(Docker 全环境版) > 执行目标:基于纯 Docker 环境构建可编译、可运行的最小化后端骨架,无宿主机依赖(无全局 Go/Protoc/Postgres/Redis 环境) > 技术栈锁定:golang:1.26.1-alpine3.23、postgres:18.3-alpine3.23、redis:8.6.2-alpine、Docker/Docker Compose ## 一、核心调整说明 1. **基础镜像版本统一**:所有 Go 构建/运行、数据库、缓存镜像均替换为指定版本 2. **纯 Docker 环境闭环**: - 宿主机无依赖(无需安装 Go/Protoc/Make 等) - 所有构建/编译/运行操作均通过 Docker 容器完成 - 新增 Protoc 构建容器(解决 proto 文件编译依赖) 3. **路径与权限优化**:适配 Alpine 3.23 镜像特性,调整文件权限和执行逻辑 ## 二、完整目录结构(./backend/ 根) ``` ./backend/ ├── gateway/ │ ├── cmd/ │ │ └── main.go │ ├── internal/ │ │ ├── config/ │ │ │ └── config.go │ │ ├── ws/ │ │ │ ├── hub.go │ │ │ ├── client.go │ │ │ └── message.go │ │ └── router/ │ │ └── router.go │ ├── go.mod │ └── Dockerfile ├── services/ │ └── user-svc/ │ ├── cmd/ │ │ └── main.go │ ├── internal/ │ │ ├── config/ │ │ │ └── config.go │ │ ├── domain/ │ │ │ └── user.go │ │ ├── repository/ │ │ │ └── repo.go │ │ ├── service/ │ │ │ └── service.go │ │ └── grpcserver/ │ │ └── server.go │ ├── proto/ │ │ └── user.proto │ ├── migrations/ │ │ └── 001_init.sql │ ├── go.mod │ └── Dockerfile ├── shared/ │ ├── proto/ │ │ ├── common/ │ │ │ └── common.proto │ │ └── generate.go │ └── pkg/ │ ├── logger/ │ │ └── logger.go │ ├── errors/ │ │ └── errors.go │ ├── database/ │ │ └── postgres.go │ └── cache/ │ └── redis.go ├── scripts/ │ ├── dev-start.sh # 纯 Docker 启动脚本 │ ├── gen-proto.sh # Docker 内编译 proto │ └── docker-proto-builder/ # Protoc 编译容器配置 │ └── Dockerfile ├── docker-compose.yml # 全服务编排(含 proto 编译、Go 构建) ├── docker-compose.dev.yml # 开发模式编排(挂载源码、热更新) ├── Makefile # 封装 Docker 命令(兼容无宿主机 Make 环境) └── README.md # 纯 Docker 环境使用说明 ``` ## 三、核心文件调整(适配指定技术栈 + 纯 Docker 环境) ### 3.1 基础镜像统一替换 所有 Dockerfile/Compose 文件中的基础镜像替换为指定版本: - Go 构建/运行:`golang:1.26.1-alpine3.23` - PostgreSQL:`postgres:18.3-alpine3.23` - Redis:`redis:8.6.2-alpine` - 基础运行镜像:`alpine:3.23` ### 3.2 ./backend/gateway/Dockerfile ```dockerfile # 构建阶段:使用指定 Go 版本 FROM golang:1.26.1-alpine3.23 AS builder WORKDIR /build # 安装依赖(Alpine 3.23 适配) RUN apk add --no-cache git ca-certificates tzdata ENV TZ=Asia/Shanghai # 复制共享代码和网关代码 COPY ../shared /shared COPY . /build # 替换模块路径并构建(关闭 CGO 适配 Alpine) RUN go mod download RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o gateway ./cmd # 运行阶段:轻量 Alpine FROM alpine:3.23 RUN apk add --no-cache ca-certificates tzdata ENV TZ=Asia/Shanghai WORKDIR /app # 复制构建产物 COPY --from=builder /build/gateway . COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # 权限优化(非 root 运行) RUN addgroup -S appgroup && adduser -S appuser -G appgroup RUN chown -R appuser:appgroup /app USER appuser EXPOSE 8080 # 优雅退出配置 STOPSIGNAL SIGTERM CMD ["./gateway"] ``` ### 3.3 ./backend/services/user-svc/Dockerfile ```dockerfile # 构建阶段 FROM golang:1.26.1-alpine3.23 AS builder WORKDIR /build RUN apk add --no-cache git ca-certificates tzdata ENV TZ=Asia/Shanghai # 复制共享代码和用户服务代码 COPY ../../shared /shared COPY . /build RUN go mod download RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o user-svc ./cmd # 运行阶段 FROM alpine:3.23 RUN apk add --no-cache ca-certificates tzdata ENV TZ=Asia/Shanghai WORKDIR /app COPY --from=builder /build/user-svc . COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # 非 root 运行 RUN addgroup -S appgroup && adduser -S appuser -G appgroup RUN chown -R appuser:appgroup /app USER appuser EXPOSE 50051 STOPSIGNAL SIGTERM CMD ["./user-svc"] ``` ### 3.4 ./backend/scripts/docker-proto-builder/Dockerfile ```dockerfile # Protoc 编译专用容器(解决宿主机无 Protoc 依赖) FROM golang:1.26.1-alpine3.23 # 安装 Protoc 及 Go 插件 RUN apk add --no-cache protobuf git RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.0 RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.5.1 # 配置环境变量 ENV PATH="$PATH:/go/bin" ENV GOPATH="/go" WORKDIR /proto CMD ["protoc", "--version"] ``` ### 3.5 ./backend/scripts/gen-proto.sh ```bash #!/bin/sh # 纯 Docker 环境编译 Proto 文件(无宿主机 Protoc 依赖) set -e # 进入项目根目录 SCRIPT_DIR=$(cd $(dirname $0)/.. && pwd) cd $SCRIPT_DIR # 构建 Protoc 编译容器并执行编译 docker build -t proto-builder:latest ./scripts/docker-proto-builder/ # 运行编译容器(挂载 proto 目录) docker run --rm \ -v $SCRIPT_DIR/shared/proto:/proto \ -w /proto \ proto-builder:latest \ sh -c "for f in */*.proto; do \ protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ \$f; \ done" echo "✅ Proto 文件编译完成(Docker 环境)" ``` ### 3.6 ./backend/docker-compose.yml ```yaml version: '3.8' services: # Proto 编译服务(一次性执行) proto-builder: build: ./scripts/docker-proto-builder/ volumes: - ./shared/proto:/proto command: sh -c "/proto/../scripts/gen-proto.sh" profiles: ["proto"] # 网关服务 gateway: build: ./gateway ports: - "8080:8080" environment: - WS_ADDR=:8080 - REDIS_ADDR=redis:6379 depends_on: - redis restart: unless-stopped security_opt: - no-new-privileges:true networks: - backend-network # 用户服务 user-svc: build: ./services/user-svc ports: - "50051:50051" environment: - DB_HOST=user-db - DB_PORT=5432 - DB_USER=postgres - DB_PASSWORD=postgres - DB_NAME=user_db - GRPC_ADDR=:50051 depends_on: - user-db restart: unless-stopped security_opt: - no-new-privileges:true networks: - backend-network # PostgreSQL 数据库(指定版本) user-db: image: postgres:18.3-alpine3.23 ports: - "5432:5432" environment: - POSTGRES_DB=user_db - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_INITDB_ARGS=--encoding=UTF8 --lc-collate=C --lc-ctype=C volumes: - user_data:/var/lib/postgresql/data - ./services/user-svc/migrations:/docker-entrypoint-initdb.d restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d user_db"] interval: 5s timeout: 3s retries: 5 networks: - backend-network # Redis 缓存(指定版本) redis: image: redis:8.6.2-alpine ports: - "6379:6379" command: redis-server --appendonly yes --requirepass "" volumes: - redis_data:/data restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 networks: - backend-network volumes: user_data: redis_data: networks: backend-network: driver: bridge ``` ### 3.7 ./backend/docker-compose.dev.yml(开发模式,挂载源码) ```yaml version: '3.8' services: gateway: build: ./gateway ports: - "8080:8080" environment: - WS_ADDR=:8080 - REDIS_ADDR=redis:6379 depends_on: - redis volumes: - ./gateway:/build - ./shared:/shared command: sh -c "go run cmd/main.go" restart: on-failure networks: - backend-network user-svc: build: ./services/user-svc ports: - "50051:50051" environment: - DB_HOST=user-db - DB_PORT=5432 - DB_USER=postgres - DB_PASSWORD=postgres - DB_NAME=user_db - GRPC_ADDR=:50051 depends_on: - user-db volumes: - ./services/user-svc:/build - ./shared:/shared command: sh -c "go run cmd/main.go" restart: on-failure networks: - backend-network # 复用主 Compose 的数据库/缓存服务 user-db: extends: file: docker-compose.yml service: user-db redis: extends: file: docker-compose.yml service: redis volumes: user_data: redis_data: networks: backend-network: driver: bridge ``` ### 3.8 ./backend/scripts/dev-start.sh ```bash #!/bin/sh set -e # 纯 Docker 环境启动脚本(无宿主机依赖) SCRIPT_DIR=$(cd $(dirname $0)/.. && pwd) cd $SCRIPT_DIR echo "======================================" echo " Asset Helper Backend (Docker 环境) " echo "======================================" # 停止旧容器 echo "🔄 停止旧容器..." docker-compose -f docker-compose.yml down -v 2>/dev/null || true # 编译 Proto 文件(Docker 内执行) echo "📝 编译 Proto 文件..." ./scripts/gen-proto.sh # 启动开发环境 echo "🚀 启动开发容器..." docker-compose -f docker-compose.yml -f docker-compose.dev.yml up --build -d # 等待服务就绪 echo "⌛ 等待服务初始化..." sleep 10 # 检查服务状态 echo "✅ 服务状态检查:" docker-compose -f docker-compose.yml ps # 健康检查 echo "\n📊 健康检查:" docker run --rm --network backend_backend-network curlimages/curl:8.7.1 -s http://gateway:8080/health || echo "⚠️ Gateway 服务未就绪" # 输出访问信息 echo "\n📌 访问信息:" echo "Gateway WebSocket: ws://localhost:8080/ws" echo "Health Check: http://localhost:8080/health" echo "User gRPC: localhost:50051" echo "PostgreSQL: localhost:5432 (user: postgres, pass: postgres, db: user_db)" echo "Redis: localhost:6379" echo "\n💡 查看日志:docker-compose -f docker-compose.yml logs -f" echo "💡 停止服务:docker-compose -f docker-compose.yml down -v" ``` ### 3.9 ./backend/Makefile(兼容无宿主机 Make 环境) ```makefile .PHONY: dev build proto test down logs clean # 兼容无宿主机 Make 环境:通过 Docker 执行核心操作 dev: @echo "启动开发环境(纯 Docker)..." @./scripts/dev-start.sh build: @echo "构建生产镜像..." @docker-compose -f docker-compose.yml build proto: @echo "编译 Proto 文件(Docker 内)..." @./scripts/gen-proto.sh test: @echo "执行健康检查..." @docker run --rm --network backend_backend-network curlimages/curl:8.7.1 -s http://gateway:8080/health || echo "Gateway 服务未运行" down: @echo "停止并清理容器..." @docker-compose -f docker-compose.yml -f docker-compose.dev.yml down -v logs: @echo "实时查看日志..." @docker-compose -f docker-compose.yml -f docker-compose.dev.yml logs -f clean: down @echo "清理镜像和数据卷..." @docker system prune -f @docker volume rm backend_user_data backend_redis_data 2>/dev/null || true ``` ### 3.10 ./backend/README.md(纯 Docker 环境说明) ```markdown # Asset Helper Backend 资产管理系统后端服务(纯 Docker 环境版) ## 核心特性 - 📦 全 Docker 环境:无需宿主机安装 Go/Protoc/Postgres/Redis 等依赖 - 🔒 安全配置:非 root 用户运行容器、权限最小化 - 🚀 开发/生产双模式:开发模式挂载源码,生产模式构建镜像 - 🛡️ 健康检查:自动检测服务状态,快速定位问题 ## 环境要求 - Docker 20.10+ - Docker Compose 2.0+ - 无其他宿主机依赖(无需 Go/Protoc/Make/Postgres/Redis) ## 快速开始 ```bash # 进入后端目录 cd ./backend # 启动开发环境(自动编译 Proto + 启动所有服务) make dev # 检查服务状态 make test # 查看实时日志 make logs # 停止并清理环境 make down # 清理所有镜像/数据卷(彻底重置) make clean ``` ## 服务端口 | 服务 | 端口 | 说明 | |--------------|---------|-----------------------| | gateway | 8080 | WebSocket + HTTP 入口 | | user-svc | 50051 | gRPC 用户服务 | | user-db | 5432 | PostgreSQL 数据库 | | redis | 6379 | Redis 缓存 | ## 开发模式 vs 生产模式 ### 开发模式(默认) - 挂载本地源码到容器,支持实时修改 - 使用 `docker-compose.dev.yml` 扩展配置 - 自动重启 Go 服务(代码修改后需手动重启) ### 生产模式 ```bash # 构建生产镜像 make build # 启动生产环境(无源码挂载) docker-compose -f docker-compose.yml up -d ``` ## 关键操作 ### 编译 Proto 文件 ```bash make proto ``` ### 健康检查 ```bash make test # 或直接执行 curl http://localhost:8080/health ``` ### 测试 WebSocket ```bash # 安装 wscat(或使用 Docker 版) docker run --rm -it --network backend_backend-network jmalloc/websocket-client wss://gateway:8080/ws > {"id":"1","type":"test","service":"user","action":"health"} ``` ## 目录结构 ``` ./backend/ # 后端服务根目录 ├── gateway/ # 网关服务(WebSocket + HTTP) ├── services/ # 微服务目录(user-svc 示例) ├── shared/ # 共享代码/Proto/工具包 ├── scripts/ # 自动化脚本(Docker 环境适配) ├── docker-compose.yml # 生产环境编排 ├── docker-compose.dev.yml # 开发环境编排 └── Makefile # 快捷命令封装 ``` ## 技术栈版本 - Go: 1.26.1-alpine3.23 - PostgreSQL: 18.3-alpine3.23 - Redis: 8.6.2-alpine - Docker: 20.10+ - Docker Compose: 2.0+ ``` ## 四、验证标准(纯 Docker 环境) ### 4.1 执行命令 ```bash cd ./backend make dev ``` ### 4.2 预期结果 1. 容器启动:`gateway`/`user-svc`/`user-db`/`redis` 4 个容器状态为 `Up` 2. Proto 编译:无报错,`shared/proto/common/` 生成 `common.pb.go` 和 `common_grpc.pb.go` 3. 健康检查:`make test` 返回 `{"status":"ok"}` 4. 端口可访问: - `ws://localhost:8080/ws` 可建立 WebSocket 连接 - `localhost:5432` 可连接 PostgreSQL - `localhost:6379` 可连接 Redis ### 4.3 生产环境验证 ```bash # 构建生产镜像 make build # 启动生产环境 docker-compose up -d # 验证无源码挂载,服务正常运行 docker-compose ps curl http://localhost:8080/health ``` ## 五、关键优化点(适配纯 Docker 环境) 1. **Protoc 编译容器化**:无需宿主机安装 Protoc,通过专用容器完成 proto 编译 2. **依赖全内置**:所有 Go 模块、系统依赖均在 Docker 内安装,无宿主机依赖 3. **权限安全**:容器内使用非 root 用户运行服务,降低安全风险 4. **健康检查**:PostgreSQL/Redis 增加健康检查,确保服务就绪后启动应用 5. **日志与重启策略**:配置合理的重启策略和日志输出,便于问题排查 6. **网络隔离**:使用自定义网络,避免端口冲突和网络安全问题 ## 六、执行说明(给 Trae 的指令) 1. 确保目标机器已安装 Docker 和 Docker Compose 2. 将上述目录结构和文件完整生成到 `./backend/` 目录 3. 执行 `cd ./backend && make dev` 启动环境 4. 验证 `make test` 返回 `{"status":"ok"}` 即完成基础架构搭建 5. 后续业务逻辑开发可基于此骨架,通过挂载源码的开发模式迭代