【问题标题】:How do I make vendoring work with Google App Engine?如何使供应商与 Google App Engine 一起工作?
【发布时间】:2017-02-18 06:29:06
【问题描述】:

我正在尝试将 Go vendoring(将依赖项存储在名为 vendor 的文件夹中)引入现有的 App Engine 项目。我已将所有依赖项存储在供应商文件夹中(使用 Godep 作为帮助程序),它看起来正确,但在本地运行应用程序时出现以下错误:

go-app-builder: Failed parsing input: package "golang.org/x/net/context" is imported from multiple locations: "/Users/erik/go/src/github.com/xyz/abc/vendor/golang.org/x/net/context" and "/Users/erik/go/src/golang.org/x/net/context"

我相信这两个位置应该解析到同一个位置,因为 Go 应用程序应该首先查看 vendor 文件夹。有没有办法让 Appengine 明白这两个依赖项是一样的?

【问题讨论】:

  • 我过去见过这个问题,通常通过确保我正在构建的存储库的所有vendor 目录都正确设置来解决。您正在运行导致此错误的命令是什么?
  • 错误来自 dev_appserver.py。假设供应商目录设置不正确似乎是合理的,但是您有什么线索吗?对我来说它看起来不错,我们的单元测试运行没有任何问题。
  • 据我了解,go-app-builder 工具的工作方式与标准 go 工具略有不同,以促进 App Engine 特定的构建,所以这可能就是您看到行为。您使用的是什么版本的 SDK?

标签: google-app-engine go


【解决方案1】:

您的项目目录(app.yaml 所在的位置)可能在 GOPATH/src 中。 不应该。 go-app-builder 将获取 app.yaml 文件夹(及以下)中的所有内容,并将您的 GOPATH 合并到其中,这意味着现在您拥有它两次。

解决方案是将 app.yaml 移出 GOPATH/src 文件夹。 此外,您会发现goapp test 在解决依赖关系时与goapp servegoapp deploy 的工作方式不同。

所以这是我一直在使用的解决方案(已经有一段时间没有使用 golang 应用程序引擎了),它是我发现的唯一设置可以正常工作所有 goapp 命令和 govendor 到工作正常(不确定godep

/GOPATH
├──/appengine
|   ├── app.yaml
|   └── aeloader.go
└──/src
    └── /MYPROJECT
         ├── main.go
         ├── /handler
         |    └── handler.go
         └── /vendor

详情:

file: GOPATH/appengine/aeloader.go (NOTE the init function is necessary, probably a bug though)
package mypackage

import (
    _ "MYPROJECT"
)

func init() {
}

现在从../GOPATH/appengine/ 运行goapp servegoapp deploy,从../GOPATH/src/MYPROJECT 运行goapp test ./...

附:我发现全局 GOPATH 的事情很愚蠢,只需将我的 GOPATH 设置为当前项目文件夹(在上面的示例中 /GOPATH)并将整个内容检查到版本控制中。

【讨论】:

  • 这太疯狂了。现在它必须住在外部 GOPATH?构建特质在哪里结束?不过谢谢。说真的。
  • 不错的答案。我在 GitHub 上创建了一个简单的应用程序来测试这种方法,它有效:github.com/nikolay-turpitko/x-gae-dep
【解决方案2】:

我使用 Makefile 将vendor 目录移动到临时的GOPATH

TMPGOPATH := $(shell mktemp -d)

deploy:
  mv vendor $(TMPGOPATH)/src
  GOPATH=$(TMPGOPATH) gcloud app deploy
  mv $(TMPGOPATH)/src vendor 

我将此 Makefile 存储在我的服务根目录附近的 vendor 目录中,并简单地使用 make deploy 手动部署或从 CI 部署。

它适用于 Glide、Godeps 或任何尊重 Go 供应商规范的工具。

请注意,您确实需要将vendor 目录移出构建目录,否则 GoAppEngine 编译器将尝试构建供应商依赖项,可能会导致编译错误。

【讨论】:

  • 这可能是最好的答案。您可以保持您的项目不是特定于 apengine 的,而不仅仅是像这样创建一个预构建步骤并以 appengine 想要的确切格式获取您的项目
  • 最佳方法/答案
【解决方案3】:

实际上,我自己也遇到了这个问题。当您使用 App Engine 工具构建任何导入正在使用供应商的东西的包时会出现问题,但您尝试运行的包在其供应商目录中没有导入。

因此,例如,如果我尝试运行包foo,它导入包bar,并且两者都使用github.com/gorilla/mux 库,如果bar 存储库有一个vendor/ 目录包含 gorilla/mux,但 foo 包的 vendor/ 目录中没有 gorilla mux,则会出现此错误。

发生这种情况的原因是bar 包将优先于它自己的vendor 包而不是GOPATH 中的包,这是foo 将使用的,导致实际位置的差异导入的路径。

我发现这个问题的解决方案是确保foo 目录在GOPATH 中并且正确安装了供应商目录。请务必注意,vendor/ 约定仅适用于 GOPATH

【讨论】:

    【解决方案4】:

    我设法使用 govendor 而不是 Godeps 解决了这个错误。根本原因似乎是 Godeps 未正确解析具有自己的供应商引用的供应商引用。

    Su-Au Hwang 提供的答案也是正确的 - 您必须将 app.yaml 与源代码分开。

    【讨论】:

      【解决方案5】:

      也遇到了同样的问题。 在docsGoogle 中提出以下建议:

      为获得最佳效果,我们建议如下:

      • 在您的应用目录中为每个服务创建一个单独的目录。
      • 每个服务的目录都应包含服务的 app.yaml 文件和一个或多个 .go 文件。
      • 不要在服务目录中包含任何子目录。
      • 您的 GOPATH 应指定一个位于您的应用目录之外的目录,并包含您的应用导入的所有依赖项。

      但这弄乱了我的项目结构,看起来像这样:

      GOPATH/
      └── src
          └── github.com
              └── username
                  └── myproject
                      ├── app.yaml
                      ├── cmd
                      │   └── myproject
                      │       └── main.go
                      ├── handlers
                      │   └── api.go
                      ├── mw
                      │   ├── auth.go
                      │   └── logger.go
                      └── vendor
      

      myproject 目录是一个 git 项目,vendor 文件夹包含所有依赖项。 从app.yaml 文件所在的myproject 目录运行gcloud deploy 不起作用,因为首先,main.go 文件不在同一个目录中,其次(来自同一个文档):

      您必须注意不要将您的源代码放置在 app.yaml 文件所在的应用目录或其下方

      我最终做的是构建自己的自定义运行时,结果证明这是一个非常干净的解决方案。
      只需使用以下命令生成Dockerfile

      gcloud beta app gen-config --custom
      

      修改它,然后在你的app.yaml中指定runtime: custom并正常部署。
      这里的诀窍当然是您可以控制在哪里复制什么。
      这是我的Dockerfile

      # Dockerfile extending the generic Go image with application files for a
      # single application.
      FROM gcr.io/google-appengine/golang
      
      ENV GOPATH /go
      
      # The files which are copied are specified in the .dockerignore file
      COPY . /go/src/github.com/username/myproject/
      
      WORKDIR /go/src/github.com/username/myproject/
      
      RUN go build -o dist/bin/myproject ./cmd/myproject
      
      # All configuration parameters are passed through environment variables and specified in app.yaml
      CMD ["/go/src/github.com/username/myproject/dist/bin/myproject"]
      

      不要忘记 App Engine 期望您的应用程序在端口 8080 上侦听。请查看 Building Custom Runtimes 文档了解更多详细信息。

      【讨论】:

        猜你喜欢
        • 2014-05-31
        • 2017-12-13
        • 2011-01-03
        • 2013-10-27
        • 1970-01-01
        • 2016-08-10
        • 2013-12-28
        • 1970-01-01
        • 2016-04-30
        相关资源
        最近更新 更多