【问题标题】:Build Docker with Go app: cannot find package使用 Go 应用构建 Docker:找不到包
【发布时间】:2018-05-29 22:44:28
【问题描述】:

我的 Dockerfile 位于带有 src/myapp 文件夹的目录的根目录中,myapp 包含带有主包的 myapp.go

Dockerfile 如下所示:

FROM golang:1.9.2

ADD . /
RUN go build myapp;

ENTRYPOINT ["/go/bin/myapp"]

我收到以下错误:

can't load package: package myapp: cannot find package "myapp" in any of:
    /usr/local/go/src/myapp (from $GOROOT)
    /go/src/myapp (from $GOPATH)

我做错了什么?在 docker 完成ADD 之后,我可以记录ls 命令吗?

【问题讨论】:

  • 答案是正确的,因为您需要确保您的应用程序正确复制到 go 路径中。但是,这假设您已经出售了所有依赖项 - 如果没有,您可能需要 go get 或 dep 以确保这些依赖项可用。但是,如果目标是使您的二进制文件可移植,那么在 docker 之外为 linux 编译、复制二进制文件然后从头开始构建轻量级容器可能是一种更好的方法,因为您不会无意中在应用程序中发布所有源代码.

标签: docker go


【解决方案1】:

您正在将所有文件复制到 Image 根目录,没有安装任何依赖项,正在尝试构建它,然后从 /go/bin/app 运行二进制文件。该目录中不存在二进制文件,并且正在生成错误。

我会推荐使用这样的 Dockerfile,

FROM golang:1.9.2 
ADD . /go/src/myapp
WORKDIR /go/src/myapp
RUN go get myapp
RUN go install
ENTRYPOINT ["/go/bin/myapp"]

这将执行以下操作。

  1. 将项目文件复制到/go/src/myapp
  2. 将工作目录设置为/go/src/myapp
  3. 安装依赖项,我使用了 go get,但将其替换为您正在使用的依赖项管理工具。
  4. 安装/构建二进制文件。
  5. 设置入口点。

您可以运行ls 或使用docker exec 的任何其他命令。

例子:

docker exec <image name/hash> ls

你也可以在生成的图片中输入shell来很好的理解使用

docker run --rm -it <image hash/name> /bin/sh

【讨论】:

    【解决方案2】:

    经过实验,我找到了这种构建 Golang 应用程序的方式。

    这种方式有几个优点:

    • 依赖安装在构建阶段

    • 如果需要,可以取消注释测试选项

    • 构建第一个大约 800 MB 的全功能映像

    • 将您的程序复制到一个新的空图像并生成大约 10 MB 的非常小的图像

    Dockerfile

    # Two-stage build:
    #    first  FROM prepares a binary file in full environment ~780MB
    #    second FROM takes only binary file ~10MB
    
    FROM golang:1.9 AS builder
    
    RUN go version
    
    COPY . "/go/src/github.com/your-login/your-project"
    WORKDIR "/go/src/github.com/your-login/your-project"
    
    #RUN go get -v -t  .
    RUN set -x && \
        #go get github.com/2tvenom/go-test-teamcity && \  
        go get github.com/golang/dep/cmd/dep && \
        dep ensure -v
    
    RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build  -o /your-app
    
    CMD ["/your-app"]
    
    EXPOSE 8000
    
    
    
    #########
    # second stage to obtain a very small image
    FROM scratch
    
    COPY --from=builder /your-app .
    
    EXPOSE 8000
    
    CMD ["/your-app"]
    

    【讨论】:

    • 这种方法很好。我以前从来没有真正理解过多级 Docker 镜像。谢谢。
    • 我认为你不需要 CMD,先 FROM 中的 EXPOSE
    【解决方案3】:

    go 1.11 可以使用 go 模块,下面是例子

    FROM alpine AS base
    RUN apk add --no-cache curl wget
    
    FROM golang:1.11 AS go-builder
    WORKDIR /go/app
    COPY . /go/app
    RUN GO111MODULE=on  CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /go/app/main /go/app/cmd/myapp/main.go
    
    FROM base
    COPY --from=go-builder /go/app/main /main
    CMD ["/main"]
    

    【讨论】:

      【解决方案4】:

      官方文档建议使用以下 Dockerfile:

      FROM golang:1.8
      
      WORKDIR /go/src/app
      COPY . .
      
      RUN go get -d -v ./...
      RUN go install -v ./...
      
      CMD ["app"]
      

      请访问https://hub.docker.com/_/golang了解更多信息

      【讨论】:

        【解决方案5】:

        myapp 需要按照建议在/go/src/myapp 中,或者在/usr/local/go/src/myapp 中。您可以将其添加到ADD 部分。

        【讨论】:

          【解决方案6】:

          如果目标是创建一个简单地运行二进制文件的容器,我会采取不同的方法。

          首先为 linux 构建二进制文件:

          GOOS=linux CGO_ENABLED=0 go build -a -installsuffix cgo
          

          然后从头构建一个轻量级的docker镜像:

          FROM scratch
          COPY myApp 
          CMD ["/myApp"]
          

          【讨论】:

          • Docker 中有多阶段构建之类的东西,即使你写了这篇文章时也可以使用 atm
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-04
          • 2020-11-07
          • 2016-12-24
          • 1970-01-01
          相关资源
          最近更新 更多