はじめに
Go modules
はGo1.13(August 2019)から正式に導入されたGo言語公式の依存パッケージ管理ツールです。Go modules
以前は、dep
が依存パッケージ管理のツールとしてはデファクトでした。Go modules
はGo1.11から使用は可能でしたが、環境変数(ENV GO111MODULE=on)を設定したり色々と手間がかかる事前準備が必要でした。Go1.13からはデフォルトでGo modules
が組み込まれています。
そもそもGo Modulesとは何?
Goの新しい依存管理システムである。
モジュールは、一つのユニットとしてバージョン管理されている関連Goパッケージの集まり。1.11からはmoduleモードとGOPATHモードが使えるようになっていましたが、1.13からはmoduleモードがデフォルトでONになっています。Goのオープンソースモジュールのエコシステムをより良く活用できるように、moduleモードがデフォルトで動作するようにしているそうです。
Golang.org: modules
Golang.org: Wiki-Modules
モジュールとは
モジュール対応モードでは,標準ライブラリを除くパッケージを「モジュール(module)」として管理する。 パッケージが git 等のバージョン管理ツールで管理されている場合はバージョン毎に異なるモジュールと見なされる。 つまりモジュールの実体は「パッケージ+バージョン」ということになる。
ただしコード上ではパッケージとモジュールの間に区別はなく,したがってソースコードを書き換える必要はない。 モジュールはソースコードではなくgo.mod
ファイルで管理される。
depとGo Modulesの機能差マトリクス
項目 | dep | go modules | |
---|---|---|---|
実行する場所 |
GOPATH 以下である必要がある |
*Goプログラムのルートディレクトリ *GOPATH以下にあるソースコードでも go.mod ファイルがあればモジュール対応モードで管理が可能 |
|
管理ファイル |
Gopkg.toml ・Gopkg.lock
|
go.mod ・go.sum
|
|
Vendoring | depがvendoring対応のツール |
go mod vendor というコマンドでvendoring対応ができる |
dockerの場合はvendoring利用がおすすめ |
Gitでの管理 |
Gopkg.toml とGopkg.lock をGit管理する |
通常は、go.mod とgo.sum は共にGit管理する |
|
パッケージ管理 | リポジトリの最新リビジョンのみが対象 | リポジトリのバージョンタグまたはリビジョン毎に管理。Semantic Versioningに対応 | Semantic Versioningとは、vX.X.Xというようなバージョン番号の定義方法 |
依存packageの場所 | $GOPATH/src以下プログラムルートのvendorディレクトリ | $GOPATH/pkg/mod以下 | *go modで取得したバイナリなどは$GOPATH/pkg/mod/以下にキャッシュされている *CIの高速化でビルドキャッシュをするときはこのディレクトリをキャッシュする必要がある *キャッシュを削除するときはgo clean -cacheコマンドで削除 *go mod vendorコマンドでdepのようにvendorディレクトリに依存関係を保存することができる *go mod tidyでgo.modから不要な依存関係を削除 |
パッケージ管理で、GOPATHの依存がなくなる点くらいで双方の機能差はほぼ無し。
「$GOPATHの呪縛からの解放」という最大のメリットで、何よりも代えがたいポイントのように思えます。
GOPATHモード(GOPATH mode)とモジュールモード(module-aware mode)
バージョン1.11以降からは、Go言語コンパイラは以下の2つのモードのどちらかで動作するようになっていました。
モード | |
---|---|
GOPATHモード | バージョン 1.10 までの動作モード。標準ライブラリを除く全てのパッケージの管理とビルドを $GOPATH 以下のディレクトリで行う。パッケージの管理はリポジトリの最新リビジョンのみが対象となる |
モジュール対応モード | 標準ライブラリを除く全てのパッケージをモジュールとして管理する。モジュールの管理とビルドは任意のディレクトリで可能で,モジュールはリポジトリのバージョンタグまたはリビジョン毎に管理される |
環境変数 $GO111MODULE
モード切替は$GO111MODULE
という環境変数で切り替えます。1.12でもauto
が規定値になっている。 1.13でも引き続きauto
になっていますが、現在の作業ディレクトリにgo.modファイルが含まれる場合は、goコマンドのモジュール対応モード
がアクティブになります。
リリースノート:1.13
設定値
設定値 | |
---|---|
auto | $GOPATH 以下のディレクトリにあるパッケージは GOPATH モードで,それ以外はモジュール対応モードで動作する |
off | 常に GOPATH モードで動作する |
on | 常にモジュール対応モードで動作する |
depからの移行
プロジェクトルートのGopkg.lock
ファイルを自動に読み込んで、moduleの初期設定を行ってくれる設計になっています。(depから移行するこが前提になっていますね )
Migrating to Go Modules などが参考になると思います。
- 既存のパッケージに go.mod ファイルを追加する
- Gopkg.lock ファイルを読んで go.mod ファイルに組み込んでくれる
$ go mod init github.com/my-repo/nice-project
go: creating new go.mod: module github.com/my-repo/nice-project
go: copying requirements from Gopkg.lock
*もちろん、まっさらな状態からgo module
で初期化と依存パッケージのダウンロードを最初から行ってもいいです。
補足:Dockerでの設定
dockerで開発している場合は、ビルド前に依存パッケージをダウンロード・インストールする必要があります。ポイントだけをピックアップしたDockerfileのイメージです。
# Goのバージョンは1.13以上
FROM golang:1.13-alpine as golang-build
# Goビルドに必要なアプリケーションをインストールする
RUN .....
WORKDIR /go/src/github.com/my-repo/nice-project
# go moduleで依存パッケージを取得してダウンロードする
# ローカルの、go.modとgo.sumをコピー
COPY go.mod go.sum ./
# 依存ライブラリをダウンロードする
RUN go mod download
# Goアプリケーションのビルド
ADD . /go/src/github.com/my-repo/nice-project
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build main.go
ビルド前に、go moduleを使って依存ライブラリ・モジュールをダウンロードしておきます。
とても少ない記述量で実現できてしまいます。
まとめ
depを使っているときはは、CIのビルドの時間を短縮のためにdep ensure -vendor-only=true
として新しいパッケージを追加する際に、Gopkg.lockとGopkg.tomlを更新していたり手間がかかっていました。modules
でキャッシュディレクトリを設定しておけば、ビルド時間も短縮できるためトリッキーなファイルの運用がなくなりました。1.13がリリースされて4ヶ月位経ちますが、dep
で苦労していたり、切替をお考えの方がいれば、modules
への移行の参考になれば幸いです。