如何在Go on Google Cloud Functions中使用子包?

时间:2019-01-18 13:56:32

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

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

我在Google工作。这个问题的目的是主动回答常见问题,并帮助开发人员从使用Go on GCF开始。

2 个答案:

答案 0 :(得分:5)

我们也遇到了这个问题。 @ 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包的子包。

答案 1 :(得分:4)

您可以将子包与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))
}

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