もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

実践 Terraformを読んでTerraform勉強中 Vol.12

はじめに

こんばんは。

今回は以下の本を読んで勉強中です。

今までの記事はこちら

# 実践 Terraformを読んでTerraform勉強中 Vol.1 - もがき系プログラマの日常

# 実践 Terraformを読んでTerraform勉強中 Vol.2 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.3 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.4 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.5 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.6 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.7 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.8 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.9 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.10 - もがき系プログラマの日常

実践 Terraformを読んでTerraform勉強中 Vol.11 - もがき系プログラマの日常

今回も第14章です。

バージョンは以下です。

$ terraform --version
Terraform v1.0.3

本題

第14章 デプロイメントパイプライン(CodePipeline以降)

まず最初に、前回のcodebuildでやってなかった部分の buildspec.yml を作成します。

コンテンツはこのような感じでファイルを置きます。

$ tree contents 
contents
├── Dockerfile
├── buildspec.yml
├── example.conf
└── src
    └── index.html

buildspec.yml

version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
    pre_build:
      commands:
        - $(aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin https://xxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com)
        - REPO=$(aws ecr describe-repositories --repository-names example --output text --query "repositories[0].repositoryUri)
        - IMAGE=$REPO:latest
      build:
        commands:
          - docker build -t $IMAGE contents
          - docker pull $IMAGE
      post_build:
        commands:
          - printf '[{"name":"example", "imageUrl":"%s"}]' $IMAGE > imagedefinitions.json
artifacts:
  files: imagedefinitions.json

次に codepipelineのポリシードキュメントとIAMロールを作成します。

# ポリシードキュメント
data "aws_iam_policy_document" "codepipeline" {
  statement {
    effect    = "Allow"
    resources = ["*"]
    actions = [
      "s3:PutObject",
      "s3:GetObject",
      "s3:GetObjectVersion",
      "s3:GetBucketVersioning",
      "codebuild:BatchGetBuilds",
      "codebuild:StartBuild",
      "ecs:DescribeServices",
      "ecs:DescribeTaskDefinition",
      "ecs:DescribeTasks",
      "ecr:ListTasks",
      "ecr:RegisterTaskDefinition",
      "ecr:UpdateService",
      "iam:PassRole",
    ]
  }
}

# IAMロール
module "codepipeline_role" {
  source     = "./iam"
  name       = "codepipeline"
  identifier = "codepipeline.amazonaws.com"
  policy     = data.aws_iam_policy_document.codepipeline.json
}

次に、アーティファクト用にS3バケットを用意します。

# アーティファクト用S3バケット
resource "aws_s3_bucket" "artifact" {
  bucket = "kojirock-artifact-pragmatic-terraform"
  lifecycle_rule {
    enabled = true
    expiration {
      days = "180"
    }
  }
}

githubトークンを作成します。

f:id:kojirooooocks:20211030235412p:plain

また、Exportしておきます

$ export GITHUB_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxx

codepipeline構築のためのコードを書きます。

長い...

resource "aws_codepipeline" "example" {
  name     = "example"
  role_arn = module.codepipeline_role.iam_role_arn

  stage {
    name = "Source"

    action {
      name             = "Source"
      category         = "Source"
      owner            = "ThirdParty"
      provider         = "GitHub"
      version          = 1
      output_artifacts = ["Source"]

      configuration = {
        Owner                = "xxxxxxxxxxxxx"
        Repo                 = "xxxxxxxxxxxxx"
        Branch               = "main"
        PollForSourceChanges = false
      }
    }
  }

  stage {
    name = "Build"

    action {
      name             = "Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      version          = 1
      input_artifacts  = ["Source"]
      output_artifacts = ["Build"]

      configuration = {
        ProjectName = aws_codebuild_project.example.id
      }
    }
  }

  stage {
    name = "Deploy"

    action {
      name            = "Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "ECS"
      version         = 1
      input_artifacts = ["Build"]

      configuration = {
        ClusterName = aws_ecs_cluster.example.name
        ServiceName = aws_ecs_service.example.name
        FileName    = "imagedefinitions.json"
      }
    }
  }

  artifact_store {
    location = aws_s3_bucket.artifact.id
    type     = "S3"
  }
}

githubからのwebhook受付のためのコードを書きます。

resource "aws_codepipeline_webhook" "example" {
  name            = "example"
  target_pipeline = aws_codepipeline.example.name
  target_action   = "Source"
  authentication  = "GITHUB_HMAC"

  authentication_configuration {
    secret_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }

  filter {
    json_path    = "$.ref"
    match_equals = "refs/heads/{Branch}"
  }
}

githubのプロバイダを定義します

provider "github" {
  organization = "xxxxxxxxxxxxx"
}

今度はgithub側のwebhook通知のためのコードを書きます。

resource "github_repository_webhook" "example" {
  repository = "xxxxxxxxxxxxx"

  configuration {
    url          = aws_codepipeline_webhook.example.url
    secret       = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    content_type = "json"
    insecure_ssl = false
  }

  events = ["push"]
}

終わりに

写経して思ったのですが、これ全部理解しているものなのでしょうか...

やってて長すぎて頭おかしくなりそうでした...

ちょっとここはもう一度やりたいと思います。

現場からは以上です。