目的
- バージョンが勝手に変わると、アプリケーション動作の保障ができないので、任意のバージョンのgoをインスコして使う
対象環境
- ビルド環境 (CircleCI)
- 実行環境 (AWS EC2)
今回ビルド環境と実行環境を分ける予定であるため、その両方への作業が必要ですが、今回は、ひとつめの、CircleCIでの適用作業をします。
利用するライブラリ
gvm: https://github.com/moovweb/gvm
gvm使ってみる
gvmはgolangのバージョン管理ライブラリです。
あまり気に入ってないけど、他にいいやつあったらおしえてほしいです。
自分のローカルで先にやっても良かったのですが、まだVM環境になってないので、CicleCIのコンテナでためしました。
CircleCIはデバッグ用途で、30min限定でコンテナにsshできます。
ぶっ壊れてもいいので、今回の作業以外でも色々遊ぶといいです。
現在使っているシェルを確認
$ echo $SHELL
/bin/bash
現在使っているgoのバージョンを確認
$ go version
go version go1.6.2 linux/amd64
gvmをインストール
$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
Cloning from https://github.com/moovweb/gvm.git to /home/ubuntu/.gvm
Created profile for existing install of Go at "/usr/local/go"
Installed GVM v1.0.22
Please restart your terminal session or to get started right away run
source /home/ubuntu/.gvm/scripts/gvm
上記出力の通り、以下を読み込んであげましょう。
source /home/ubuntu/.gvm/scripts/gvm
インストールgo一覧の確認
$ gvm list
gvm gos (installed)
system
現状システムインストールされたgoだけが表示されています。CircleCIで使われてるイメージはデフォルトでgo入ってるので。すなわちsystemですね。
gvmで任意のバージョンのgoインストール
gvm install go1.4 -B
Installing go1.4 from binary source
ちゃんと入ったようなので、先ほどインストールしたバージョンを使います
gvm use go1.4
Now using version go1.4
--default
オプションをつけることもできます。たぶん基本的につけてつかうことになるでしょう。
goのバージョン確認
go version
go version go1.4 linux/amd64
ちゃんと1.4に変わってます。
元に戻す
gvm use system
ちなみにgvm経由でインストール可能なgoのバージョンの一覧は以下で得ることができます
gvm listall
バルスコマンド。インストールしたバイナリなどに加え、gvm自身も消え去ります。
けっきょく、${HOME}/.gvm
(= ${GVM_ROOT}
) をrm -rf
すればおなじことです。
gvm implode
さて。もともと、やりたかったことは、CircleCIのビルド時のバージョン固定なので、これをcircle.yml
に落とし込みます。
CircleCIで任意のバージョンのgo使ってビルドする
Since the install is in the default location, GOROOT is not set. If you install your own version of Go, make sure to set the location in GOROOT
任意のバージョン使いたければちゃんと$GOROOTセットしてねって書いてるけど、これはgvmが勝手にやってくれてました。
echo $GOROOT
これはありがたいのでしたが、しかし、とてもありがた迷惑だったのが、$GOPATHの変更まで勝手にやっちゃってくれます。
echo $GOPATH
e.g.
/Users/a13533/.gvm/pkgsets/system/global
ここで結構はまります。
このGOPATHで頑張ってみてもいいのですが、circleciでは$HOME/.go_project
をGOPATHと扱うよう推奨してあります。推奨ではなくデフォルトですが、これをぼくは推奨として受け取ります。公式ドキュメントに沿っておいた方が後続のコーダーが理解しやすいとおもうので良。
a symlink is placed to your project’s directory at /home/ubuntu/.go_project/src/github.com/<USER>/<REPO_NAME>
なので、gvmが決めるGOPATHにこちらが指定したいGOPATHを追加する方法で解決しました。
そもそもどこで環境変数を上書きしているのかを探します。結論は、当該シェルのrcファイルを改変してくれていたのでした。
bashでインスコしたなら.bashrc
、zshでインスコしたなら.zshrc
の末尾に以下が追記されていると思います。
[[-s "$HOME/.gvm/scripts/gvm"]] && source "$HOME/.gvm/scripts/gvm"
このなかを追って読むと、デフォルトのpkgsetに書かれてある環境変数がロードされていることがわかるとおもいます。
そこで、デフォルトのpkgset
の設定ファイル末尾に追記してGOPATHをoverrideします。
注意: gvmのpkgsetやpkgenvを使ってGOPATH管理をしない前提です。
echo "export GOPATH; GOPATH=\"${GVM_ROOT}/pkgsets/${GVM_GOS}/global:${GOPATH}:${GOPATH_ORG}\"" >> ${GVM_ROOT}/environments/default
これで、こちらが設定したGOPATH_ORG
がGOPATHに追加されるようになります。
環境変数がセットできない、cdできない...etc
ここまで話して、export GOPATH=$GOPATH:$追加パス
でよくないか?と思われるかとおもいますが、
ひっかかりポイントとして、CircleCIは、各コマンドをサブシェルとして実行します。
どういうことかというと、
- export HOGE=fuga
- echo $HOGE
この結果は、設定した環境変数の中身は空になります。
なぜなら環境変数入れたあとに実行されるechoコマンドは別シェルで実行されるからです。
cd
コマンドしてから何かを実行したいパターンでよくはまりそうです。以下も想定した通りにはいきません。
- cd path/to/repo
- sh ./hoge.sh
sh: ./hoge.sh: No such file or directory
流れるようにコマンドが実行されるかと思いきやここ要注意です。
さて。以下、今回やった範囲の設定です。
machine:
environment:
GOROOT: ""
PATH: "/usr/local/go/bin:/usr/local/go_workspace/bin:~/.go_workspace/bin:${PATH}"
GOPATH_ORG: "${HOME}/.go_workspace:/usr/local/go_workspace:${HOME}/.go_project"
GVM_GOS: "go1.6.2"
post:
- bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) && source ${HOME}/.gvm/scripts/gvm
- gvm install ${GVM_GOS} -B
- gvm use ${GVM_GOS} --default
# `gvm` arbitrarily changes GOPATH value :( so forcibly override it with its original value.
- echo "export GOPATH; GOPATH=\"${GVM_ROOT}/pkgsets/${GVM_GOS}/global:${GOPATH}:${GOPATH_ORG}\"" >> ${GVM_ROOT}/environments/default
dependencies:
pre:
- go get github.com/golang/lint/golint
- sudo add-apt-repository ppa:masterminds/glide -y && sudo apt-get update && sudo apt-get install glide -y
- mkdir -p ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}
- ln -sfnv ${HOME}/${CIRCLE_PROJECT_REPONAME} ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
override:
- glide install
- cd ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} && go build -v -race -o build/output
test:
override:
- cd ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} && go test -v -race -cover `glide nv`
今回なかなか強引に対応しましたがほかにいいやりかたないかな。
ghq使っている自分としてはGOPATH問題がなかなかめんどうなためやりづらい。
普通に単体で使えばちゃんと便利なんだけど。