跳转到主要内容

介绍


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

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

先决条件

 

  • 安装 1.16 或更高版本。要进行设置,请按照您的操作系统的如何安装 Go 教程进行操作。
  • 对分发 Go 模块的理解,您可以在如何分发 Go 模块教程中找到。
  • 熟悉 Git,您可以通过遵循如何使用 Git:参考指南获得。
  • 一个名为 mysecret 的空私有 GitHub 存储库,用于您已发布的私有模块。要开始使用,请按照 GitHub 文档创建存储库。
  • 一个 GitHub 个人访问令牌,可以从您的存储库中读取。您将使用它来允许 Go 访问您的私有存储库。


分发私有模块


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

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

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

创建项目目录并导航到它:

mkdir projects
cd projects


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

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


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

Output
Cloning 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 函数以打印运行秘密进程行!调用时:

projects/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 某些导入路径是私有的并且它不应该尝试使用中央 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

Output
GOPRIVATE=github.com/your_github_username/mysecret


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

go get github.com/your_github_username/mysecret

Output
go 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 提供您的凭据,您需要在您的主目录中拥有一个包含 github.com 的 .netrc。

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

nano ~/.netrc


接下来,在文件中创建一个新条目。机器值应该是您为其设置凭据的主机名,在本例中为 github.com。登录值应该是您的 GitHub 用户名。最后,密码值应该是您创建的 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 部分的顺序无关紧要,如果文件中除了您刚刚添加的 url 部分之外没有其他内容,您也不必担心。用户部分内的电子邮件和姓名字段的顺序也无关紧要。

这个新部分告诉 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 以外的域。

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

使用私有模块


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

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

mkdir myproject


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

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

Output
go: creating new go.mod: module github.com/your_github_username/myproject


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

nano main.go


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

projects/myproject/main.go

package main

import "fmt"

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

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

go run main.go



Output

My new project!


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

go get github.com/your_github_username/mysecret


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

Output
go: 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 函数的调用。您还需要更新导入语句以将您的 github.com/your_github_username/mysecret 私有模块也添加为导入:

projects/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


您将看到我的新项目!原始代码中的行,但现在您还会看到运行秘密过程!来自您导入的 mysecret 模块的行:

Output
My new project!
Running the secret process!


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

结论


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

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

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

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

文章链接