TL;DR
Dockerコンテナ
x module aware mode
x プライベートリポジトリ
の組み合わせで go get
できないことにお困りの場合は、 gitconfig
書き換えや ssh agent forwarding
などをしなくても、 GOPROXY
を使うとモジュール利用者が何も設定することなくコンテナ内で go get
できるようになるよという話
1. はじめに
弊社では長らくGoのモジュール管理に glide を使っていましたが、Go Modules
が Go1.13
で正式にサポートされることもあり乗り換えようとしました。
社内には多くの内製ライブラリがあり、それらをプライベートリポジトリで管理していました。 glide
で管理していた際は、 glide.yaml
に以下のように x-oauth-basic
をつけて対応していました。
- package: github.com/knocknote/private_repo
repo: https://${basic_auth_token}:x-oauth-basic@github.com/knocknote/private_repo.git
また、開発にはDockerを利用しており、Goの実行環境は Dockerコンテナ上にあります。
これらの前提の上で、Go1.12
x GO111MODULE=on
な環境に移行することが目的です。
しかし、 go get
はプライベートリポジトリに対応していないため、普通にやると gitconfig
をいじって x-oauth-basic
をつけてアクセスするようにしたり、 go get
を利用するときに内部的に SSH
でアクセスできるように変更する必要があります。
ですが、モジュールの依存解決をしたいがためにこれらの設定をチームメンバ全員に強いるのも嫌ですし、何も設定することなく Docker
コンテナ内で go get
できるようにしたいところです。
そこで、GOPROXY
に目をつけました。 GOPROXY=http://localhost:6000
な具合に GOPROXY
を設定しておくと、 go get
する際に http://localhost:6000
を通してモジュールをダウンロードしにいくような挙動になります。これによって、例えば http://localhost:6000
で立ち上げているサーバーからモジュールを取得しに行くときには必ず x-oauth-basic
でトークンをつけてアクセスしにいくみたいなことができるようになる可能性があります。
今回、この GOPROXY
を利用した方法でやりたいことが実現できたため、そのアプローチの紹介をしたいと思います。
また、前段として今まで似たようなことをしたいときに利用したであろう解決パターンについても触れたいと思います。
2. よくある(と思っている)解決方法
2.1 gitconfig 書き換えパターン
2.1.1 gitconfig 書き換えで x-oauth-basic
を常につけるようにする
git config --global url."https://${token}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
2.1.2 gitconfig 書き換えで https
でアクセスする代わりに SSH を利用する
.gitconfig
に以下を記述
[url "git@github.com:"]
insteadOf = https://github.com/
2.2 あらかじめ git clone パターン
はじめからプライベートリポジトリを git clone
しておいて、それらを git-submodule
なりで紐づけておくようなやり方です。
弊社では glide
でモジュール管理をしていた際、バージョン固定などの観点から vendor
配下をバージョン管理するようにし、プライベートリポジトリもそこに含めていました。また、vendor
を submodule
としてアプリケーションコードのリポジトリにマウントしておき、ライブラリを利用する側としては git submodule update
してやれば簡単に更新できる状態で運用していました。
module aware mode
では vendor
廃止の方向に動いているため、この方法をとりずらくなっていますが、
例えば go.mod
の replace
directive に
replace (
github.com/knocknote/private_repo => ./vendor/github.com/knocknote/private_repo
)
と書けば同様のことができます。
3. GOPROXY を使ったやり方
GOPROXY
を利用する場合に便利なプロジェクトとして goproxyio/goproxy があります。これはまさにやりたいことそのままで、 go get
をプロキシできるようになるのですが、プライベートリポジトリには対応していません。
そこで、 簡単なパッチを当てたバージョンを knocknote/goproxy に作成しました。やっていることは -basicAuthToken
オプションを足して、指定されている場合は goproxy
内部で(というよりかは modfetch
の内部で) git ls-remote https://github.com/knocknote/private-repo
を実行するときに、 git ls-remote https://${basic_auth_token}:x-oauth-basic@github.com/knocknote/private-repo
を代わりに行うようにするというものです。
こちらは ビルド済みのものを DockerHub で公開しているため ( https://hub.docker.com/r/knocknote/goproxy )、以下のように docker-compose.yml
に書くだけでプライベートリポジトリが取得できるようになるはずです。
services:
module_proxy:
image: knocknote/goproxy:latest
ports:
- "8002:8002"
entrypoint: /goproxy -cacheDir=/go -basicAuthToken=xxxxx -listen=0.0.0.0:8002
app:
environment:
GO111MODULE: "on"
GOPROXY: "http://module_proxy:8002"
(略)
この設定を一度書いてしまえば、使う側としては何も設定することなく、プライベートリポジトリだとしても go get
でとってくることができます! :)
4. まとめ
GOPROXY
を使ったプライベートリポジトリの取得方法を紹介してみました。同じような悩みをかかえていた方の参考になれば嬉しいです。まだ昨日今日でガッと作った仕組みですが、Go Modules
に移行できる兆しが見えてきた気がします。
また、もっと良い方法でやっているよとか、これだとこのケースに対応するのがしんどいのでこうしたほうが良いといった情報があれば教えていただけると嬉しいです!