为 Docker 和 CI 加速 Go 模块
最后,Golang 世界在生态系统中内置了一个传统的依赖管理器:Go Modules。 Go 1.11 开始作为选择加入功能已被社区广泛采用,当 Go Modules 将默认启用时,我们非常接近 Go 1.13。最终可以解决选择“最佳”工具这一令人愉快的困境。 我不得不提到两个非常贴近我心的功能: 没有更多的$GOPATH监禁!在我多年的经验中,我习惯于将我在~/Projects/中工作的所有内容
最后,Golang 世界在生态系统中内置了一个传统的依赖管理器:Go Modules。 Go 1.11 开始作为选择加入功能已被社区广泛采用,当 Go Modules 将默认启用时,我们非常接近 Go 1.13。最终可以解决选择“最佳”工具这一令人愉快的困境。
我不得不提到两个非常贴近我心的功能:
-
没有更多的
$GOPATH
监禁!在我多年的经验中,我习惯于将我在~/Projects/
中工作的所有内容及其子文件夹存储在主目录的某个位置,无论是哪种编程语言。所以,被迫将我的 Golang 东西放在另一个特定的地方并尊重路径中的 SCM url 是一种真正的痛苦,并且让例行的cd
操作感觉像是一件苦差事。不再是问题! -
没有更多的供应商!依赖更新不会产生巨大的 PR 差异来读取,并且存储库更轻。我可以从我的源代码中删除
vendor
文件夹并忘记它。
迁移到 Go Modules 是非常简单的并且不会超过几分钟,特别是如果您使用任何受支持的包管理器进行迁移。
$ go mod init
$ rm vendor/*
$ go test ./...
$ git add .
$ git commit
差不多就是这样!
使用 Go 模块,您的依赖项不再是源代码的一部分。工具链自行下载它们,使模块保持最新,并将它们缓存在本地$GOPATH/pkg/mod
中以供将来使用。当您的所有进程都发生在像笔记本电脑这样的有状态环境中时,这听起来很完美,但是 CI 管道或 Docker 中的无状态构建呢? Go 会时不时地下载依赖项中的每个项目并浪费您宝贵的时间。让我们通过一些缓存来解决这个问题!
在 CI 上缓存
在 CI 上缓存构建之间的依赖关系是一种常见的情况,以至于一些服务提供了一种简化的、特定于生态系统的语法来使其更容易。唉,我还没有在流行的 CI 上找到特定的 Go Modules 缓存,所以让我们手动完成。
如果您使用 TravisCI,则非常简单。只需将这些行添加到您的.travis.yml
配置中即可:
cache:
directories:
- $GOPATH/pkg/mod
在我最喜欢的 CircleCI 上设置依赖缓存有点冗长。在下面的代码中包装go mod download
或您的构建步骤。 Golang 将处理丢失的依赖项,CircleCI 将根据go.sum
文件的内容在构建之间缓存它们。
- restore_cache:
keys:
- go-modules-v1-{{ checksum "go.sum" }}
- go-modules-v1
# get dependencies here with `go mod download` or implicitly
# with `go build` or `go test`
- save_cache:
key: go-modules-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
以下是我在 CircleCI 上的小项目提升的结果:
前:
`go test ./...` => 00:20s
缓存预热后:
Restoring Cache => 00:03s
`go test ./...` => 00:06s
Saving Cache => 00:00s
一点也不差:CI 构建速度提高 2 倍,而且是免费的。
在 Docker 中缓存
我们如何使用 Docker 有两个完全不同的用例:用于隔离应用程序及其环境的开发过程,以及用于打包生产构建。
开发中
如果您遵循测试驱动开发 (TDD) 缓存,Go Modules 可以显着提高您的开发效率。您肯定知道拥有尽可能快的测试套件是多么重要。
使用 Docker Compose,将您的模块缓存在单独的卷中,并查看性能提升。我节省了 20 秒。对于一个小小的改变来说还不错!
这是一个最小的docker-compose.yml
,为简洁起见进行了简化,突出显示了卷的变化:
version: '3'
services:
app:
image: application:0.0.1-development
build:
context: .
dockerfile: docker/development/Dockerfile
volumes:
- .:/app
- go-modules:/go/pkg/mod # Put modules cache into a separate volume
runner:
<<: *app
test:
<<: *app
command: go test ./...
volumes:
go-modules: # Define the volume
生产中
对于生产构建,我们可以利用层缓存的力量。依赖关系的变化比代码本身的变化少——让我们在构建阶段之前将其作为Dockerfile
中的一个单独步骤。
# `FROM` and other prerequisites here skipped for the sake of brevity
# Copy `go.mod` for definitions and `go.sum` to invalidate the next layer
# in case of a change in the dependencies
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# `RUN go build ...` and further steps
简而言之
引入 Go Modules 是一个激动人心的时刻,对 Golang 社区来说是一种重大的解脱。它为我们带来了许多我们期待已久的优秀功能。如果您还没有尝试过 Modules,请不要犹豫。迁移到它非常容易,但不要忘记更改 CI 或 Docker 设置以避免下载开销并保持构建快速。
更多推荐
所有评论(0)