从含共享模块的Go单体仓库部署服务的问题求助
解决方案
方案一:使用Go Workspace(Go 1.18+)+ 多阶段Docker构建
这是单体仓库场景下最高效的方案,既解决本地开发的模块关联问题,又能实现Docker构建时仅复制必要文件。
步骤:
- 在仓库根目录创建
go.work文件,统一管理所有模块:
go 1.20 use ( ./services/svc1 ./services/svc2 ./libs/lib1 ./libs/lib2 )
- 移除各服务
go.mod中的replace语句,仅保留require声明即可(Workspace会自动关联本地模块):
module example.com/services/svc1 go 1.20 require example.com/libs/lib1 v0.0.0
- 为每个服务编写多阶段Dockerfile(以svc1为例,放在
services/svc1/Dockerfile):
# 构建阶段:仅复制必要依赖与源码 FROM golang:1.20-alpine AS builder WORKDIR /app # 先复制依赖文件,利用Docker缓存加速构建 COPY go.work go.work.sum ./ COPY services/svc1/go.mod services/svc1/go.sum ./services/svc1/ COPY libs/lib1/go.mod libs/lib1/go.sum ./libs/lib1/ # 下载依赖 RUN go mod download -C ./services/svc1 # 复制服务与依赖库的源码 COPY services/svc1/ ./services/svc1/ COPY libs/lib1/ ./libs/lib1/ # 编译可执行文件 RUN go build -o /svc1 ./services/svc1/main.go # 运行阶段:仅保留编译后的二进制文件,缩小镜像体积 FROM alpine:latest WORKDIR /app COPY --from=builder /svc1 . CMD ["./svc1"]
- 构建镜像时,从仓库根目录执行命令(确保上下文能访问到libs和services):
docker build -f services/svc1/Dockerfile . -t svc1:latest
方案二:模块版本化+伪版本(解决跨分支依赖问题)
如果共享库仅存在于非主分支(如dev),可以通过Go模块的版本化机制让go mod直接下载分支代码,无需本地replace。
步骤:
- 为共享库生成版本标签或伪版本:
- 打正式标签:在仓库根目录执行
git tag example.com/libs/lib1/v0.1.0(标签格式需匹配模块路径),推送到远程仓库。 - 伪版本(适合临时分支):获取分支最新commit哈希,生成伪版本号,格式为
v0.0.0-YYYYMMDDHHMMSS-<commit哈希>,例如v0.0.0-20240520153000-abcdef123456。
- 打正式标签:在仓库根目录执行
- 更新服务的
go.mod,直接引用对应版本,移除replace:
module example.com/services/svc1 go 1.20 require example.com/libs/lib1 v0.1.0 # 或伪版本:require example.com/libs/lib1 v0.0.0-20240520153000-abcdef123456
- 服务的Dockerfile可简化为仅复制自身代码(依赖通过
go mod download从远程拉取):
FROM golang:1.20-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o /svc1 main.go FROM alpine:latest COPY --from=builder /svc1 . CMD ["./svc1"]
- 直接在服务目录构建镜像即可:
cd services/svc1 && docker build . -t svc1:latest
方案三:Docker上下文过滤(适合临时场景)
如果不想修改模块结构,可通过.dockerignore或构建参数过滤不必要的文件,减少构建上下文体积。
步骤:
- 在仓库根目录创建针对svc1的忽略文件
.dockerignore-svc1:
services/svc2/ libs/lib2/ .git/
- 构建时指定忽略文件,仅复制svc1和lib1相关内容:
docker build -f services/svc1/Dockerfile --exclude-file .dockerignore-svc1 . -t svc1:latest
注意:此方案仍需保留
replace语句,无法解决跨分支依赖下载问题,仅适合本地构建场景。
内容的提问来源于stack exchange,提问作者abh1sheke
相关产品推荐
相关产品推荐

