CodeBuildでgo言語のプロジェクトをビルドする際の注意事項
こんにちは。エンジニアの島袋です。
前回に引き続き、AWS CodeBuildの話になります。
CodeBuildでgo言語のプロジェクトをビルドする場合のハマりポイントに気づいたので、そちらを紹介します。
要点から先に言うと、以下です。
- CodeBuildは/tmp配下にリポジトリをチェックアウトするため、ビルド対象がGOPATH配下にない
- GOPATH配下にないとvendoringが有効にならないため、go build時に「パッケージが見つからない」と言われる
go buildがコケる??
前回のエントリではbuildspec.ymlのphase名をtypoしたせいでドハマリしてたんですが、その後typoを修正し、再度ビルドを実行すると、今度はgo buildでコケました。
エラーメッセージには「cannot find package〜」と表示されています。
依存しているパッケージが見つからないということですが、そんなはずはありません。
installフェイズでglideを使い、依存パッケージは全てvendorディレクトリの中にダウンロード済みです。
では何が駄目だったのでしょうか?
ビルド対象のプロジェクトがGOPATH配下になかったため、vendoringが有効になっていなかった
GOPATHとvendoringについて簡単に説明しておくと、GOPATHはgo言語を利用する際に設定が必要になる環境変数で、ユーザが任意のパスを指定する必要があります。
go言語でbuildコマンドを叩くと、buildに必要な依存パッケージをGOPATH/src配下から走査します。
(go get "パッケージ名" とコマンドを叩くと、GOPATH/src配下にパッケージをダウンロードできます)
ところが、この方法ではプロジェクト毎に利用するパッケージのバージョンを管理することができません。
(go getコマンドは常に最新版を取得します)
そこで追加された機能がvendoringです。
vendoringは有効な状態では、GOPATH/src配下を走査する前に、プロジェクトのルートディレクトリ直下のvendorディレクトリからパッケージを走査します。
上述のglideはvendorディレクトリ内に依存パッケージをダウンロードするパッケージマネージャです。
(rubyにおけるbundlerのようなものですね)
そんな便利なvendoringなんですが、ビルド対象のプロジェクトディレクトリをGOPATH/src配下に配置していないと有効になりません。
ところが、CodeBuildはビルド対象として指定したリポジトリを"/tmp/src257031055/src"といった感じで/tmp配下にチェックアウトしてしまうんですね。
当該ディレクトリ内のvendorディレクトリ内に依存パッケージをダウンロードし、go buildコマンドを叩いても、vendoringが有効になっていないため、GOPATH/src配下した走査してくれず、「cannot find package〜」と表示されてしまうわけです。
筆者含め、go言語利用者はGOPATH/src配下にディレクトリを作ってコードを書き始めるのが半ば常識化しているため、vendoringが無効になっていることに気づくのに時間を要しました。
回避策
とりあえずのワークアラウンドなんですが、以下のようにしました。
...省略... pre_build: commands: - glide install - mkdir -p $GOPATH/src/github.com/stk132/tsg - mv * $GOPATH/src/github.com/stk132/tsg/. build: commands: - cd $GOPATH/src/github.com/stk132/tsg && go build
はい。pre_buildフェイズでGOPATH/src配下にディレクトリを切って、CodeBuildがチェックアウトしてきたリポジトリの中身を全てコピーしています。
(これで当該ディレクトリの中ではvendoringが有効になります。)
そしてbuildフェイズでは当該ディレクトリに移動して、go buildを実行します。
(cdコマンドとgo buildをチェインしているのは、別の行にわけて実行すると、元のワーキングディレクトリに戻っているためです。多分Dockerfileのビルド時と同じ挙動??)
これ、もうちょっとスマートな解決方法ないですかね。。。。?
GOPATH=$GOPATH:pwd
とかして、ワーキングディレクトリをGOPATHに追加する方法も考えたんですけど、それだとビルド対象プロジェクト内のサブパッケージが走査できなくなるんですよね。
終わりに
よくよく考えると、jenkins等も同様の問題をはらんでいる気がするのですが、もしかしてgo言語のプロジェクトのCIを回している人にとっては今回のようなのは常識だったりするのでしょうか?
筆者は専らローカルで利用するCLIコマンドばかり作っているため、ビルドもローカルマシン上で行なっていたため、まんまとハマってしまいました。
コメント