お久しぶりです。インフラソリューション部の“のなか”です。
今回は前回に続き、AWS上で稼働している既存WordPressを更新する際にかかっているデプロイ時間を30分から5分に圧縮した話をしていきます。
前編ではWordPressを構築しましたが、後編では自動デプロイを設定していきます。
それではWordPressのデプロイ自動化の後編を始めていきましょう!
注意点
– 前編で説明した内容は省略
前提条件
– 前編を実施済み
– SSHの公開鍵と秘密鍵を作成済み
– WSL2にzipパッケージをインストール済み
用語説明
EC2 Image Builderとは
後編に入る前にEC2 Image Builderについて説明します。
EC2 Image Builderとは公式ドキュメントのユーザーガイドで以下のように説明されています。
EC2 Image Builder is a fully managed AWS service that helps you to automate the creation, management, and deployment of customized, secure, and up-to-date server images. You can use the AWS Management Console, AWS Command Line Interface, or APIs to create custom images in your AWS account.
説明を1行でまとめるとイメージの作成、管理、デプロイを自動化するツールです。例えば公式ドキュメントでは以下の図で説明されています。
以下の順番で実行し、この一連の処理をイメージパイプラインと言います。
1. イメージからインスタンスを起動
2. (ビルド)元のイメージにソフトウェアをインストール
3. インスタンスを終了
4. ソフトウェアをインストールイメージからインスタンスを起動
5. (テスト)作成したイメージをテスト
6. インスタンスを終了
7. テストしたイメージからゴールデンイメージを作成
イメージのビルドとテストが可能になるため、イメージの管理やセキュリティの担保がマネージドサービスから行えますが、2回インスタンスの起動と終了が行われるため、実行時間が30分程度かかります。
※実行時間はイメージ毎で異なります。
ドキュメントルート配下をデプロイするだけであれば、CodeDeployのみでも良いですが、EC2自体を更新したい場合は試してみると良いと思います。
後編のリソース作成手順
手順
1. TerraformでCodeCommitを作成
2. TerraformでDeployを作成
3. TerraformでCodePipelineを作成し、動作確認
4. TerraformでEC2 Image Builderを作成
5. TerraformでLambdaを作成
6. TerraformでCodePipelineにLambdaを追加し、動作確認
後編のシステム図と使用するAWSのリソース
システム図
使用するAWSのリソース
– S3
– Lambda
後編のディレクトリ構成
Terraform
後編の~/terraform-blog
は以下のディレクトリ構成になります。
.
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── hashicorp
│ └── aws
│ └── 4.57.1
│ └── linux_amd64
│ └── terraform-provider-aws_v4.57.1_x5
├── .terraform.lock.hcl
├── README.md
├── aws_asg.tf
├── aws_codepipeline.tf
├── aws_data.tf
├── aws_ec2.tf
├── aws_iam.tf
├── aws_imagebuilder.tf
├── aws_s3.tf
├── aws_vpc.tf
├── lambda_function.py
├── lambda_function.py.zip
├── provider.tf
├── terraform.tfstate
└── terraform.tfstate.backup
構築
IAMを設定
1. AWSのコンソールにサインインし、Basic_Groupユーザーグループに以下ポリシーをアタッチ
– AmazonS3FullAccess
– AutoScalingFullAccess
– AWSCodeCommitFullAccess
– AWSCodeDeployFullAccess
– AWSCodePipeline_FullAccess
– AWSImageBuilderFullAccess
– AWSLambda_FullAccess
1. vi ~/terraform-blog/aws_iam.tf
でROLE_BLOGロールのポリシーを追加
#----------------------------------------
# IAMロールを作成
#----------------------------------------
resource "aws_iam_role" "ROLE_BLOG" {
name = "ROLE_BLOG"
assume_role_policy = "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}"
description = "Allows EC2 instances to call AWS services on your behalf."
path = "/"
managed_policy_arns = [
"arn:aws:iam::aws:policy/AmazonEC2FullAccess",
"arn:aws:iam::aws:policy/AmazonSSMFullAccess",
# 追加
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AWSCodePipeline_FullAccess",
"arn:aws:iam::aws:policy/AWSImageBuilderFullAccess"
]
tags = {
Name = "ROLE_BLOG"
}
}
CodeCommitを設定
まずはドキュメントルートを自動デプロイするため以下システムを構築していきます。
※①~④の説明は前編を確認して下さい。
1. BlogUserのセキュリティ認証情報画面で、AWS CodeCommitのSSH公開キーに作成済みのSSH公開鍵をアップロードして、SSHキーIDをメモ
1. WSL2でvi ~/terraform-blog/aws_codepipeline.tf
を実行し、CodeCommitの設定を追記
resource "aws_codecommit_repository" "BlogCodecommitRepo" {
repository_name = "BlogCodecommitRepo"
tags = {
Name = "BlogCodecommitRepo"
}
}
1. Terraformを実行し、CodeCommitにリポジトリを作成
terraform planterraform apply
1. CMSサーバー(EC2)とCMSサーバー(ASG)にSSHし、AWS CodeCommitのSSH公開キーに登録した公開鍵をauthorized_keysに追記し、秘密鍵を配置
以下は秘密鍵がid_rsaの場合のディレクトリ例です。
[root@ip-10-0-0-10 .ssh]# ls -al合計 8drwx------ 2 root root 43 5月 16 10:26 .dr-xr-x--- 6 root root 185 5月 16 10:25 ..-rw------- 1 root root 553 5月 16 09:45 authorized_keys-rw------- 1 root root 1675 5月 16 10:25 id_rsa
1. vi ~/.ssh/config
でSSHの設定ファイルを作成
以下は秘密鍵がid_rsaの場合の設定ファイルです。
Host git-codecommit.*.amazonaws.com
User (1でメモしたSSHキーIDをここに入力)
IdentityFile ~/.ssh/id_rsa
1. chmod 600 ~/.ssh/config
でSSHの設定ファイルの権限を変更
drwx------ 2 root root 76 5月 12 10:35 .dr-xr-x--- 6 root root 203 5月 12 10:35 ..-rw------- 1 root root 553 5月 8 10:19 authorized_keys-rw------- 1 root root 89 5月 8 10:58 config-rw------- 1 root root 1675 5月 2 09:56 id_rsa-rw-r--r-- 1 root root 1230 5月 8 13:53 known_hosts
1. CMSサーバー(EC2)にSSHし、vi /var/www/html/appspec.yml
で自動デプロイするための設定ファイルを作成
version: 0.0os: linuxfiles: - source: / destination: /var/www/htmlfile_exists_behavior: OVERWRITE
1. CodeCommitのリポジトリにドキュメントルート配下をpush
cd /var/www/html/yum install -y gitgit init .git add .git commit -m "first push"git push --set-upstream ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/BlogCodecommitRepo master
※以降は以下のコマンドでCodeCommitにpushします。
cd /var/www/html/git add .git commit -m "change config"git push
CodeDeployを設定
1. WSL2でvi ~/terraform-blog/aws_codepipeline.tf
を実行し、CodeDeployの設定を追記
#----------------------------------------
# CodeDeployのアプリケーションを作成
#----------------------------------------
resource "aws_codedeploy_app" "BlogCodedeployApp" {
name = "BlogCodedeployApp"
compute_platform = "Server"
tags = {
Name = "BlogCodedeployApp"
}
}
#----------------------------------------
# CodeDeployのデプロイグループを作成
#----------------------------------------
resource "aws_codedeploy_deployment_group" "BlogCodedeployDeployGroup" {
app_name = aws_codedeploy_app.BlogCodedeployApp.name
deployment_group_name = "BlogCodedeployDeployGroup"
service_role_arn = aws_iam_role.CodeDeployServiceRole.arn
deployment_config_name = "CodeDeployDefault.AllAtOnce"
autoscaling_groups = [aws_autoscaling_group.BlogASG.name]
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
deployment_style {
deployment_option = "WITHOUT_TRAFFIC_CONTROL"
deployment_type = "IN_PLACE"
}
tags = {
Name = "BlogCodedeployDeployGroup"
}
}
1. vi ~/terraform-blog/aws_iam.tf
でCodeDeployのサービスロールの設定を追記
#----------------------------------------
# IAMロールを作成
#----------------------------------------
resource "aws_iam_role" "CodeDeployServiceRole" {
name = "CodeDeployServiceRole"
assume_role_policy = "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codedeploy.amazonaws.com\"},\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}"
description = "Allows CodeDeploy to call AWS services such as Auto Scaling on your behalf."
path = "/"
managed_policy_arns = [
"arn:aws:iam::aws:policy/AWSCodeDeployFullAccess",
"arn:aws:iam::aws:policy/AmazonEC2FullAccess"
]
tags = {
Name = "CodeDeployServiceRole"
}
}
1. Terraformを実行し、CodeDeployを作成
terraform planterraform apply
1. CMSサーバー(EC2)とCMSサーバー(ASG)にSSHし、CodeDeployのエージェントをインストール
sudo su -yum -y install ruby wget gitwget -P /tmp https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/installchmod +x /tmp/install/tmp/install auto
1. CMSサーバー(ASG)にSSHし、WordPressのドキュメントルートをクローン
cd /var/www/html/rm -rf /var/www/html/*git clone ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/BlogCodecommitRepo .
CodePipelineを設定
1. vi ~/terraform-blog/aws_s3.tf
を実行し、データを格納するためのS3のバケットを作成
resource "aws_s3_bucket" "blogbucketwp" {
bucket = "blogbucketwp"
tags = {
Name = "blogbucketwp"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "blogasbssec" {
bucket = aws_s3_bucket.blogbucketwp.bucket
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
bucket_key_enabled = true
}
}
resource "aws_s3_bucket_request_payment_configuration" "blogbucketwpasbrpc" {
bucket = aws_s3_bucket.blogbucketwp.bucket
payer = "BucketOwner"
}
1. WSL2でvi ~/terraform-blog/aws_codepipeline.tf
を実行し、CodePipelineの設定を追記
#----------------------------------------
# CodeCommitのリポジトリを作成
#----------------------------------------
resource "aws_codecommit_repository" "BlogCodecommitRepo" {
repository_name = "BlogCodecommitRepo"
tags = {
Name = "BlogCodecommitRepo"
}
}
#----------------------------------------
# CodeDeployのアプリケーションを作成
#----------------------------------------
resource "aws_codedeploy_app" "BlogCodedeployApp" {
name = "BlogCodedeployApp"
compute_platform = "Server"
tags = {
Name = "BlogCodedeployApp"
}
}
#----------------------------------------
# CodeDeployのデプロイグループを作成
#----------------------------------------
resource "aws_codedeploy_deployment_group" "BlogCodedeployDeployGroup" {
app_name = aws_codedeploy_app.BlogCodedeployApp.name
deployment_group_name = "BlogCodedeployDeployGroup"
service_role_arn = aws_iam_role.CodeDeployServiceRole.arn
deployment_config_name = "CodeDeployDefault.AllAtOnce"
autoscaling_groups = [aws_autoscaling_group.BlogASG.name]
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
deployment_style {
deployment_option = "WITHOUT_TRAFFIC_CONTROL"
deployment_type = "IN_PLACE"
}
tags = {
Name = "BlogCodedeployDeployGroup"
}
}
#----------------------------------------
# CodePipelineを作成
#----------------------------------------
resource "aws_codepipeline" "BlogCodepipelinePipeline" {
name = "BlogCodepipelinePipeline"
role_arn = aws_iam_role.ServiceRoleCodePipeline.arn
stage {
name = "Source"
action {
name = "Source"
namespace = "SourceVariables"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
region = "ap-northeast-1"
output_artifacts = ["SourceArtifact"]
configuration = {
BranchName = "master"
OutputArtifactFormat = "CODE_ZIP"
PollForSourceChanges = "true"
RepositoryName = aws_codecommit_repository.BlogCodecommitRepo.repository_name
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
namespace = "DeployVariables"
category = "Deploy"
owner = "AWS"
provider = "CodeDeploy"
version = "1"
region = "ap-northeast-1"
input_artifacts = ["SourceArtifact"]
configuration = {
ApplicationName = aws_codedeploy_app.BlogCodedeployApp.name
DeploymentGroupName = aws_codedeploy_deployment_group.BlogCodedeployDeployGroup.deployment_group_name
}
}
}
artifact_store {
location = aws_s3_bucket.blogbucketwp.bucket
type = "S3"
}
tags = {
Name = "BlogCodepipelinePipeline"
}
}
1. vi ~/terraform-blog/aws_iam.tf
でCodePipelineのサービスロールの設定を追記
#----------------------------------------
# IAMロールを作成
#----------------------------------------]
resource "aws_iam_role" "ServiceRoleCodePipeline" {
name = "ServiceRoleCodePipeline"
assume_role_policy = "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"codepipeline.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}"
description = ""
path = "/service-role/"
managed_policy_arns = [
"arn:aws:iam::aws:policy/AWSCodePipeline_FullAccess",
"arn:aws:iam::aws:policy/AWSCodeCommitFullAccess",
"arn:aws:iam::aws:policy/AWSCodeDeployFullAccess",
"arn:aws:iam::aws:policy/AWSLambda_FullAccess",
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AWSImageBuilderFullAccess",
"arn:aws:iam::aws:policy/AmazonEC2FullAccess"
]
tags = {
Name = "ServiceRoleCodePipeline"
}
}
1. Terraformを実行し、CodePipelineを作成
terraform planterraform apply
1. CodePipelineのSourceとDeployが成功することを確認
自動デプロイの動作確認
1. CMSサーバー(EC2)にSSHし、権限を変更
sudo chmod 777 -R /var/www/html/wp-content/*
1. CMSサーバー(EC2)の管理画面のテーマエディターで背景色を修正
以下はデフォルトのテーマTwenty Twenty-Oneのstyle.cssのbodyの背景色を白色に修正した例です。
1. CMSサーバー(ASG)にブラウザからアクセスし、背景色がデフォルトであることを確認
1. CMSサーバー(EC2)にSSHし、ドキュメントルート配下をCodeCommitにpush
sudo su -cd /var/www/htmlgit add .git commit -m "change config"git push
1. CMSサーバー(ASG)にブラウザからアクセスし、背景色を修正されていることを確認
※CodePipelineが処理中であれば反映されていないことがあるため、5分程度おいて再度確認してください。
EC2 Image Builderを設定
1. WSL2でvi ~/terraform-blog/aws_data.tf
を実行し、アカウント情報を取得する設定を追記
data "aws_caller_identity" "current" {}
1. vi ~/terraform-blog/aws_imagebuilder.tf
を実行し、EC2 Image Builderの設定を追記
#----------------------------------------
# EC2 Image Builderのビルド用コンポーネントを作成
#----------------------------------------
resource "aws_imagebuilder_component" "BlogBuildComponent" {
name = "BlogBuildComponent"
platform = "Linux"
supported_os_versions = ["Amazon Linux 2"]
version = "1.0.0"
data = "name: HelloWorldTestingDocument\ndescription: This is hello world testing document.\nschemaVersion: 1.0\n\nphases:\n - name: build\n steps:\n - name: HelloWorldStep\n action: ExecuteBash\n inputs:\n commands:\n - echo \"Hello World! Build.\"\n\n - name: validate\n steps:\n - name: HelloWorldStep\n action: ExecuteBash\n inputs:\n commands:\n - echo \"Hello World! Validate.\"\n\n - name: test\n steps:\n - name: HelloWorldStep\n action: ExecuteBash\n inputs:\n commands:\n - echo \"Hello World! Test.\"\n"
tags = {
Name = "BlogBuildComponent"
}
}
#----------------------------------------
# EC2 Image Builderのテスト用コンポーネントを作成
#----------------------------------------
resource "aws_imagebuilder_component" "BlogTestComponent" {
name = "BlogTestComponent"
platform = "Linux"
supported_os_versions = ["Amazon Linux 2"]
version = "1.0.0"
data = "name: HelloWorldTestingDocument\ndescription: This is hello world testing document.\nschemaVersion: 1.0\n\nphases:\n - name: test\n steps:\n - name: HelloWorldStep\n action: ExecuteBash\n inputs:\n commands:\n - echo \"Hello World! Test.\"\n"
tags = {
Name = "BlogTestComponent"
}
}
#----------------------------------------
# EC2 Image Builderのイメージレシピを作成
#----------------------------------------
resource "aws_imagebuilder_image_recipe" "BlogImageRecipe" {
name = "BlogImageRecipe"
parent_image = aws_ami_from_instance.BlogAMI.id
version = "1.0.0"
working_directory = "/tmp"
block_device_mapping {
device_name = "/dev/xvda"
ebs {
delete_on_termination = true
encrypted = false
volume_size = 8
volume_type = "gp2"
}
}
systems_manager_agent {
uninstall_after_build = false
}
component {
component_arn = aws_imagebuilder_component.BlogBuildComponent.arn
}
component {
component_arn = aws_imagebuilder_component.BlogTestComponent.arn
}
tags = {
Name = "BlogImageRecipe"
}
}
#----------------------------------------
# EC2 Image Builderのイメージレシピを作成
#----------------------------------------
resource "aws_imagebuilder_infrastructure_configuration" "BlogInfra" {
name = "BlogInfra"
instance_profile_name = aws_iam_role.ROLE_BLOG.name
instance_types = ["t2.micro"]
key_pair = "KEY_BlogSample"
security_group_ids = [aws_security_group.sg_blog.id]
subnet_id = aws_subnet.pub_subnet1a_blog.id
terminate_instance_on_failure = true
tags = {
Name = "BlogInfra"
}
}
#----------------------------------------
# EC2 Image Builderのディストリビューションを作成
#----------------------------------------
resource "aws_imagebuilder_distribution_configuration" "BlogDist" {
name = "BlogDist"
distribution {
region = "ap-northeast-1"
ami_distribution_configuration {
name = "BlogAMI{{imagebuilder:buildDate}}"
ami_tags = {
Name = "BlogImageBuilderAMI"
}
}
launch_template_configuration {
account_id = data.aws_caller_identity.current.id
default = true
launch_template_id = aws_launch_template.BlogTemplate.id
}
}
tags = {
Name = "BlogDist"
}
}
#----------------------------------------
# EC2 Image Builderのイメージパイプラインを作成
#----------------------------------------
resource "aws_imagebuilder_image_pipeline" "BlogImagePipeline" {
name = "BlogImagePipeline"
status = "ENABLED"
distribution_configuration_arn = aws_imagebuilder_distribution_configuration.BlogDist.arn
enhanced_image_metadata_enabled = true
image_recipe_arn = aws_imagebuilder_image_recipe.BlogImageRecipe.arn
infrastructure_configuration_arn = aws_imagebuilder_infrastructure_configuration.BlogInfra.arn
image_tests_configuration {
image_tests_enabled = true
timeout_minutes = 720
}
tags = {
Name = "BlogImagePipeline"
}
}
1. Terraformを実行し、イメージパイプラインを作成
terraform planterraform apply
1. イメージパイプラインを実行し、動作確認
以下のようにエラーが出力されていないことを確認します。
CodePipelineでEC2 Image Builderを呼び出す
1. WSL2でvi ~/terraform-blog/lambda_function.py
を実行し、EC2 Image Builderを呼び出すLambdaのソースコードを作成
import boto3
import logging
import json
import os
import traceback
logger = logging.getLogger()
logger.setLevel(logging.INFO)
codepipeline_client = boto3.client('codepipeline')
imagebuilder_client = boto3.client('imagebuilder')
# AMI作成の成功時の処理
def put_job_success(job_id):
logger.info('Putting job success')
codepipeline_client.put_job_success_result(jobId=job_id)
# AMI作成中の時の処理
def continue_job_later(job_id,image_build_version_arn):
logger.info('Putting job continuation')
continuation_token = json.dumps({'ImageBuildVersionArn':image_build_version_arn})
codepipeline_client.put_job_success_result(
jobId=job_id,
continuationToken=continuation_token
)
# AMI作成の失敗時の処理
def put_job_failure(job_id, err):
logger.error('Putting job failed')
message = str(err)
codepipeline_client.put_job_failure_result(
jobId=job_id,
failureDetails={
'type': 'JobFailed',
'message': message
}
)
# codepipelineからlambda_functionを呼び出し
def lambda_handler(event, context):
try:
job_id = event['CodePipeline.job']['id']
job_data = event['CodePipeline.job']['data']
image_pipeline_arn = os.environ['IMAGE_PIPELINE_ARN']
pipeline_name = os.environ['CODEPIPELINE_NAME']
logger.info('ImagePipelineArn is %s', image_pipeline_arn)
logger.info('CodePipeline Event is %s',event['CodePipeline.job'])
# 継続トークンの有無を確認
if 'continuationToken' in job_data:
continuation_token = json.loads(job_data['continuationToken'])
image_build_version_arn = continuation_token['ImageBuildVersionArn']
logger.info('ImageBuilderVersionArn is %s', image_build_version_arn)
# ビルドの状態を取得
response = imagebuilder_client.get_image(
imageBuildVersionArn = image_build_version_arn
)
build_status = response['image']['state']['status']
logger.info('ImageBuild Status is %s',build_status)
# 処理の結果が成功なら状態をAVAILABLEに遷移
if build_status == 'AVAILABLE':
put_job_success(job_id)
# 処理の結果が失敗なら状態をFAILEDに遷移
elif build_status == 'FAILED':
errmsg='Build Error'
put_job_failure(job_id, errmsg)
# 処理が継続中の場合continue_job_later関数を呼び出す
else:
continue_job_later(job_id,image_build_version_arn)
else:
# ビルドを実行
response = imagebuilder_client.start_image_pipeline_execution(
imagePipelineArn=image_pipeline_arn
)
image_build_version_arn = response['imageBuildVersionArn']
logger.info('imageBuildVersionArn is %s', image_build_version_arn)
continue_job_later(job_id,image_build_version_arn)
# 例外処理
except Exception as err:
logger.error('Function exception: %s', err)
traceback.print_exc()
put_job_failure(job_id, 'Function exception: ' + str(err))
logger.info('Function complete')
return "Complete."
1. Lambdaのソースコードをzip形式で圧縮
cd ~/terraform-blog/sudo zip lambda_function.py.zip lambda_function.py
1. vi ~/terraform-blog/aws_s3.tf
を実行し、Lambdaのソースコードを保持するS3の設定を追記
resource "aws_s3_object" "lambdacode" {
bucket = aws_s3_bucket.blogbucketwp.bucket
key = "lambda_function.py.zip"
source = "~/terraform-blog/lambda_function.py.zip"
etag = filemd5("~/terraform-blog/lambda_function.py.zip")
}
1. Terraformを実行し、Lambdaのソースコードを保持するS3を作成
terraform planterraform apply
1. vi ~/terraform-blog/aws_codepipeline.tf
を実行し、Lambdaリソースを作成する設定とLambdaを呼び出す設定を追記するためファイルを書き換える
#----------------------------------------
# CodeCommitのリポジトリを作成
#----------------------------------------
resource "aws_codecommit_repository" "BlogCodecommitRepo" {
repository_name = "BlogCodecommitRepo"
tags = {
Name = "BlogCodecommitRepo"
}
}
#----------------------------------------
# CodeDeployのアプリケーションを作成
#----------------------------------------
resource "aws_codedeploy_app" "BlogCodedeployApp" {
name = "BlogCodedeployApp"
compute_platform = "Server"
tags = {
Name = "BlogCodedeployApp"
}
}
#----------------------------------------
# CodeDeployのデプロイグループを作成
#----------------------------------------
resource "aws_codedeploy_deployment_group" "BlogCodedeployDeployGroup" {
app_name = aws_codedeploy_app.BlogCodedeployApp.name
deployment_group_name = "BlogCodedeployDeployGroup"
service_role_arn = aws_iam_role.CodeDeployServiceRole.arn
deployment_config_name = "CodeDeployDefault.AllAtOnce"
autoscaling_groups = [aws_autoscaling_group.BlogASG.name]
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
deployment_style {
deployment_option = "WITHOUT_TRAFFIC_CONTROL"
deployment_type = "IN_PLACE"
}
tags = {
Name = "BlogCodedeployDeployGroup"
}
}
#----------------------------------------
# Lambdaを作成
#----------------------------------------
resource "aws_lambda_function" "BlogImageBuilderFunction" {
architectures = ["x86_64"]
s3_bucket = aws_s3_bucket.blogbucketwp.bucket
s3_key = "lambda_function.py.zip"
function_name = "BlogImageBuilderFunction"
handler = "lambda_function.lambda_handler"
memory_size = 128
package_type = "Zip"
reserved_concurrent_executions = -1
role = aws_iam_role.ServiceRoleLambda.arn
runtime = "python3.9"
timeout = 3
tracing_config {
mode = "PassThrough"
}
ephemeral_storage {
size = 512
}
environment {
variables = {
CODEPIPELINE_NAME = "BlogCodepipelinePipeline"
IMAGE_PIPELINE_ARN = aws_imagebuilder_image_pipeline.BlogImagePipeline.arn
}
}
tags = {
Name = "BlogImageBuilderFunction"
}
}
#----------------------------------------
# CodePipelineを作成
#----------------------------------------
resource "aws_codepipeline" "BlogCodepipelinePipeline" {
name = "BlogCodepipelinePipeline"
role_arn = aws_iam_role.ServiceRoleCodePipeline.arn
stage {
name = "Source"
action {
name = "Source"
namespace = "SourceVariables"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
region = "ap-northeast-1"
output_artifacts = ["SourceArtifact"]
configuration = {
BranchName = "master"
OutputArtifactFormat = "CODE_ZIP"
PollForSourceChanges = "true"
RepositoryName = aws_codecommit_repository.BlogCodecommitRepo.repository_name
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
namespace = "DeployVariables"
category = "Deploy"
owner = "AWS"
provider = "CodeDeploy"
version = "1"
region = "ap-northeast-1"
input_artifacts = ["SourceArtifact"]
configuration = {
ApplicationName = aws_codedeploy_app.BlogCodedeployApp.name
DeploymentGroupName = aws_codedeploy_deployment_group.BlogCodedeployDeployGroup.deployment_group_name
}
}
}
stage {
name = "Invoke"
action {
name = aws_lambda_function.BlogImageBuilderFunction.function_name
namespace = "InvokeVariables"
category = "Invoke"
owner = "AWS"
provider = "Lambda"
version = "1"
region = "ap-northeast-1"
input_artifacts = []
output_artifacts = []
configuration = {
FunctionName = aws_lambda_function.BlogImageBuilderFunction.function_name
}
}
}
artifact_store {
location = aws_s3_bucket.blogbucketwp.bucket
type = "S3"
}
tags = {
Name = "BlogCodepipelinePipeline"
}
}
1. Terraformを実行し、CodePipelineを作成
terraform planterraform apply
1. 作成したCodePipelineを実行し、動作確認
動作確認
1. CMSサーバー(EC2)の管理画面のテーマエディターで背景色を修正
以下はデフォルトのテーマTwenty Twenty-Oneのstyle.css
のbodyの背景色を黒色に修正した例です。
1. CMSサーバー(ASG)にブラウザからアクセスし、背景色が白色であることを確認
1. CMSサーバー(EC2)にSSHし、ドキュメントルート配下をCodeCommitにpush
sudo su -cd /var/www/htmlgit add .git commit -m "change config"git push
1. CMSサーバー(ASG)にブラウザからアクセスし、背景色を修正されていることを確認
※CodePipelineが処理中であれば反映されていないことがあるため、30分程度おいて再度確認してください。
改善点
今回は権限を非常に緩く設定しましたが、実際に使用する際は適宜読み替えて権限を設定してください。
バージョン管理もgitを使ったことがない人でも使えるようにコマンドを固定していますが、コンフリクトが発生する等のリスクがあるため、gitを使える人はブランチを切ったりコミットメッセージを変更する等適宜読み替えてください。
また、イメージの管理にEC2 Image Builderを使用しましたが、ゴールデンイメージ作成に30分程度かかるため、ビルドとテストを行う必要が無ければAWS Backupを使用する等の別の方法を使用した方が良いです。
IAMをTerraformでresourceで管理していますが、data sourceを使用した方がスクラップ&ビルドしやすいです。
所感
今回はイメージの管理を自動化しましたが、EC2からAMIを取得する作業や、AMIが正常に取得しているかの確認をする作業がマネージドサービスで自動化できるため非常に便利でした。
前編と合わせて、ドキュメントルート配下の自動デプロイ、AMI管理の自動化、Ansibleによるプロビジョニングの自動化、Terraformによるインフラのコード化等の様々なツールを紹介しましたが、全てのツールを使用しなくても何か一つでも試すと作業が快適になると思います。
前編と後編を合わせるとかなりボリュームがありますが、ここまで読んで頂きありがとうございました。