CodeBuildを使ってECRにpushして本番作業を減らしたい


背景

  • 現在の本番環境はECSを使っている。
  • リリース毎に手動でDockerのビルドからECRにpushを行い、タスクを作成してデプロイを行っている。
  • 手動作業による人的ミス、本番作業の精神的負荷を下げたい。
  • AWSのSAAの勉強中CodeBuildサービスなるものを発見。
  • まずはCodeBuildを使ってDockerのイメージ生成からECRへのpushをワンコマンドで行いたい。

コード解説

resource "aws_ecr_repository" "nginx" {
  name                 = "my-nginx"
  image_tag_mutability = "MUTABLE"
  image_scanning_configuration {
    scan_on_push = true
  }
}

output "ecr_url" {
  value = aws_ecr_repository.nginx.repository_url
}
  • IAMポリシー
    • CodeBuild用のIAMポリシーの設定
    • CodeBuild関連の権限に加えて、ECRへのpushのための権限とCloudWatchにログを流すための権限を付与
    • 実際の本番環境は資材をS3で管理しているのでそちらの権限も追加している
data "aws_iam_policy_document" "assume_role_codebuild" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["codebuild.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "codebuild_execution_role" {
  name               = "MyCodeBuildRole"
  assume_role_policy = data.aws_iam_policy_document.assume_role_codebuild.json
}

resource "aws_iam_role_policy_attachment" "amazon_ec2_container_registry_full_access" {
  role       = aws_iam_role.codebuild_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess"
}

resource "aws_iam_role_policy_attachment" "amazon_ec2_container_registry_power_user" {
  role       = aws_iam_role.codebuild_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser"
}

resource "aws_iam_policy" "codebuild_base_policy" {
  name = "CodeBuildBasePolicy-my_nginx"
  policy = jsonencode({
    Version: "2012-10-17",
    Statement: [
      {
        Effect: "Allow",
        Resource: [
          "arn:aws:logs:ap-northeast-1:${var.aws_account_id}:log-group:/aws/codebuild/my_nginx",
          "arn:aws:logs:ap-northeast-1:${var.aws_account_id}:log-group:/aws/codebuild/my_nginx:*"
        ],
        Action: [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
      },
      {
        Effect: "Allow",
        Resource: [
          "arn:aws:s3:::codepipeline-ap-northeast-1-*"
        ],
        Action: [
          "s3:PutObject",
          "s3:GetObject",
          "s3:GetObjectVersion",
          "s3:GetBucketAcl",
          "s3:GetBucketLocation"
        ]
      },
      {
        Effect: "Allow",
        Action: [
          "codebuild:CreateReportGroup",
          "codebuild:CreateReport",
          "codebuild:UpdateReport",
          "codebuild:BatchPutTestCases",
          "codebuild:BatchPutCodeCoverages"
        ],
        Resource: [
          "arn:aws:codebuild:ap-northeast-1:${var.aws_account_id}:report-group/my_nginx-*"
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "codebuild_policy" {
  role       = aws_iam_role.codebuild_execution_role.name

  policy_arn = aws_iam_policy.codebuild_base_policy.arn
}
  • CodeBuild
    • ビルドする環境の設定: 今回はFargateのECSを想定しているのでx86アーキテクチャを指定。
    • ビルドするソースの指定: 下記ではGitHubを指定しているがS3等も指定可能。
    • ビルドのコマンドの設定: https://github.com/akapo001/terraform-ecr-ecs/blob/main/buildspec.yml
      ※特に指定がない場合、sourceセクションで指定したファイルの場所からbuildspec.ymlを自動で見つけてくれる。(任意のファイルを指定することも可能)
resource "aws_codebuild_project" "my_nginx" {
  name = "my_nginx"
  service_role = aws_iam_role.codebuild_execution_role.arn
  artifacts {
    type = "NO_ARTIFACTS"
  }
  environment {
    compute_type = "BUILD_GENERAL1_SMALL"
    image = "aws/codebuild/amazonlinux2-x86_64-standard:2.0"
    type = "LINUX_CONTAINER"
    privileged_mode = true

    environment_variable {
      name = "AWS_ACCOUNT_ID"
      value = var.aws_account_id
      type = "PLAINTEXT"
    }
    environment_variable {
      name = "AWS_DEFAULT_REGION"
      value = "ap-northeast-1"
      type = "PLAINTEXT"
    }
    environment_variable {
      name = "IMAGE_REPO_NAME"
      value = "my-nginx"
      type = "PLAINTEXT"
    }
    environment_variable {
      name = "IMAGE_TAG"
      value = "latest"
      type = "PLAINTEXT"
    }
  }
  source {
    type = "GITHUB"
    location = "https://github.com/akapo001/terraform-ecr-ecs.git"
    git_clone_depth = 1
    git_submodules_config {
      fetch_submodules = true
    }
  }
  source_version = "main"
}

ビルド

  • terraform.tfvarsファイルにシークレット情報を書き込んだ後terraform applyを実行する。
  • 下記画面より、「ビルドを開始」を押すだけでbuildspec.ymlに書かれたコマンドを実行し、最終的にECRにイメージがpushされる。

完了画面

  • ECSのコンソールにてプッシュされていることが確認できました。