概要
Go 1.13から、goコマンドはデフォルトでGo Module MirrorとChecksum Databaseを使用してモジュールをダウンロード&認証するようになりました。
環境
- go 1.14.1
Module Mirror (Module Proxy)
Module Mirrorは公開モジュールをキャッシュし、go modでのダウンロードを高速化するためのProxyです。
ProxyのURLはGOPROXY
にセットされています。
$ go env GOPROXY https://proxy.golang.org,direct
メリット
大きく以下のメリットがあります。
ダウンロードの高速化
1つ目は実際に検証すると分かりますが、proxyを経由しない場合はVCS特有(プロトコル、履歴管理など)のオーバーヘッドの影響を受けるので遅くなります。
proxy使わないダウンロード
git@github.com:hashicorp/vault.git
のリポジトリで検証してみます。
まずはproxyを使わない方。
$ time GO111MODULE=on GOPROXY=direct go mod download real 2m37.808s user 1m55.232s sys 0m37.981s
proxy使ったダウンロード
go clean -modcache
でmoduleを消してから今度はproxy経由(デフォルト)でダウンロードしてみます。
$ time GO111MODULE=on go mod download real 0m51.068s user 0m27.813s sys 0m22.059s
3倍以上速くなってますね。
低速な環境だと7倍速くなったということもあるようです。
Awesome! In our tests, we saw 3x speedups on fast networks and 6x on slow networks. 7x is a new record!
— Sameer Ajmani (@Sajma) 2019年7月27日
vendorディレクトリを消せるようになった
個人的には3つ目が嬉しくて、これまでだと依存ライブラリが気づいたら消えていて困ることが何度かありました。
そのためバージョン管理にvendor
ディレクトリを含ませるというプラクティスを取っていました。
しかし自分たちのコード以外に大量のファイルが追加されるため、以下のような問題が頭を悩ませていました。
- PRが見にくい
- レビューのため開くのも重い
- コミットを分けたりしたがそうすると
Viewed
など一部機能が使えない
- 検索でノイズが大量に出る
- git cloneが遅い
- CIではdepthを変更しておかないとどんどん遅くなる
また
といった問題もありました。
Module Mirrorの登場でこういったデメリットのあるvendor
ディレクトリ削除できるようになりました。
注意点
Module Mirrorを使う上で以下の点に注意して下さい。
これはPrivateリポジトリのデータが漏れないという意味で嬉しいですが、開発する際はそのままだとエラーになってしまいます。
対応策としては以下の2つがあります。
- GOPRIVATEでPrivateリポジトリをModule Mirrorの対象外とする
- 自前のProxyを用意する
GOPRIVATE
にPrivateリポを指定
GOPRIVATE
という環境変数を利用します。
GOPRIVATE
はglobパターンで記述します。また複数ある場合はカンマで区切ります。
例えば以下のように設定した場合
GOPRIVATE=*.corp.example.com,rsc.io/private
git.corp.example.com/xyzzy
rsc.io/private
rsc.io/private/quux
といったリポジトリが対象になります。
path prefixマッチングが効くので、後ろにワイルドカード*
をつける必要はありません。
自前のProxyを用意する
GOPROXY
は自分でProxyを設定できるので、Privateリポジトリ対応したProxyを自前で用意する、という対応です。
以下の記事が参考になります。
Go Modulesに対応しつつ、Dockerコンテナの中でプライベートリポジトリを go get する - Qiita
.gitconfig
をいじらないといけなくてつらい、、といったケースで有用だと思います。
Checksum Database
go.mod
はバージョンのロックに使われますが、そこで固定したバージョンはあとからダウンロードした時に同一とは限りません。
- タグ
v1.0.1
付けてをリリースする - バージョン
v1.0.1
を指定したロックファイルを作る - 悪意ある人物がタグ
v1.0.1
削除、不正なコードを埋め込み、新たにタグv1.0.1
を作成 - ロックファイルから
v1.0.1
をダウンロードすると悪意あるコードになっている
といった感じで、タグ自体は一貫性を保証できません。
そこでgo.sum
というChecksumを用いた検証をしていますが、初めてgo.sumを作成した時は各モジュールのChecksumを持っていないので検証できないという課題がありました。
そこでGoチームは sum.golang.org
というグローバルな追記型のChecksumデータベースを用意して
$ go env GOSUMDB sum.golang.org
go getした際にこのデータベースのChecksumと比較し、検証するという対応を行いました。
メリット
このChecksumデータベースによるメリットは以下です。
- モジュールの一貫性を保証できる
- 信頼性のないProxyを経由しても問題ない
- 追記型なので改竄されない
注意点
Checksumデータベースを使う上で以下の点に注意して下さい。
- バージョンの付け替えをするとエラーになる
- Privateリポジトリは保存されない
バージョンの付け替えをするとエラー
先に述べたようにChecksumデータベースは追記型であり、既存データの変更はできません。
つまり一度 sum.golang.org に登録されると取り消すことができないので、手動でタグを変更してしまったりするとChecksumの値が異なるようになり、以下のエラーが発生するようになります。
SECURITY ERROR This download does NOT match the one reported by the checksum server. The bits may have been replaced on the origin server, or an attacker may have intercepted the download attempt.
Privateリポジトリ
PrivateリポジトリはChecksumデータベースに記録されません。
そのため、普通にgo get
しようとするとChecksumデータベースの検証が走り404 NotFound
か410 Gone
がレスポンスとして返ります。
Module Mirrorと同様にGOPRIVATE
を指定することでChecksumデータベースによる検証の対象外とすることができます。
まとめ
Module MirrorによるProxyのおかげで
- ダウンロードの高速化
- オリジンが消えてもビルド可能
となり、Checksumデータベースにより
- コードの真正性を保証
できるようになりました。
Privateリポジトリはこの仕組みから外れるため、GOPRIVATE
で対象外にするようにしましょう。