在父目录中运行"go mod download"的Golang实践指南

在父目录中运行"go mod download"的Golang实践指南 项目结构:

project_dir/
├── prj1/
│   ├── go/
│   ├─    |─ go.mod
│   ├─    |─ main.go
│   └─    |─ ...
│   └── ...
├── prj2/
│   ├── go.mod
│   ├── main.go
│   └── Dockerfile
│   └── ...
└── ...

prj2 中的代码通过 go mod edit -replace 命令引用了 prj1 中的一个函数。现在,这在本地运行良好,但我需要使用 Docker 进行部署,并且遇到了问题。

我的 Docker 脚本如下所示:

FROM golang:1.17.5 as builder

WORKDIR /app

COPY go.* ./
ADD ./prj1 ./prj1
RUN go mod download
...

最初,我在 prj2 目录内运行 docker build .,Dockerfile 中没有 ADD 命令,但 RUN go mod download 失败并提示:

go mod download: github.com/name/project/prj1@v0.0.0-00010101000000-000000000000 (replaced by …/prj1/go/): reading /prj1/go/go.mod: open /prj1/go/go.mod: no such file or directory

因此,我在 Dockerfile 中添加了 ADD 命令来复制 prj1。接着,我回到 project_dir 并运行 docker build -f ./prj2/Dockerfile,但现在 RUN go mod download 又失败了,提示:

go mod download: no modules specified (see ‘go help mod download’)

所以,我的基本问题是,如何告知 go 命令 go.mod 文件位于 prj2 目录内?

编辑: 正确的项目结构


更多关于在父目录中运行"go mod download"的Golang实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

替换的格式如下: replace github.com/name/project/prj1 => …/proj1/go/

更多关于在父目录中运行"go mod download"的Golang实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你 prj2/go.mod 中的 “replace” 是相对路径吗?或许你可以尝试 replace … => /app/prj1

我认为 将 http://github.com/name/project/prj1 替换为 /app/proj1/go 应该是可行的,因为 proj1 的完整路径位于 /app 目录下。

你好,@ozuf

go mod download 必须在 go.mod 文件所在的目录中运行。(换句话说,在主模块内部)。对于 Docker,这可能意味着 go.mod 文件必须在 WORKDIR 目录下(或者 WORKDIR 必须指向 go.mod 文件所在的位置)。

关于另一个错误,.../prj1/go 中的三个点是故意的吗?我认为应该只有两个点,这样才符合项目结构。

在父目录中运行 go mod download 时,需要指定正确的模块路径。以下是解决方案:

解决方案

1. 修改 Dockerfile 使用正确的上下文和工作目录

FROM golang:1.17.5 as builder

# 设置工作目录到 prj2
WORKDIR /app/prj2

# 复制整个项目结构
COPY . /app/

# 复制 prj2 的 go.mod 和 go.sum
COPY prj2/go.mod prj2/go.sum ./

# 下载依赖
RUN go mod download

# 复制源代码
COPY prj2/ ./

# 构建
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

2. 使用多阶段构建的完整示例

FROM golang:1.17.5 as builder

# 设置项目根目录
WORKDIR /app

# 复制所有 go.mod 文件
COPY prj1/go/go.mod ./prj1/go/
COPY prj2/go.mod ./prj2/

# 复制 go.sum 文件(如果存在)
COPY prj1/go/go.sum ./prj1/go/ 2>/dev/null || true
COPY prj2/go.sum ./prj2/ 2>/dev/null || true

# 在 prj2 目录中下载依赖
WORKDIR /app/prj2
RUN go mod download

# 复制所有源代码
COPY . .

# 构建 prj2
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# 最终阶段
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/prj2/main .
CMD ["./main"]

3. 使用构建参数指定模块路径

FROM golang:1.17.5 as builder

ARG MODULE_PATH=prj2

WORKDIR /app

# 复制必要的文件
COPY ${MODULE_PATH}/go.mod ${MODULE_PATH}/go.sum ./

# 下载依赖
RUN go mod download

# 复制源代码
COPY ${MODULE_PATH}/ ./
COPY prj1/go/ ./prj1/go/

# 构建
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

4. 使用 docker-compose 的配置示例

version: '3.8'
services:
  prj2:
    build:
      context: .
      dockerfile: prj2/Dockerfile
    volumes:
      - ./prj2:/app/prj2
      - ./prj1/go:/app/prj1/go

5. 关键点说明

在 prj2 的 go.mod 中,replace 指令应该正确指向本地路径:

module github.com/yourname/prj2

go 1.17

replace github.com/yourname/prj1 => ../prj1/go

require github.com/yourname/prj1 v0.0.0

构建命令应该从项目根目录执行:

# 从项目根目录构建
docker build -f prj2/Dockerfile -t prj2-app .

# 或者进入 prj2 目录构建
cd prj2
docker build -t prj2-app .

6. 验证构建的脚本

#!/bin/bash
# build.sh

# 确保在项目根目录
if [ ! -f "prj2/Dockerfile" ]; then
    echo "请在项目根目录运行此脚本"
    exit 1
fi

# 清理旧的构建
docker rm -f prj2-build 2>/dev/null || true

# 构建镜像
docker build -f prj2/Dockerfile -t prj2-app .

# 验证构建
docker run --rm prj2-app go version

这些方法都能解决在父目录中运行 go mod download 时找不到正确模块的问题。关键是要确保 Docker 构建上下文正确,并且 go mod download 在包含正确 go.mod 文件的目录中执行。

回到顶部