【问题标题】:Manage local/private Golang packages and modules for docker builds管理用于 docker 构建的本地/私有 Golang 包和模块
【发布时间】:2020-04-19 04:29:25
【问题描述】:

我对 golang 和 docker 还是很陌生,所以在查看了许多线程和互联网资源之后,我最终对如何设置感到困惑。

我的问题是由于未找到本地依赖项,我正面临 golang 应用程序的 docker build 错误。

仅供参考(本地机器):go 版本 go1.13.4 linux/amd64

这是我的问题的背景:

我有一个存储库,其中包含将在 Kubernetes 中运行的简单微服务(用 Go 编写)的源代码。因此存储库中的每个文件夹都代表一个服务。我还有一个文件夹“工具”,它重新组合了许多服务共享的辅助功能和资源。 我的存储库不在任何 Go 特殊路径中,它位于我的一个驱动器的根目录中。 所以这是我的仓库的样子:

.
├── service1
│   ├── main.go
│   ├── Dockerfile
│   ├── go.mod
│   └── go.sum
├── service2
├── service3
│   ...
├── serviceX
├── tools
│   ├── helpers.go
│   ├── ressources.go
│   ├── go.mod
└── └── go.sum

因此,每个文件夹/服务都是一个独立处理其依赖关系的 go 模块。文件夹工具也是一个模块。 我用go mod init FOLDER_NAME初始化了每个模块

在服务service1中我引用了模块tools来使用一些功能。以下是我的实现方式:(./service1/main.go 的 src)

package main

import (
    "fmt"

    st "../tools"

    // other modules imports
)

func main() {
    st.ExecHelperFunc()
    // http server inits
}

当我在本地运行 service1's main.go 或者我在本地构建它并在之后运行二进制文件时,服务可以正常工作。

但是当我尝试构建 service1 的 dockerfile 时,我得到 golang build 错误: build _/go/src/app/tools: cannot find module for path _/go/src/app/tools

这是我的 dockerfile:

FROM golang:1.13 as builder
ENV GO111MODULE=on
WORKDIR /go/src/app
COPY ./tools ./tools
COPY ./service1 ./service1

WORKDIR /go/src/app/tools
RUN go mod download
WORKDIR /go/src/app/service1
RUN go mod download

WORKDIR /go/src/app

RUN go build -o server /go/src/app/service1/main.go

FROM centos:7
RUN yum -y update && yum clean all
COPY --from=builder /go/src/app/server .
EXPOSE 3000
CMD ["./server"]

所以我不明白为什么 docker 无法构建服务?显然他无法定位/识别模块工具,但为什么呢?我为 dockerfile 尝试了许多不同的设置,但仍然无法弄清楚。

提前感谢您的帮助。

更新:

正如答案中所建议的,将 dockerfile 中 GO111MODULE 的值从 on 更改为 auto 并不能解决构建错误,而是让我得到一个新错误:

unexpected directory layout:
    import path: _/go/src/app/tools
    root: /go/src
    dir: /go/src/app/tools
    expand root: /go
    expand dir: /go/src/app/tools
    separator: /

【问题讨论】:

    标签: docker go go-modules go-packages


    【解决方案1】:

    您应该将环境变量 GO111MODULE 更改为 auto。

    最终的 Dockerfile 是:

    FROM golang:1.13 as builder
    ENV GO111MODULE=auto
    WORKDIR /go/src/app
    COPY ./tools ./tools
    COPY ./service1 ./service1
    
    WORKDIR /go/src/app/tools
    RUN go mod download
    WORKDIR /go/src/app/service1
    RUN go mod download
    
    WORKDIR /go/src/app
    
    RUN go build -o server /go/src/app/service1/main.go
    
    FROM centos:7
    RUN yum -y update && yum clean all
    COPY --from=builder /go/src/app/server .
    EXPOSE 3000
    CMD ["./server"]
    

    更新

    在我看来,如果 GO111MODULE 等于 'auto',golang 将禁用模块功能,并在 GOPATH 中查找第三方包。在编译代码之前,你应该go get -u github.com/op/go-logging。我想这不是你想要的。

    根据示例here,我更新了我的repo,here。您可以尝试在 docker 容器中构建代码。可以编译成功,但是需要改一下包名。

    【讨论】:

    • 嗨!谢谢您的回答。不幸的是,将 GO111MODULE 更改为 auto 并没有使 docker build 成功。现在我在 go build 行仍然有一个新错误:unexpected directory layout: import path: _/go/src/app/tools root: /go/src dir: /go/src/app/tools expand root: /go expand dir: /go/src/app/tools separator: /
    • 你错过了什么重要的事情吗?我在这里创建了一个演示。(github.com/juxuny/go-build-trial)。您只需进入根目录并运行docker build -t go-build-demo -f service1/Dockerfile .
    • 感谢您的所有努力和帮助!对此,我真的非常感激。我克隆了您的存储库,并且可以毫无错误地构建 dockerfile。但是工具模块是“裸露的”,而我正在尝试构建的工具模块实际上使用了不同的公共模块。所以我添加了一个简单的日志模块并尝试再次构建。它失败了,和我的错误一样。如果您允许,我会将我的修改推送到一个分支中
    • 好的,你可以将你的修改推送到一个分支中。让我看看出了什么问题。
    • 我分叉了你的仓库,然后创建了一个 PR 来让事情变得简单干净;)
    【解决方案2】:

    对于面临类似问题的任何人 - 我使用 vendor 目录解决了类似问题。基本上,您通过运行go mod vendor 下载主机上的依赖项,然后它们将自动复制到 docker 容器中。

    从 Dockerfile 中,您必须删除 RUN go mod download,并且您还需要使用 -mod=vendor 标志修改构建命令。

    要构建 docker 镜像,您需要运行这些命令

    go mod vendor
    docker build . -t image-name
    

    我希望这会对某人有所帮助。我在这里找到了这个解决方案:https://smartystreets.com/blog/2018/09/private-dependencies-in-docker-and-go/

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 2020-04-28
      • 2020-02-26
      • 2020-11-07
      • 2015-09-05
      • 2022-11-09
      • 2021-04-25
      相关资源
      最近更新 更多