如何在你自己的项目中使用私有Go模块

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Diversity in Tech Fund 来接受捐赠。

介绍

Go 生态系统的一个有利方面是大量模块是开源的。 由于它们是开源的,因此可以自由访问、检查、使用和学习。 但是,有时出于各种原因需要制作私有 Go 模块,例如将专有业务逻辑保留在公司内部。

在本教程中,您将发布私有 Go 模块,设置身份验证以访问私有模块,并在项目中使用私有 Go 模块。

先决条件

  • Go version 1.16 or greater installed. To set this up, follow the How To Install Go tutorial for your operating system.
  • 对分发 Go 模块的理解,可以在 如何分发 Go 模块 教程中找到。
  • 熟悉Git,可以参考【X53X】如何使用Git:参考指南【X90X】。
  • 一个名为 mysecret 的空私有 GitHub 存储库,用于您发布的私有模块。 要开始使用,请按照 GitHub 文档创建存储库
  • 一个 GitHub 个人访问令牌 可以从您的存储库中读取。 您将使用它来允许 Go 访问您的私有存储库。

分发私有模块

与许多编程语言不同,Go 从存储库而不是中央包服务器分发模块。 这种方法的一个好处是发布私有模块与发布公共模块非常相似。 Go 私有模块不需要完全独立的私有包服务器,而是通过私有源代码存储库分发。 由于大多数源代码托管选项都支持开箱即用,因此无需设置额外的专用服务器。

为了使用私有模块,您需要访问私有 Go 模块。 在本节中,您将创建和发布一个私有模块,您可以在本教程后面使用它来从另一个 Go 程序访问私有模块。

要创建新的私有 Go 模块,首先要克隆它所在的私有 GitHub 存储库。 作为先决条件的一部分,您在 GitHub 帐户中创建了一个名为 mysecret 的私有空存储库,这是您将用于私有模块的存储库。 该存储库可以克隆到您计算机上任何您想要的位置,但许多开发人员倾向于为他们的项目创建一个目录。 在本教程中,您将使用一个名为 projects 的目录。

创建 projects 目录并导航到它:

mkdir projects
cd projects

projects 目录,运行 git clone 将您的私有 mysecret 存储库克隆到您的计算机:

git clone git@github.com:your_github_username/mysecret.git

Git 会确认它已经克隆了你的模块,并且可能会警告你克隆了一个空的存储库。 如果是这样,这不是您需要担心的事情:

OutputCloning into 'mysecret'...
warning: You appear to have cloned an empty repository.

接下来,使用 cd 进入您克隆的新 mysecret 目录,并使用 go mod init 以及您的私有存储库的名称来创建一个新的 Go 模块:

cd mysecret
go mod init github.com/your_github_username/mysecret

现在你的模块已经创建好了,是时候添加一个你可以从另一个项目中使用的函数了。 使用 nano 或您喜欢的文本编辑器打开与您的存储库同名的文件,例如 mysecret.go。 该名称并不重要,可以是任何名称,但使用与存储库相同的名称可以更轻松地确定在使用新模块时首先要查找的文件:

nano mysecret.go

mysecret.go 文件中,将包命名为与您的存储库相同的名称,然后添加一个 SecretProcess 函数以在调用时打印 Running the secret process! 行:

项目/mysecret/mysecret.go

package mysecret

import "fmt"

func SecretProcess() {
    fmt.Println("Running the secret process!")
}

现在您已经创建了私有模块,您将把它发布到您的私有存储库以供其他人使用。 由于您的私有存储库仅允许您最初访问它,因此您可以控制谁可以访问您的私有模块。 您可以限制对自己的访问,但也可以向朋友或同事授予访问权限。

由于私有和公共 Go 模块都是源存储库,因此发布私有 Go 模块遵循与发布公共模块相同的过程。 要发布新模块,请使用 git add 命令在当前目录中暂存更改,然后使用 git commit 命令将这些更改提交到本地存储库:

git add .
git commit -m "Initial private module implementation"

您将看到来自 Git 的确认您的初始提交已成功以及提交中包含的文件的摘要:

Output[main (root-commit) bda059d] Initial private module implementation
 2 files changed, 10 insertions(+)
 create mode 100644 go.mod
 create mode 100644 mysecret.go

现在剩下的唯一部分是将您的更改移动到您的 GitHub 存储库。 与公共模块类似,使用 git push 命令发布您的代码:

git push

然后,Git 将推送您的更改,并使任何有权访问您的私有存储库的人都可以使用它们:

git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 404 bytes | 404.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:your_github_username/mysecret.git
 * [new branch]      main -> main

与公共 Go 模块一样,您也可以向私有 Go 模块添加版本。 如何分发 Go 模块 教程的 发布新模块版本 部分包含有关如何执行此操作的信息。

在本节中,您创建了一个具有 SecretProcess 函数的新模块并将其发布到您的私有 mysecret GitHub 存储库,使其成为私有 Go 模块。 但是,为了从另一个 Go 程序访问此模块,您需要配置 Go,以便它知道如何访问该模块。

配置转到访问私有模块

虽然 Go 模块通常从其源代码存储库中分发,但 Go 团队还运行一些 中央 Go 模块服务 以帮助确保在原始存储库发生问题时模块继续存在。 默认情况下,Go 配置为使用这些服务,但是当您尝试下载私有模块时,它们可能会导致问题,因为它们无权访问这些模块。 要告诉 Go 某些导入路径是私有的并且它不应该尝试使用中央 Go 服务,您可以使用 GOPRIVATE 环境变量。 GOPRIVATE 环境变量是导入路径前缀的逗号分隔列表,当遇到时,Go 工具将尝试直接访问它们,而不是通过中央服务。 一个这样的例子就是您刚刚创建的私有模块。

为了使用私有模块,您将通过在 GOPRIVATE 变量中设置它来告诉 Go 将哪个路径视为私有。 在设置 GOPRIVATE 变量值时,您可以做出一些选择。 一种选择是将 GOPRIVATE 设置为 github.com。 不过,这可能不是您想要的,因为这会告诉 Go 不要将中央服务用于 github.com 上托管的任何模块,包括不属于您的模块。

下一个选项是将 GOPRIVATE 设置为仅您自己的用户路径,例如 github.com/your_github_username。 这解决了将所有 GitHub 视为私有的问题,但在某些时候,您可能会创建想要通过 Go 模块镜像下载的公共模块。 这样做不会导致任何问题,并且是一个完全合理的选择,但您也可以选择更具体。

最具体的选项是设置 GOPRIVATE 以完全匹配模块的路径,例如:github.com/your_github_username/mysecret。 这解决了前面选项中的两个问题,但也引入了您需要将每个私有存储库单独添加到 GOPRIVATE 的问题,如下所示:

GOPRIVATE=github.com/your_github_username/mysecret,github.com/your_github_username/othersecret

为自己选择最佳选择是权衡您所处情况的利弊。

由于您现在只有一个私有模块,因此我们将使用完整的存储库名称作为值。 要在当前终端中设置 GOPRIVATE=github.com/your_github_username/mysecret 环境变量,请使用导出命令:

export GOPRIVATE=github.com/your_github_username/mysecret

如果您想仔细检查它是否已设置,您可以使用 env 命令和 grep 来检查 GOPRIVATE 名称:

env | grep GOPRIVATE
OutputGOPRIVATE=github.com/your_github_username/mysecret

即使 Go 现在知道您的模块是私有的,但仍然不足以使用该模块。 如果您尝试将您的私有模块 go get 放入另一个模块,您可能会看到类似于以下内容的错误:

go get github.com/your_github_username/mysecret
Outputgo get: module github.com/your_github_username/mysecret: git ls-remote -q origin in /Users/your_github_username/go/pkg/mod/cache/vcs/2f8c...b9ea: exit status 128:
    fatal: could not read Username for 'https://github.com': terminal prompts disabled
Confirm the import path was entered correctly.
If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.

此错误消息显示 Go 尝试下载您的模块,但遇到了仍然无法访问的内容。 由于使用 Git 下载模块,它通常会要求您输入凭据。 但是,在这种情况下,Go 正在为您调用 Git,并且无法提示它们。 此时,要访问您的模块,您需要为 Git 提供一种无需您立即输入即可检索您的凭据的方法。

为 HTTPS 提供私有模块凭证

告诉 Git 如何代表您登录的一种方法是 .netrc 文件。 .netrc 文件位于用户的主目录中,包含各种主机名以及这些主机的登录凭据。 它被许多工具广泛使用,包括 Git。

默认情况下,当 go get 尝试下载模块时,它会先尝试使用 HTTPS。 但是,如前面的示例所示,它无法提示您输入用户名和密码。 要向 Git 提供您的凭据,您需要在您的主目录中有一个 .netrc,其中包含 github.com

要在 Linux、MacOS 或适用于 Linux (WSL) 的 Windows 子系统上创建 .netrc 文件,请打开主目录 (~/) 中的 .netrc 文件,以便对其进行编辑:

nano ~/.netrc

接下来,在文件中创建一个新条目。 machine 值应该是您为其设置凭据的主机名,在本例中为 github.comlogin 值应该是你的 GitHub 用户名。 最后,password 值应该是您创建的 GitHub 个人访问令牌

~/.netrc

machine github.com
login your_github_username
password your_github_access_token

如果您愿意,也可以将整个条目放在文件的一行中:

~/.netrc

machine github.com login your_github_username password your_github_access_token

注意: 如果您使用 Bitbucket 作为源代码托管,除了 bitbucket.org 之外,您可能还需要为 api.bitbucket.org 添加第二个条目。 过去,Bitbucket 为多种类型的版本控制提供托管,因此 Go 在尝试下载之前会使用 API 检查存储库的类型。 虽然不再是这种情况,但 API 检查仍然存在。 如果您遇到此问题,示例错误消息可能如下所示:

go get bitbucket.org/your_github_username/mysecret: reading https://api.bitbucket.org/2.0/repositories/your_bitbucket_username/protocol?fields=scm: 403 Forbidden
    server response: Access denied. You must have write or admin access.

如果您在尝试下载私有模块时看到 403 Forbidden 错误,请仔细检查 Go 尝试连接的主机名。 它可以指示您需要添加到 .netrc 文件中的另一个主机名,例如 api.bitbucket.org


现在您的环境已设置为使用 HTTPS 身份验证来下载您的私有模块。 尽管 HTTPS 是 Go 和 Git 会尝试下载模块的默认方式,但也可以告诉 Git 使用 SSH 代替。 使用 SSH 而不是 HTTPS 可能很有用,因此您可以使用与推送私有模块相同的 SSH 密钥。 如果您不想创建个人访问令牌,它还允许您在设置 CI/CD 环境时使用 部署密钥

为 SSH 提供私有模块凭证

为了使用 SSH 密钥而不是 HTTPS 作为私有 Go 模块的身份验证方法,Git 提供了一个名为 insteadOf 的配置选项。 insteadOf 选项允许您说“而不是”使用 https://github.com/ 作为所有 Git 请求的请求 URL,您更愿意使用 ssh://git@github.com/

在 Linux、MacOS 和 WSL 上,此配置位于 .gitconfig 文件中。 您可能已经熟悉此文件,因为它也是您配置提交电子邮件地址和名称的地方。 要编辑文件,请使用 nano 或您喜欢的文本编辑器,然后在您的主目录中打开 ~/.gitconfig 文件:

nano ~/.gitconfig

打开文件后,编辑它以包含 ssh://git@github.com/url 部分,如下例所示:

~/.gitconfig

[user]
    email = your_github_username@example.com
    name = Sammy the Shark
    
[url "ssh://git@github.com/"]
    insteadOf = https://github.com/

url 部分相对于 user 部分的顺序无关紧要,如果文件中除了 [X173X 之外没有其他内容,您也不必担心] 您刚刚添加的部分。 user 部分中 emailname 字段的顺序也无关紧要。

这个新部分告诉 Git 你使用的任何以 https://github.com/ 开头的 URL 都应该用 ssh://git@github.com/ 替换前缀。 由于 Go 默认使用 HTTPS,这也会影响您的 go get 命令。 以您的私有模块为例,这意味着 Go 将 github.com/your_github_username/mysecret 导入路径转换为 URL https://github.com/your_github_username/mysecret。 当 Git 遇到这个 URL 时,它会看到 URL 与 insteadOf 引用的 https://github.com/ 前缀匹配,并将生成的 URL 转换为 ssh://git@github.com/your_github_username/mysecret

只要 ssh://git@ URL 也适用于该主机,同样的模式可以用于 GitHub 以外的域。

在本节中,您通过更新 .gitconfig 文件并添加 url 部分将 Git 配置为使用 SSH 下载 Go 模块。 现在您的私有模块的身份验证已设置,您可以访问它以在您的 Go 程序中使用。

使用私有模块

在前面的部分中,您将 Go 配置为通过 HTTPS、SSH 或两者都访问您的私有 Go 模块。 现在 Go 可以访问您的私有模块,它可以像您过去使用的任何公共模块一样使用。 在本节中,您将创建一个使用您的私有模块的新 Go 模块。

在您用于项目的目录中,例如 projects,使用 mkdir 命令为新项目创建一个名为 myproject 的目录:

mkdir myproject

创建目录后,使用 cd 转到目录并使用 go mod init 根据项目所在的存储库 URL 为您的项目初始化一个新的 Go 模块,例如 [ X199X]。 如果您不打算将您的项目推送到任何其他存储库,则模块名称可能只是 myproject 或任何其他名称,但最好使用完整的 URL,因为大多数共享的模块都需要它们.

cd myproject
go mod init github.com/your_github_username/myproject
Outputgo: creating new go.mod: module github.com/your_github_username/myproject

现在,通过使用 nano 或您喜欢的文本编辑器打开 main.go 来创建项目的第一个代码文件:

nano main.go

在文件中,设置初始的 main 函数,您将从以下位置调用您的私有模块:

项目/myproject/main.go

package main

import "fmt"

func main() {
    fmt.Println("My new project!")
}

要立即运行您的项目并确保一切设置正确,您可以使用 go run 命令并为其提供 main.go 文件:

go run main.go
OutputMy new project!

接下来,使用 go get 将您的私有模块添加为新项目的依赖项,类似于您对公共模块的操作:

go get github.com/your_github_username/mysecret

然后 go 工具将下载您的私有模块的代码,并使用与您的最新提交哈希和该提交时间匹配的版本字符串将其添加为依赖项:

Outputgo: downloading github.com/your_github_username/mysecret v0.0.0-20210920195630-bda059d63fa2
go get: added github.com/your_github_username/mysecret v0.0.0-20210920195630-bda059d63fa2

最后,再次打开 main.go 文件并更新它以在 main 函数中添加对私有模块的 SecretProcess 函数的调用。 您还需要更新 import 语句以将 github.com/your_github_username/mysecret 私有模块也添加为导入:

项目/myproject/main.go

package main

import (
    "fmt"

    "github.com/your_github_username/mysecret"
)

func main() {
    fmt.Println("My new project!")
    mysecret.SecretProcess()
}

要查看使用您的私有模块运行的最终项目,请再次使用 go run 命令,同时提供 main.go 文件作为参数:

go run main.go

您将从原始代码中看到 My new project! 行,但现在您还会从导入的 mysecret 模块中看到 Running the secret process! 行:

OutputMy new project!
Running the secret process!

在本节中,您使用 go init 创建了一个新的 Go 模块来访问您之前发布的私有模块。 创建模块后,您可以使用 go get 下载您的私有模块,就像使用公共 Go 模块一样。 最后,您使用 go run 使用私有模块编译和运行您的 Go 程序。

结论

在本教程中,您创建并发布了一个私有 Go 模块。 您还设置了 HTTPS 和 SSH 身份验证来访问您的私有 Go 模块。 最后,您在一个新项目中使用了您的私有模块。

有关 Go 模块的更多信息,Go 项目有 一系列博客文章 详细介绍了 Go 工具如何与模块交互和理解模块。 Go 项目在 Go 模块参考 中也有关于 Go 模块的非常详细的技术参考。

除了 GOPRIVATE 环境变量之外,在使用私有 Go 模块时还可以使用更多变量。 它们可以在 Go 模块参考Private Modules 部分详细查看。

如果您有兴趣更详细地探索 .netrc 文件,.netrc 上的 GNU 网站包含所有可用关键字的列表。 git-config 文档 还包含有关您使用的 insteadOf 配置选项以及其他可用选项如何工作的更多信息。

本教程也是 DigitalOcean How to Code in Go 系列的一部分。 该系列涵盖了许多 Go 主题,从第一次安装 Go 到如何使用语言本身。