Go Modules で GitHub の private repository に依存しているプロジェクトを AWS CodeBuild で build する | SEEDS Creators' Blog | 株式会社シーズ

Go Modules で GitHub の private repository に依存しているプロジェクトを AWS CodeBuild で build する

クラウド事業部エンジニアの川勝です。
最近 AWS 認定 DevOps エンジニア – プロフェッショナル を取得しました。
せっかく試験に受かったので DevOps っぽい内容の記事を書こうかと思います。

概要

Go Modules で github の private repository に依存している場合、ローカル環境では自分の github アカウントでssh接続していれば問題ないのですが、CI/CD環境で依存解決するにはちょっと工夫が必要です。

  1. 自分のアカウント、または権限のある machine account の access token を発行して CI/CD環境の git config に access token を使用するように変更する。
  2. 自分のアカウント、または権限のある machine account の ssh秘密鍵をCI/CD環境に設置する。
  3. Go modules で依存しないように git のsubmodule にして repository に含める

などなど….しばらく思案していました。
考え方としては 3 に近いのですが、 AWS CodeBuild を使用すると repository に変更を加えなくても source を複数設定することで依存解決ができたのでその方法をまとめます。

使用するソースコードは以下で公開しています。
https://github.com/kawakattsun/codebuild-go-modules-sample
依存パッケージは private にしているので閲覧できませんが、埋め込まれたバージョン情報を表示するだけのものになっています。

package version

import "fmt"

var (
	version  string
	revision string
)

// ShowVersion show version.
func ShowVersion(name string) {
	fmt.Printf("%s version %s (%s)\n", name, version, revision)
}

ビルドプロジェクトの作成

まず AWS マネジメントコンソールから AWS CodeBuild のビルドプロジェクトを作成します。

ビルドプロジェクトを作成する
プロジェクトの設定

ソース

今回のポイントであるソースの設定です。以下を選択して Github に接続します。
ソースプロバイダ: Github
リポジトリ: OAuth を使用して接続する

ソース
Gitub 側で AWS CodeBuild からの接続を承認
Github と認証ができたら AWS CodeBuild 側で Github への接続を確認
Github アカウントのリポジトリ が表示されるので選択

[ソース 1 – プライマリ] を設定したら [ソースの追加] から [ソース 2] の設定を行います。
今回の場合だと以下のリポジトリを選択しています。
[ソース 2] のほうが Github アカウントの private repository に設定されています。
ソース 1: codebuild-go-modules-sample.git
ソース 2: codebuild-go-modules-sample-private.git

[ソース 2] の方には [ソース識別子] を設定します。
buildspec.yml でソースが展開されているディレクトリの指定に使用します。

ソースの追加

ちなみに [ソース識別子] ですが 128文字以内の半角英数字とアンダースコア(_) のみが使用可能です。
わかりやすくリポジトリ名を設定していますが、ハイフン(-) を使用するとプロジェクトの作成時にエラーとなります。

ソース識別子 のバリデーションエラー

エラーだけならいいのですが、後述するサービスロールを新規作成にしていると、実はエラーになってもサービスロースは作成されてしまいます…
したがってエラー箇所修正して再度登録しようとするとまたエラーになっていまいます。
さらにこの時点で作成されたサービスロールは既存のロール一覧には出てこないので AWS IAM の画面から ARN をしらべて設定しないといけなかったります。

サービスロールが作成されてしまってすでに存在します、、、と言われる

環境

続いて [環境] の設定です。
今回は環境イメージはマネージド型イメージの最新の Amazon Linux 2 を使います。
どのようなものが用意されているかは CodeBuild に用意されている Docker イメージ を参照してください。
あと先程ちょっと問題があったサービスロールもここで設定します。

環境

Buildspec

AWS CodeBuild では YAML 形式でコマンドを記述します。

Buildspec

今回用意したのは以下になります。
プログラムの内容てきには実行すると version と revision を表示する、、というものです。

version: 0.2

phases:
  install:
    runtime-versions:
      golang: latest
  pre_build:
    commands:
    - echo "replace github.com/kawakattsun/codebuild-go-modules-sample-private => $(realpath --relative-to=./ ${CODEBUILD_SRC_DIR_codebuild_go_modules_sample_private})" >> go.mod
    - export GO_LDFLAGS="-X github.com/kawakattsun/codebuild-go-modules-sample-private/version.version=${CODEBUILD_SOURCE_VERSION} -X github.com/kawakattsun/codebuild-go-modules-sample-private/version.revision=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 8)"
    - go mod download
  build:
    commands:
    - go build -trimpath -ldflags "${GO_LDFLAGS}" -o ./bin/codebuild-go-modules-sample .
    - ./bin/codebuild-go-modules-sample

本記事の本題である GitHub の private repository に依存している github.com/kawakattsun/codebuild-go-modules-sample-private というパッケージを go.mod のreplace でローカルのディレクトリを参照するようにしています。(8行目)
CODEBUILD_SRC_DIR_codebuild_go_modules_sample_private という環境変数に [ソース 2] で設定したプログラムのソースが保存されているディレクトリのパスが格納されています。
CODEBUILD_SRC_DIR_ のあとに設定した識別子をつなげた変数名になっています。
詳しくは ビルド環境の環境変数 を参照してください。

この設定を入れることで、ビルド環境の git 設定を調整する必要なく build できるようになりました。

その他の設定

あとは特に今回は使用しないのでデフォルトのままで [ビルドプロジェクトを作成する] と完成です。

ビルドの開始

それでは早速ビルドを開始しましょう。

ビルドの開始

実行時に設定するのは [ソースのバージョン] です。
今回はソース 1, 2 ともに v0.1.0 という tag を git で付けていますので tag の値を入力しています。
ここで入力した値が buildspec の環境変数 CODEBUILD_SOURCE_VERSION い格納されます。
したがって今回のプログラムだと private repository のプロジェクトの中の変数にバージョン情報を埋め込んでいますので、実行してこの値が表示されれば OK となります。

ビルド設定

実行してしばらくするとログが表示されます。
赤枠にバージョンの値が表示されていますね!
うまく build できて実行できました。

ビルドログ

ちなみに buildspec.yml 8行目の go.mod のreplace を追記している箇所をコメントアウトして実行すると以下のようにエラーとなりました。

ビルドログ – エラー

まとめ

今回の方法は Go Modules で Github の private repository に依存している場合の解決方法のベストプラクティスというわけではありませんが、一つの方法としてありかと思います。
OAuth 認証すれば token の発行などは必要ないので認証情報の流出という面で安全でもあります。
ただし AWS マネジメントコンソール で AWS CodeBuild を閲覧できるユーザは他人が OAuth 認証していると自分が見れないはずの Github の repository が閲覧できる可能性もあるのでそこは注意が必要です。

その他にAWS CodeBuild のメリットとして、入力ソースが複数設定できるのは他の CI/CD 系のサービスにはあまりないように思います。(要確認ですが…)
今回は Github だけがソースでしたが、 Amazon S3 など複数のサービスから取得して実行できるので使いかたが広がりそうですね。

以上、川勝でした。