FROM golang:1.25-alpine AS builder ENV CGO_ENABLED=0 ENV GO111MODULE=on ENV GOPROXY=https://goproxy.cn,direct # 确保 PATH 包含 Go bin 目录,以便 protoc 能找到插件 ENV PATH=$PATH:/go/bin # 安装构建所需的工具:git、protoc、make RUN apk add --no-cache git protobuf make WORKDIR /app # 复制 go.work 文件(用于工作区配置,必须在项目根目录) COPY go.work go.work.sum* ./ # 复制所有模块的 go.mod 文件(先复制所有依赖文件以利用 Docker 缓存) # 需要先复制所有 go.mod,因为 go.work 引用了它们 COPY server/go.mod server/go.sum ./server/ COPY grpc/user/userv1/go.mod grpc/user/userv1/go.sum* ./grpc/user/userv1/ # 在项目根目录执行 go mod download(go.work 会自动处理所有模块) WORKDIR /app RUN go work sync # 安装 protoc 插件(需要在有 go.mod 的环境中安装) # 使用临时工作目录安装插件,避免影响项目目录 WORKDIR /tmp RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest && \ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest && \ go install github.com/envoyproxy/protoc-gen-validate@latest && \ go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http@latest && \ go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors@latest # 复制 grpc 目录(包括 proto 文件和 Makefile) WORKDIR /app COPY grpc/ ./grpc/ # 在容器内生成 proto 文件(只生成需要的文件,排除 HTTP 相关) WORKDIR /app/grpc # 只生成 go、grpc、validate 和 errors 文件,不生成 http 文件(避免依赖问题) RUN protoc --proto_path=./ \ --proto_path=./third_party \ --go_out=paths=source_relative:./ \ --go-grpc_out=paths=source_relative:./ \ --validate_out=paths=source_relative,lang=go:./ \ --go-errors_out=paths=source_relative:./ \ $(find . -path "./third_party" -prune -o -type f -name "*.proto" -print) # 生成 proto 后,更新依赖(proto 生成的文件可能需要额外的依赖) WORKDIR /app/grpc/user/userv1 RUN go mod tidy # 复制 server 源代码 WORKDIR /app COPY server/ ./server/ # 构建应用(在项目根目录,go.work 会自动生效) # 使用 -ldflags 减小二进制文件大小,移除调试信息 WORKDIR /app/server RUN go build -ldflags="-w -s" -trimpath -o /out/server ./cmd/server/main.go && \ chmod +x /out/server # 使用最小化的 alpine 镜像(包含时区支持,应用需要 loc=Local) FROM alpine:3.19 # 只安装运行时必需的包:时区和 CA 证书(用于可能的 HTTPS 连接) RUN apk add --no-cache ca-certificates tzdata && \ # 创建非 root 用户 addgroup -g 1000 appuser && \ adduser -D -u 1000 -G appuser appuser && \ # 清理缓存 rm -rf /var/cache/apk/* WORKDIR /app COPY --from=builder /out/server /app/server # 设置文件所有者和执行权限(在切换用户之前) RUN chown appuser:appuser /app/server && chmod +x /app/server # 创建必要的目录 RUN mkdir -p /app/storage/export /app/log && \ chown -R appuser:appuser /app/storage /app/log EXPOSE 8077 USER appuser:appuser ENTRYPOINT ["/app/server"]