弊社では一部のサービスのビルドとデプロイにAWS CodePipeline, CodeBuild を使用しています。インフラの作成には terraform を使用しています。
ソースは Github で管理しているのですが、ビルドしたいリポジトリが別リポジトリをサブモジュールとして参照している場合に、サブモジュールのソースを取得できませんでした。
その時の対処法を記しておきます。
CodeBuild でサブモジュール使えなかったっけ?
使えます。ただし CodePipeline と組み合わせなければ。
terraform のリファレンスを見てみましょう。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project
source: git_submodules_config
This block is only valid when the type is CODECOMMIT, GITHUB, GITHUB_ENTERPRISE, GITLAB, or GITLAB_SELF_MANAGED.
fetch_submodules - (Required) Whether to fetch Git submodules for the AWS CodeBuild build project.
CodePipeline と組み合わせているので type は CODEPIPELINE
になっていました。ということで属性をちょっといじるだけでは解決しません。
対処法
パイプラインのソースステージでプライマリとサブモジュールそれぞれ別々に取得するよう action を作成します。ビルドステージではどれがプライマリなのかを示してやります。
terraform
まずは CodePipeline の定義
resource "aws_codepipeline" "pipeline" {
# nameなどを省略
stage {
name = "Source"
# プライマリリポジトリ用
action {
name = "SourcePrimary"
category = "Source"
namespace = "SourceVariablesPrimary"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["primary_output"]
configuration = {
ConnectionArn = data.aws_codestarconnections_connection.github.arn
FullRepositoryId = var.github_repository
BranchName = var.target_branch
}
}
# サブモジュールリポジトリ用
action {
name = "SourceSubModule"
category = "Source"
namespace = "SourceVariablesSubModule"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["submodule_output"]
configuration = {
ConnectionArn = data.aws_codestarconnections_connection.github.arn
FullRepositoryId = var.github_repository_submodule
BranchName = var.target_branch_submodule
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["primary_output", "submodule_output"]
output_artifacts = ["build_output"]
version = "1"
configuration = {
ProjectName = aws_codebuild_project.buildstage.name
# 2つ以上のソースがある時はどちらがプライマリか指定する必要がある
PrimarySource = "primary_output"
}
}
}
}
次に CodeBuild の定義です。
resource "aws_codebuild_project" "buildstage" {
# nameなどを省略
source {
type = "CODEPIPELINE"
buildspec = "buildspec-build.yaml"
}
}
buildspec.yaml
プライマリのリポジトリは自動でカレントディレクトリに展開されます。
一方、サブモジュールは環境変数 ${CODEBUILD_SRC_DIR_xxxxxxx}
の示すディレクトリに展開されます。ここで xxxxxxx
の部分はソースステージの action で指定した output_artifacts
の値です。
セカンダリソースの場合、ディレクトリパスの環境変数は「CODEBUILD_SRC_DIR_」です。「」は作成するソース識別子です。
あとはサブモジュールのソースを任意のディレクトリに移動するなりしましょう。
version: 0.2
phases:
pre_build:
commands:
# ソースステージの action で `output_artifacts = ["submodule_output"]` と指定したので
# サブモジュールは ${CODEBUILD_SRC_DIR_submodule_output} に展開される
cp -r ${CODEBUILD_SRC_DIR_submodule_output}/* ./submodule_directory/
まとめ
CodePipeline + CodeBuild でサブモジュールを含むソースをビルドする場合はこうするとよいです。
- プライマリとサブモジュールをそれぞれソースのactionで別々に取得する
- buildspec でサブモジュールを任意のディレクトリに移動する