こんにちは。バックエンドエンジニアの高橋です。
あるプロジェクトで実装したCodeDeployとCodePipelineを使ったデプロイをTerraform化したので、その実装例を紹介したいと思います。
バランサーとEC2
今回はバランサーに複数のウェブサーバがぶら下がっていてそこにインプレースデプロイする構成とします。
デプロイフロー
CodePipelineソースアクションのGitHubバージョンですが、1が非推奨の為バージョン2で実装します。
※ Terraformでは、バージョン2のGitHub接続の為のCodeStartConnectionが一部使えないので注意(後述)
Terraformで実装
前提
VPC、EC2、ALBといったリソースは既に構築済みである事とします。
また各環境とモジュールのそれぞれに必要な変数が設定されているものとします。
ディレクトリ構成
. ├── envs │ ├── develop │ │ ├── backend.tf │ │ ├── deploy │ │ │ ├── backend.tf │ │ │ ├── main.tf │ │ │ └── variables.tf │ │ ├── main.tf │ │ └── variables.tf └── modules └── deploy ├── codedeploy │ ├── main.tf │ └── output.tf ├── codepipeline │ └── main.tf └── provider └── main.tf
CodeDeploy
必要なリソースのインポート
$ terraform import module.codedeploy.aws_vpc.main_vpc vpc-0****** $ terraform import module.codedeploy.aws_lb_target_group.alb_target_group arn:aws:****** $ terraform import module.codedeploy.aws_iam_role.ec2_deploy_role RoleNameSample
①インポートしたリソースの定義
// VPC resource "aws_vpc" "main_vpc" { ~~ } // ALB Target Group resource "aws_lb_target_group" "alb_target_group" { ~~ } // EC2にアタッチしたロール resource "aws_iam_role" "ec2_attach_role" { ~~ }
②デプロイアプリケーションとデプロイグループの作成
// アプリケーション作成 resource "aws_codedeploy_app" "deploy_application" { compute_platform = "Server" name = "${var.project}-deploy" } // デプロイグループ作成 resource "aws_codedeploy_deployment_group" "deploy_group" { app_name = aws_codedeploy_app.deploy_application.name deployment_group_name = "${var.stage}-deploy-group" service_role_arn = aws_iam_role.ec2_attach_role.arn deployment_config_name = "CodeDeployDefault.OneAtATime" // デプロイ対象のEC2タグ ec2_tag_set { ec2_tag_filter { key = "Deploy" type = "KEY_AND_VALUE" value = var.stage } } // 失敗時のロールバック auto_rollback_configuration { enabled = true events = ["DEPLOYMENT_FAILURE"] } // ロードバランサーの有効化 deployment_style { deployment_option = "WITH_TRAFFIC_CONTROL" deployment_type = "IN_PLACE" } // ターゲットグループ load_balancer_info { target_group_info { name = aws_lb_target_group.alb_target_group.name } } }
CodePipeline
①IAMロール作成とポリシーアタッチ
ポリシーは長いので割愛します。
ActionにはCodeDeployやS3など必要なリソースを適宜セットしてください。
// IAMロール作成 resource "aws_iam_role" "codepipeline_role" { name = "${var.project}-${var.stage}-pipeline-role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "codepipeline.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } // ポリシーの作成 resource "aws_iam_role_policy" "codepipeline_policy" { name = "${var.project}-${var.stage}-pipeline-policy" role = aws_iam_role.codepipeline_role.id policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": [ "iam:PassRole" ], "Resource": "*", "Effect": "Allow", "Condition": { "StringEqualsIfExists": { "iam:PassedToService": [ "cloudformation.amazonaws.com", "elasticbeanstalk.amazonaws.com", "ec2.amazonaws.com", "ecs-tasks.amazonaws.com" ] } } }, ~~ } EOF }
②S3バケット作成
resource "aws_s3_bucket" "codepipeline_bucket" { bucket = "${var.project}-${var.stage}-codepipeline-${var.region}" acl = "private" force_destroy = false }
③パイプライン作成
ソース/デプロイステージのみを作ります。
(ビルドステージは今回はスキップします)
~~ variable "codestar_connection_arn" {} ~~ resource "aws_codepipeline" "codepipeline" { name = "${var.project}-${var.stage}-pipeline" role_arn = aws_iam_role.codesart_connection.arn // アーティファクトストア artifact_store { location = aws_s3_bucket.codepipeline_bucket.bucket type = "S3" } // ソースステージ stage { name = "Source" action { name = "Source" category = "Source" owner = "AWS" provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["SourceArtifact"] configuration = { ConnectionArn = var.codestar_connection_arn FullRepositoryId = var.repository BranchName = var.repository_branch } } } // デプロイステージ stage { name = "Deploy" action { name = "Deploy" category = "Deploy" owner = "AWS" provider = "CodeDeploy" input_artifacts = ["SourceArtifact"] version = "1" configuration = { ApplicationName = var.codedeploy_application_name DeploymentGroupName = var.codedeploy_deploy_group_name } } } }
aws_codestarconnections_connectionリソースについて
Terraformで保留状態になっており使用出来ません。
(2021年2月12日現在)
その為、事前にAWSコンソールのCodePipelineから適当にアプリケーションを作成し、発行されたarnを変数定義する必要があります。
入出力アーティファクトについて
パイプラインの各ステージで必要な output_artifacts/input_artifacts の箇所は実装する際に少し迷いそうですが、
以下の図の様なワークフローを理解すると分かり易いのかなと思います。
まとめ
Terraformで言語化すると作成するリソースにはどのリソースやコンポーネントが必要なのかといった全体像の把握が改めて出来る点が良いなと思っています。
ただ一部保留や未対応であったりと100%がTerraformで対応出来る訳ではない点が残念です。
最後に
Wizではエンジニアを募集しております。 興味のある方、ぜひご覧下さい。