最后,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 设置以避免下载开销并保持构建快速。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐