【问题标题】:How can I use a sub-packages with Go on Google Cloud Functions?如何在 Go on Google Cloud Functions 上使用子包?
【发布时间】:2019-06-12 19:23:01
【问题描述】:

我想使用来自 Go Cloud Function 的帮助程序包。该包有一些可以在多个函数之间共享的辅助逻辑。但是,构建包以使它们都能正常工作的正确方法是什么?包应该在同一个项目中 - 不作为一个完全独立的包发布和公开。

我在谷歌工作。此问题的目标是主动回答常见问题并帮助开发人员从 Go on GCF 开始。

【问题讨论】:

  • 我知道这个问题之前已经回答过了,但是我经历了类似的旅程并写了一篇关于它的帖子——也许它会有所帮助medium.com/@rizwaniqbal/…

标签: go google-cloud-platform google-cloud-functions


【解决方案1】:

您可以使用带有Go modules 的子包。 Go 模块是 Go 的新依赖管理解决方案 - 它们让您可以在 GOPATH 之外工作,并让您管理您拥有的每个依赖项的确切版本。

模块还允许您定义一组具有相同导入路径前缀的 Go 包。当你编写一个函数时,这可以让你在你的模块中导入其他包。

您要部署的功能需要位于模块的根目录。

这是一个示例文件结构以及如何导入包:

.
├── cmd
│   └── main.go # Useful for testing. Can import and setup your function.
├── function.go # Can import example.com/foo/helperpackage
├── function_test.go
├── go.mod # module example.com/foo
└── helperpackage
    └── helper.go

此设置在function.go 中有您的功能,并由function_test.go 测试。它们位于名为example.com/foo 的模块中。 helperpackage 可以通过function.go 使用example.com/foo/helperpackage 导入。

这也有一个cmd 目录,可能对本地测试有帮助。您可以导入 example.com/foo 并启动一个 HTTP 服务器,它将您的函数注册为一个 HTTP 处理程序。例如:

package main

import (
    "log"
    "net/http"

    "example.com/foo"
)

func main() {
    http.Handle("/HelloHTTP", foo.HelloHTTP)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

注意:您可以使用供应商目录来获得相同的结果。但是,您的函数导入的所有包都需要位于供应商目录(具有完整的导入路径)中,这可行,但维护起来很麻烦。将子包复制到您的供应商目录中并不常见,因此我不建议这样做。

【讨论】:

  • 我完全按照您的描述进行了尝试,但我的错误是:Deployment failure: Build failed: go: finding cloud.google.com/go v0.40.0 go: finding rsc.io/binaryregexp v0.2.0 go: finding google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 files/restaurant/main.go:5:2: unknown import path "example/backend/database": cannot find module providing package example/backend/database files/main.go:7:2: unknown import path "example/backend/proto": cannot find module providing package example/backend/proto您能帮忙吗?
  • 你的模块名称是什么?导入应该以你的模块名称为前缀(类似于example.com/example/backend/proto)。
  • @TylerBui-Palsulich 我和Brian有类似的问题,花时间写了详细的重现步骤,你可以在:stackoverflow.com/questions/58722009/…
  • 那么现实生活中的场景如何,具有多个功能?例如如果我们需要另一个 gcf 中的 helperpackage 怎么办?另一个带有 cmd/main.go、function.go 等的目录
【解决方案2】:

我们也遇到了这个问题。 @TylerBui-Palsulich (https://stackoverflow.com/a/54255486/2307346) 提供的 go.mod 方法不起作用,因为我们还必须从私有存储库下载依赖项。

来自 Google 文档:

如果您的函数的依赖项托管在不可公开访问的存储库中,则必须在部署函数之前使用供应商目录来获取您的依赖项 (https://cloud.google.com/functions/docs/writing/specifying-dependencies-go#using_a_vendor_directory)

给定以下包结构:

cloudfunctions.go
sharedpackage
-> shared.go
go.mod

在我们的go.mod 文件中,我们定义了以下命名空间:module some/namespace cloudfunctions.go 文件具有以下包定义和导入

package foobar

import (
    "bitbucket.org/some/private/dependency"
    "some/namespace/sharedpackage"
)

由于私有依赖,我们不能使用 go.mod 文件。相反,我们提供了一个vendor 目录。

警告:如果您的项目根目录下同时有 go.mod 文件和供应商目录,则在云中构建函数时,供应商目录的内容将被忽略。为确保使用您的供应商目录,您必须在部署之前从项目的源代码中排除 go.mod 文件。如果您使用的是 gcloud 命令行工具,则可以通过使用 .gcloudignore 确保 go.mod 不上传。 (https://cloud.google.com/functions/docs/writing/specifying-dependencies-go#using_a_vendor_directory)

gcloud deploy 如果找到 go.mod 将忽略供应商目录,我们使用具有以下内容的 .gloudignore 文件修复此问题:

go.mod
go.sum

最后我们有以下文件结构:

cloudfunctions.go
sharedpackage
-> shared.go
go.mod
vendor
.gcloudignore

最后一步,修复找不到包错误

在运行部署步骤时,您仍然会遇到类似以下的错误:

 (gcloud.functions.deploy) OperationError: code=3, message=Build failed: /tmp/sgb/gopath/src/serverlessapp/vendor/some/namespace/cloud_functions.go:5:2: cannot find package "some/namespace/sharedpackage" in any of:...

这是因为包含模块名称的go.mod 文件被忽略了。现在 Go 编译器不再知道 some/namespace/sharedpackage 指的是本地的 sharedpackage 目录。

我们设法通过更改模块名称以匹配包名称来使其工作:

go.mod 中的模块名称更改为module foobarcloudfunctions.go 中的导入更改为:"foobar/sharedpackage"

package foobar

import (
    "bitbucket.org/some/private/dependency"
    "foobar/sharedpackage"
)

现在 Go 编译器能够检测到 foobar/sharedpackagefoobar 包的子包。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 2017-10-03
    • 2020-11-03
    • 1970-01-01
    相关资源
    最近更新 更多