😊
CloudFormationで環境構築を自動化する (CI/CDまでの道⑩)
はじめに
ついに「CI/CDまでの道」最終回となりました。
今回は前回作成したFargate
の環境構築をCloudFormation
でなるべく自動構築できるようにしていきます。
構築しているインフラ環境は以下となります。
青枠の部分は今回は手動で構築することにしました。
今後IaCする機会があれば記事を更新する予定です。
青枠の構築については第9回通りです。
CI/CDまでの道シリーズ
- rails6+mysqlのdocker環境構築 (CI/CDまでの道①)
- dockerにwebpacker環境構築(jquery, bootstrap5, vue) (CI/CDまでの道②)
- rails(docker)に必要なgemを追加する (CI/CDまでの道③)
- rails(docker)にnginxを導入する (CI/CDまでの道④)
- rails(docker)をproductionモードで起動してみる (CI/CDまでの道⑤)
- ec2にdocker-composeでrailsをデプロイする (CI/CDまでの道⑥)
- Fargateにrailsをデプロイする (CI/CDまでの道⑦)
- Rails(Docker)をCodeBuildでCIする (CI/CDまでの道⑧)
- CodeDeployでRails(Docker)をBlue/Greenデプロイする (CI/CDまでの道⑨)
- CloudFormationで環境構築を自動化する (CI/CDまでの道⑩)
環境
- wsl2 (ubuntu20.04)
- docker 20.10.9
- docker-compose 1.29.1
- git 2.25.1
- vscode
ネットワークの構築
vpc.yml
というファイルにネットワーク設定を書き足していきます。
ファイル分割は一度完成してから行うつもりです。
共通: スタックの起動
スタックをAWS CLIから実行します。
# 検証
$ aws cloudformation validate-template --template-body file://vpc.yml
# スタック作成
$ aws cloudformation create-stack --stack-name vpc --template-body file://vpc.yml
# スタック削除
$ aws cloudformation delete-stack --stack-name vpc
VPC
vpc.yml
Resources:
#=================================
# VPCの作成
#=================================
SampleVPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: 'false'
EnableDnsSupport: 'true'
Tags:
- Key: Name
Value: sample-vpc
サブネット
vpc.yml
#=================================
# サブネットの作成
#=================================
PublicSubnet01:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
CidrBlock: 10.0.0.0/20
MapPublicIpOnLaunch: true
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: sample-subnet-public01
PublicSubnet02:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
CidrBlock: 10.0.16.0/20
MapPublicIpOnLaunch: true
AvailabilityZone: ap-northeast-1c
Tags:
- Key: Name
Value: sample-subnet-public02
PrivateSubnet01:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
CidrBlock: 10.0.64.0/20
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: sample-subnet-private01
PrivateSubnet02:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
CidrBlock: 10.0.80.0/20
AvailabilityZone: ap-northeast-1c
Tags:
- Key: Name
Value: sample-subnet-private02
インターネットゲートウェイ
vpc.yml
#=================================
# インターネットゲートウェイの作成
#=================================
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: sample-igw
# InternetGatewayとVPCの接続
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref SampleVPC
ルートテーブル
vpc.yml
#=================================
# ルートテーブルの作成
#=================================
SampleRtPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SampleVPC
Tags:
- Key: Name
Value: sample-rt-public
# SubnetとRoutetableの関連付け
PublicRouteTableAssociation1a:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref SampleRtPublic
SubnetId: !Ref SamplePublicSubnet01
PublicRouteTableAssociation1c:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref SampleRtPublic
SubnetId: !Ref SamplePublicSubnet02
# Routeの指定
PublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
RouteTableId: !Ref SampleRtPublic
GatewayId: !Ref SampleIgw
セキュリティグループ
vpc.yml
#=================================
# セキュリティグループの作成
#=================================
SampleSgElb:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for load balancer
GroupName: sample-sg-elb
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: sample-sg-elb
VpcId: !Ref SampleVPC
SampleSgEcs:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ecs
GroupName: sample-sg-ecs
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: sample-sg-ecs
VpcId: !Ref SampleVPC
SampleSgDb:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for rds
GroupName: sample-sg-db
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: sample-sg-db
VpcId: !Ref SampleVPC
RDS
vpc.yml
#=================================
# RDSの作成
#=================================
# DBパラメーターグループ
SampleDBPg:
Type: AWS::RDS::DBParameterGroup
Properties:
Family: mysql8.0
Description: sample parameter group
Tags:
- Key: Name
Value: sample-db-pg
# DBサブネットグループ
SampleDBSubnet:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupName: sample-db-subnet
DBSubnetGroupDescription: sample db subnet
SubnetIds:
- !Ref SamplePrivateSubnet01
- !Ref SamplePrivateSubnet02
# DB
SampleDB:
Type: AWS::RDS::DBInstance
Properties:
AllocatedStorage : 20
DBInstanceClass: db.t2.micro
Port: 3306
StorageType: gp2
BackupRetentionPeriod: 7
MasterUsername: admin
MasterUserPassword: password
DBInstanceIdentifier: sample-db
Engine: mysql
EngineVersion: 8.0.23
DBSubnetGroupName: !Ref SampleDBSubnet
DBParameterGroupName: !Ref SampleDBPg
MultiAZ: true
VPCSecurityGroups:
- !Ref SampleSgDB
S3
vpc.yml
#=================================
# S3
#=================================
SampleS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: "[一意なバケット名]"
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
VersioningConfiguration:
Status: Enabled
バケットの名前はAWSでユニークな名前に変更してください。
ロードバランサー
vpc.yml
#=================================
# ロードバランサー
#=================================
SampleElb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: sample-elb
Scheme: internet-facing
SecurityGroups:
- !Ref SampleSgElb
Subnets:
- !Ref SamplePublicSubnet01
- !Ref SamplePublicSubnet02
Tags:
- Key: Name
Value: sample-elb
# ALBのターゲットグループの指定
BlueGreenTarget1:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: BlueGreenTarget1
TargetType: ip
Port: 80
Protocol: HTTP
HealthCheckPath : /test
VpcId: !Ref SampleVPC
BlueGreenTarget2:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: BlueGreenTarget2
TargetType: ip
Port: 80
Protocol: HTTP
HealthCheckPath : /test
VpcId: !Ref SampleVPC
# ALBのリスナーの指定
ALBListener1:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn:
!Ref BlueGreenTarget1
LoadBalancerArn:
!Ref SampleElb
Port: 80
Protocol: HTTP
ALBListener2:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn:
!Ref BlueGreenTarget2
LoadBalancerArn:
!Ref SampleElb
Port: 8080
Protocol: HTTP
ECR
vpc.yml
#=================================
# ECR
#=================================
SampleRails:
Type: AWS::ECR::Repository
Properties:
RepositoryName: sample-rails
SampleNginx:
Type: AWS::ECR::Repository
Properties:
RepositoryName: sample-nginx
ECS
vpc.yml
#=================================
# ECS
#=================================
# クラスター
ECSCluster:
Type: 'AWS::ECS::Cluster'
Properties:
ClusterName: sample-cluster
# ロググループ
ECSLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/ecs/logs/sample-ecs-group'
# タスク定義
ECSTaskDefinition:
Type: 'AWS::ECS::TaskDefinition'
Properties:
Cpu: 256
Memory: 512
ExecutionRoleArn: arn:aws:iam::[アカウントID]:role/ecsTaskExecutionRole
TaskRoleArn: arn:aws:iam::[アカウントID]:role/ecsTaskExecutionRole
Family: sample-ecs
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
# コンテナ追加
ContainerDefinitions:
- Name: rails
Image: [アカウントID].dkr.ecr.ap-northeast-1.amazonaws.com/sample-rails:staging
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSLogGroup
awslogs-region: ap-northeast-1
awslogs-stream-prefix: sample
MemoryReservation: 128
PortMappings:
- HostPort: 3000
Protocol: tcp
ContainerPort: 3000
Environment:
- Name: DB_USERNAME
Value: admin
- Name: DB_PASSWORD
Value: password
- Name: DB_DATABASE
Value: myapp
- Name: DB_HOST
Value: !GetAtt SampleDB.Endpoint.Address
- Name: SECRET_KEY_BASE
Value: [master.keyの値]
- Name: nginx
Image: [アカウントID].dkr.ecr.ap-northeast-1.amazonaws.com/sample-nginx:latest
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSLogGroup
awslogs-region: ap-northeast-1
awslogs-stream-prefix: sample
MemoryReservation: 128
PortMappings:
- HostPort: 80
Protocol: tcp
ContainerPort: 80
VolumesFrom:
- SourceContainer: rails
アカウントIDとmaster.keyの値を各自のものに置き換えてください。
その他
- Rails(latest, staging)とNginx(latest)のPush
- IAM (ecsTaskExecutionRole, CodeDeployRole)作成
- CodeBuild(build, test)作成
- ECSのサービス作成
- CodePipeline作成
- ACM(SSL証明書)作成
- Route53でレコード作成
この作業を記事通りに行うことで同じ環境が再現できるようになります
削除はECR
とS3
は中身があるのでコンソールから手作業で先に削除する必要があります。
おわりに
作成したものはこちらのリポジトリに用意しています。
今回は説明がほぼありませんが、いままでの設定をそのまま入力しているのでそれぞれのコンソールでの設定した値と見比べることで各項目が何を表しているか理解できると思います。
以上で「CI/CDまでの道」を終わります。
1か月かけて更新してきましたが1から調べてここまでやれたことに達成感を感じています。
次はRailsを使った個人開発に挑戦していきたいと思います。
Discussion