使用Rails和Nuxt3来创建一个todo列表[REST-API/Terraform/Fargate]〜第七部分,蓝/绿部署之后

首先

我打算用Rails和Nuxt3来详细解释如何从头开始创建一个待办事项清单。

使用电脑以mac为前提。

完成的配置图如下所示。

aws_structure.png

此外,GitHub存储库在这里。

 

各个系列如下所示。

在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第1部分,Rails基本设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第2部分,Rails API设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第3部分,Nuxt.js设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第4部分,TerraformECS前期设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第5部分,TerraformECS后期设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第6部分,Blue/Green部署前期设置
在Rails和Nuxt3中创建一个todo列表[REST-API/Terraform/Fargate]〜第7部分,Blue/Green部署后期设置

Codepipeline 代码管道

CodePipeline:自动化的软件传送管道

CodePipeline是将Code系列连接在一起的工具。

resource "aws_codepipeline" "codepipeline" {
  name     = "${var.app_name}-pipeline"
  role_arn = aws_iam_role.codepipeline_role.arn

  artifact_store {
    # S3 (アーティファクト格納用)
    # CodePileline では次のステージにアーティファクトを引き渡す時、S3 バケットを経由させます。
    location = aws_s3_bucket.codepipeline_bucket.bucket
    type     = "S3"
  }

  stage {
    name = "Source"

    action {
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeCommit"
      output_artifacts = ["SourceArtifact"]
      version          = "1"

      configuration = {
        RepositoryName       = aws_codecommit_repository.codecommit_repository.repository_name
        BranchName           = "main"
        OutputArtifactFormat = "CODE_ZIP"
      }
    }
  }

  stage {
    name = "Build"

    # webserver
    action {
      name             = "WEB_Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      input_artifacts  = ["SourceArtifact"]
      output_artifacts = ["BuildArtifact1"]
      version          = "1"

      configuration = {
        ProjectName = aws_codebuild_project.web.name
      }
    }

    # apisever
    action {
      name             = "API_Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      input_artifacts  = ["SourceArtifact"]
      output_artifacts = ["BuildArtifact2"]
      version          = "1"

      configuration = {
        ProjectName = aws_codebuild_project.api.name
      }
    }
  }

  stage {
    name = "Deploy"

    # webserver
    action {
      name            = "WEB_Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "CodeDeployToECS"
      input_artifacts = ["BuildArtifact1"]
      version         = "1"

      configuration = {
        ApplicationName                = var.app_name
        DeploymentGroupName            = aws_codedeploy_deployment_group.web.deployment_group_name
        TaskDefinitionTemplateArtifact = "BuildArtifact1"
        TaskDefinitionTemplatePath     = "taskdef.json"
        AppSpecTemplateArtifact        = "BuildArtifact1"
        AppSpecTemplatePath            = "appspec.yml"
        Image1ArtifactName             = "BuildArtifact1"
        Image1ContainerName            = "IMAGE1_NAME"
      }
    }

    # apserver
    action {
      name            = "API_Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "CodeDeployToECS"
      input_artifacts = ["BuildArtifact2"]
      version         = "1"

      configuration = {
        ApplicationName                = var.app_name
        DeploymentGroupName            = aws_codedeploy_deployment_group.api.deployment_group_name
        TaskDefinitionTemplateArtifact = "BuildArtifact2"
        TaskDefinitionTemplatePath     = "taskdef.json"
        AppSpecTemplateArtifact        = "BuildArtifact2"
        AppSpecTemplatePath            = "appspec.yml"
        Image1ArtifactName             = "BuildArtifact2"
        Image1ContainerName            = "IMAGE1_NAME"
      }
    }
  }
}

代码提交

CodeCommit用于将代码镜像到GitHub上。

resource "aws_codecommit_repository" "codecommit_repository" {
  repository_name = "${var.app_name}-repository"
  description     = "This is the ${var.app_name} App Repository"
}

CodeBuild 代码构建

由于BuildAriifn中的限制是最多只能存储3MB的内容,因此我们只限制在appspec.yml、taskdef.json和imageDetail.json这三个文件中。

resource "aws_codebuild_project" "web" {
  name         = "${var.app_name}-web-codebuild"
  description  = "codebuild_project for web ${var.app_name}"
  service_role = aws_iam_role.codebuild-role.arn

  artifacts {
    type = "CODEPIPELINE"
  }

  source {
    type      = "CODEPIPELINE"
    buildspec = "terraform/template/web_buildspec.yml"
  }

  environment {
    compute_type    = "BUILD_GENERAL1_SMALL"
    image           = "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
    type            = "LINUX_CONTAINER"
    privileged_mode = true


    environment_variable {
      name  = "AWS_ACCOUNT_ID"
      value = data.aws_caller_identity.self.account_id
    }
    environment_variable {
      name  = "ECR_WEB_REPOSITORY"
      value = var.web_app_name
    }
    environment_variable {
      name  = "ECS_WEB_TASK_DEFINITION_ARN"
      value = "${var.web_app_name}-definition"
    }
  }
}

resource "aws_codebuild_project" "api" {
  name         = "${var.app_name}-api-codebuild"
  description  = "codebuild_project for api ${var.app_name}"
  service_role = aws_iam_role.codebuild-role.arn

  artifacts {
    type = "CODEPIPELINE"
  }

  source {
    type      = "CODEPIPELINE"
    buildspec = "terraform/template/api_buildspec.yml"
  }

  environment {
    compute_type    = "BUILD_GENERAL1_SMALL"
    image           = "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
    type            = "LINUX_CONTAINER"
    privileged_mode = true

    environment_variable {
      name  = "AWS_ACCOUNT_ID"
      value = data.aws_caller_identity.self.account_id
    }
    environment_variable {
      name  = "ECR_API_REPOSITORY"
      value = var.api_app_name
    }
    environment_variable {
      name  = "ECS_API_TASK_DEFINITION_ARN"
      value = "${var.api_app_name}-definition"
    }
  }
}
version: 0.2

env:
  variables:
    AWS_REGION: ap-northeast-1
    IMAGE_TAG: latest

phases:
  pre_build:
    commands:
      - API_REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_API_REPOSITORY
  build:
    commands:
      - printf '{"Version":"1.0","ImageURI":"%s"}' $API_REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
      - echo $ECS_API_TASK_DEFINITION_ARN
      - $(aws ecs describe-task-definition --task-definition $ECS_API_TASK_DEFINITION_ARN --query taskDefinition | jq '.containerDefinitions[0].image="<IMAGE1_NAME>"' > taskdef.json)
      - cat taskdef.json
      - $(aws ecs describe-task-definition --task-definition apiserver-definition --query taskDefinition | jq '.containerDefinitions[0].image="<IMAGE1_NAME>"' > taskdef.json)
      - cat taskdef.json
      - cp terraform/template/api_appspec.yml appspec.yml

artifacts:
  files:
    - appspec.yml
    - taskdef.json
    - imageDetail.json
version: 0.2

env:
  variables:
    AWS_REGION: ap-northeast-1
    IMAGE_TAG: latest

phases:
  pre_build:
    commands:
      - WEB_REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_WEB_REPOSITORY
  build:
    commands:
      - cp terraform/template/web_appspec.yml appspec.yml
      - $(aws ecs describe-task-definition --task-definition $ECS_WEB_TASK_DEFINITION_ARN --query taskDefinition | jq '.containerDefinitions[0].image="<IMAGE1_NAME>"' > taskdef.json)
      - printf '{"Version":"1.0","ImageURI":"%s"}' $WEB_REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
  files:
    - appspec.yml
    - taskdef.json
    - imageDetail.json

编码部署

resource "aws_codedeploy_app" "main" {
  compute_platform = "ECS"
  name             = var.app_name
}

resource "aws_codedeploy_deployment_group" "web" {
  app_name               = aws_codedeploy_app.main.name
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
  deployment_group_name  = var.web_app_name
  service_role_arn       = aws_iam_role.codedeploy-role.arn

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 5
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  ecs_service {
    cluster_name = "todolist-cluster"
    service_name = "webserver-service"
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [var.http_arn]
      }

      target_group {
        name = var.web_blue_name
      }

      target_group {
        name = var.web_green_name
      }
    }
  }
}


resource "aws_codedeploy_deployment_group" "api" {
  app_name               = aws_codedeploy_app.main.name
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
  deployment_group_name  = var.api_app_name
  service_role_arn       = aws_iam_role.codedeploy-role.arn

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 5
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  ecs_service {
    cluster_name = "todolist-cluster"
    service_name = "apiserver-service"
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [var.http_arn]
      }

      target_group {
        name = var.api_blue_name
      }

      target_group {
        name = var.api_green_name
      }
    }
  }
}
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "<TASK_DEFINITION>"
        LoadBalancerInfo:
          ContainerName: "apiserver"
          ContainerPort: 8080
        PlatformVersion: "1.4.0"
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "<TASK_DEFINITION>"
        LoadBalancerInfo:
          ContainerName: "webserver"
          ContainerPort: 3000
        PlatformVersion: "1.4.0"

结果

最后执行。

Screenshot 2023-06-04 at 14.08.49.png
Screenshot 2023-06-04 at 14.09.55.png
广告
将在 10 秒后关闭
bannerAds