【问题标题】:write dockerfile for multiple go.mod project为多个 go.mod 项目编写 dockerfile
【发布时间】:2021-02-16 01:41:15
【问题描述】:

有一个用 Go 编写的库。它的文件夹结构是:

lib/
    golang/
        go.mod
        lib.go
        example/
            golang/
                proto/
                    protofile
                go.mod
                main.go
                Dockerfile

example 是展示如何使用这个库的文件夹,所以它有一个可以构建和运行的 main.go。为了使用 lib,example/golang/go.mod 是:

module golang

go 1.15

require (
    lib/golang v0.0.0
    other stuff...
)

replace lib/golang => ../../golang
    

现在我想把可运行的例子打包成一个docker镜像,Dockerfile是:

FROM golang:1.15

WORKDIR /go/src/app
COPY . .

RUN go env -w GO111MODULE=auto
RUN go env -w GOPROXY=https://goproxy.io,direct

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

然后我 cd 进入 example/golang 运行docker build -t example .,错误日志是

open /go/golang/go.mod: no such file or directory

好像无法访问 lib/go.mod 文件,然后我 cd 到 lib 文件夹并运行 docker build -t server -f examples/golang/Dockerfile .,但这会影响 main.go 的导入:

import "golang/proto"

错误日志是:

golang/proto: unrecognized import path "golang/proto"

我应该如何解决这个问题以制作 docker 镜像?

============================================

在我花了一些时间阅读 docker doc 之后,这里是关于这个问题的总结:

docker build 命令遵循 PATH 参数,即末尾的点 .。控制构建的内容,它决定了 docker build 可以访问哪些文件。所以第一个错误的原因是 pwd 是 lib/example/golang,而 docker build 命令路径是.,那么 docker build 无法访问 lib/example/golang 的父文件,它们在 main.go 中是必需的一个库。 命令应该是:docker build -t example ../../ 但是,docker build 只在内容路径的根目录中寻找 Dockerfile,所以使用 -f 告诉它 Dockerfile 的位置:docker build -t example -f ./Dockerfile ../../

如果 pwd 为 lib/,则命令为 docker build -t server -f examples/golang/Dockerfile .

简短:

  1. 如果 dockerfile 不在项目根路径下,请使用 docker build 命令的 -f 和 PATH 为其提供足够的文件访问权限。如果使用 go 模块,请确保 PATH 包含 go.mod 文件
  2. 如果main.go位于子文件夹,请确保dockerfile中的WORKDIR与COPY后的子文件夹一致,否则go build或go install编译失败

【问题讨论】:

  • "golang/proto" 是无效的导入路径。你需要解决这个问题。这不是 docker 的问题。
  • run go build without dockerfile 会成功,不是编码错误
  • go build 工作并不意味着它不是编码错误。您的 Docker 外部环境可能允许无效的导入路径。
  • 你的 Dockerfile 是嵌套的 - 所以 docker build . 构建上下文看不到父目录库。

标签: docker go


【解决方案1】:

您的Dockerfile 嵌套过多。由于您的 go build 依赖于相对路径 - 父目录中的路径 - docker build . 不会看到任何父目录文件。

Dockerfile 移到顶部,例如

Dockerile
lib/

并更新以构建嵌套的构建目录:

FROM golang:1.15

WORKDIR /go/src/app

# just need to copy lib tree
COPY lib .  

# working from here now
WORKDIR /go/src/app/lib/golang/example/golang 

RUN go env -w GO111MODULE=auto    
RUN go env -w GOPROXY=https://goproxy.io,direct

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

【讨论】:

  • 我对 Docker 层有一个考虑,docs.docker.com/develop/develop-images/… 我的意思是也许我们可以这样写来减少镜像层,这有什么意义吗? ``` RUN GO111MODULE=auto GOPROXY=goproxy.io,direct go get -d -v ./... RUN GO111MODULE=auto GOPROXY=goproxy.io,direct go install -v ./... ```
  • 您可以使用多阶段 docker build 并且仅将构建的资产复制到最后阶段 - 这将减少/消除任何中间 docker 层。
【解决方案2】:

您可以在使用 Docker 构建之前使用go mod vendor,它会将您的所有 mod 集中在 vendor 文件夹中。

我在里面做了一个名为 build.sh 的新文件:

#! /bin/sh
go mod vendor
docker build . -t myapp/myservice
rm -rf ./vendor

并在我需要构建时运行它,通过删除供应商我仍然可以使用 go run *.go 和我的库的新版本

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 2016-03-27
    • 2023-03-16
    • 2020-11-06
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    相关资源
    最近更新 更多