如何在你自己的项目中使用私有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.com
。 login
值应该是你的 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
部分中 email
和 name
字段的顺序也无关紧要。
这个新部分告诉 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 到如何使用语言本身。