はじめに
RailsとNuxt3でtodoリストの作り方を
初めから丁寧に説明したいと思います。
使用pcはmacを想定しています。
完成した構成図は以下の通りです。
また、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デプロイ後編
codepipline
codepipline
codepiplineは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
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
codedeploy
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"
結果
最後に実行します。