CloudFormation
CloudFormationはAWS上で構築するインフラ作業を自動化するサービスである。 AWS上に構築するリソースをテンプレートファイルとして定義し、それをCloudFormationに取り込ませインフラを構築していく。 取り込んだテンプレートはCloudFormation上でスタックとして管理され、以降内容の更新が可能。 テンプレートはjsonもしくはymlで定義する。 ここではymlで定義する前提で説明する。
使い方
マネジメントコンソール上からCloudFormationのサービスを選び、作成したテンプレートファイルをアップロードする。
テンプレート
テンプレートの記述ルール。 テンプレートは以下4つの項目を定義する。
Parameters: CloudFormationを使用する際の引数を定義。 画面上から入力できるものもあれば、テンプレートをネストした際に親テンプレートから引き継ぐことが可能。 Mappings: CloudFormation内で使用する定数を定義。 Resources: CloudFormationで作成するリソースを定義。 Outputs: CloudFormation実行後に出力する項目を定義。
パラメータ定義
テンプレートに渡すパラメータの定義。
定義
変数名と型を定義する。
Parameters: Prefix : {"Type" : "String"} AccountId : {"Type" : "Number"}
参照
組み込み関数のRefで参照する。 ※パラメータに限らず定義した変数は基本的にRefで参照可能。
{"Ref" : "Prefix"}
マッピング定義
テンプレート内でキーと値をセットで定数を定義する。
定義
3階層でキーと値を定義する。
Mappings: Develop: Prefix: Lerge: "Develop" TempleteURL: VPC: "s3-ap-northeast-1.amazonaws.com/templete/01_vpc.yml" EC2: "s3-ap-northeast-1.amazonaws.com/templete/02_ec2.yml"
参照
組み込み関数Fn::FindInMapを使用して参照する。
{"Fn::FindInMap": [ Develop, Prefix, Lerge ] }
リソース定義
構築するAWSリソースを定義する。
※コードは下記のサンプル参照
出力項目定義
テンプレートを適用した結果の変数を出力する。 出力した内容はマネジメントコンソールで確認する。 ネストしていた子スタックが値を出力した場合は親スタックで参照可能。
定義
出力変数名を定義し、Valueに組み込み関数のRefで値を設定する。
Outputs: VPCId: Value: { Ref : VPC } EIP: Value: { Ref : EIP }
ネストについて
ここでいうCloudFormationのネストとはテンプレート内で別のテンプレートを呼び出すことである。 このテンプレートからスタックを作成した際に自動で別のスタックが作成される。 大規模なインフラを構築する際にはネストを利用してテンプレートを記述することを勧める。 例えば、共通項目を別のテンプレートとして作成することで流用が可能となり保守性が上がる。 また、一つのテンプレートに対して記述するリソース定義の量を減らすことで可読性が上がる。
定義の仕方
リソース定義としてスタックを定義する。
Mappings: Develop: TempleteURL: VPC: "https://s3-ap-northeast-1.amazonaws.com/templete/01_vpc.yml" Prefix: Upper: Develop- Lower: develop- VPC: CidrBlock: "10.254" VPN: CidrBlock: "192.168" Resources: VPC: Type: AWS::CloudFormation::Stack DeletionPolicy: Delete Properties: TemplateURL: {"Fn::FindInMap": [ Develop, TempleteURL, VPC ] } Parameters: PrefixUpper: {"Fn::FindInMap": [ Develop, Prefix, Upper ] } CidrBlock: {"Fn::FindInMap": [ Develop, VPC, CidrBlock ] } VPNCidrBlock: {"Fn::FindInMap": [ Develop, VPN, CidrBlock ] }
削除ポリシーについて
スタックを削除したときのリソースの振る舞いを設定する項目。 リソースを作成するときに設定することができる。 デフォルトだとスタックを削除したときに一緒にリソースも削除する。 基本的にデフォルトのままで問題ない。 ※誤ってスタック自体が削除されないようユーザー管理は徹底すること
ポリシー | 振る舞い |
Delete | 削除する。※デフォルト |
Retain | 削除しない。 |
Snapshot | スナップショットを取得してから削除する。 |
サンプル
以下、リソースを作成する際のサンプルである。 このサンプルは実際にインフラ構築を実施した際に使用したテンプレートを元にしている。 このためマップやパラメータの参照が多くなっているがこの部分は固定値にしてしまっても良い。
Stack
VPC: Type: AWS::CloudFormation::Stack DeletionPolicy: Delete Properties: TemplateURL: {"Fn::FindInMap": [ Develop, TempleteURL, VPC ] } Parameters: PrefixLarge: {"Fn::FindInMap": [ Develop, Prefix, Large ] } CidrBlock: {"Fn::FindInMap": [ Develop, VPC, CidrBlock ] }
VPC
VPC: Type: AWS::EC2::VPC Properties: CidrBlock: {"Fn::Join" : ["", [{"Ref" : "CidrBlock"}, ".0.0/16"]]} EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default Tags: - Key: Name Value: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "VPC"]]} Subnet: Type: AWS::EC2::Subnet Properties: VpcId: { Ref: VPC } AvailabilityZone: ap-northeast-1a CidrBlock: {"Fn::Join" : ["", [{"Ref" : "CidrBlock"}, ".0.0/24"]]} Tags: - Key: Name Value: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "Subnet"]]}
EC2(SecurityGroup)
セキュリティグループはルールを設定する方法が2つある。 セキュリティグループ自身を作成する際に指定する方法と後付けをする方法。 他のセキュリティグループを参照するルールを設定する場合は後付けを勧める。
WebServerSG: Type: AWS::EC2::SecurityGroup Properties: VpcId: { Ref: VPC } GroupDescription: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "WebServer-SG"]]} Tags: - Key: Name Value: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "WebServer-SG"]]} SecurityGroupEgress: - { IpProtocol: tcp, FromPort: 80, ToPort: 80, CidrIp: 0.0.0.0/0 } - { IpProtocol: tcp, FromPort: 443, ToPort: 443, CidrIp: 0.0.0.0/0 } - { IpProtocol: udp, FromPort: 53, ToPort: 53, CidrIp: 0.0.0.0/0 } - { IpProtocol: udp, FromPort: 123, ToPort: 123, CidrIp: 0.0.0.0/0 } WebServerSGIngress: Type: AWS::EC2::SecurityGroupIngress Properties: { GroupId: {Ref : WebServerSG}, IpProtocol: tcp, FromPort: 22,ToPort: 22, CidrIp: 0.0.0.0/0 } WebServerSGEgress: Type: AWS::EC2::SecurityGroupEgress Properties: { GroupId: {Ref : WebServerSG}, IpProtocol: tcp, FromPort: 443, ToPort: 443, SourceSecurityGroupId: { Ref : ApiServerSG } }
EC2(Instance/ELB)
WebServerLB: Type: AWS::ElasticLoadBalancing::LoadBalancer DeletionPolicy: Delete Properties: LoadBalancerName: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "WebServer-LB"]]} Subnets: - { Ref : PublicSubnetA } - { Ref : PublicSubnetC } Scheme: internal CrossZone: TRUE ConnectionDrainingPolicy: Enabled: TRUE Timeout: 5 HealthCheck: HealthyThreshold: 2 Interval: 30 Target: HTTP:8080/index.html Timeout: 5 UnhealthyThreshold: 2 SecurityGroups: - { Ref : WebServerLBSG } Listeners: - InstancePort: 8080 LoadBalancerPort: 80 Protocol: HTTP InstanceProtocol: HTTP - InstancePort: 8080 LoadBalancerPort: 443 Protocol: HTTPS InstanceProtocol: HTTP SSLCertificateId: {Ref : SSLCertificateId} PolicyNames: - AppCookieStickinessPolicy AppCookieStickinessPolicy: - PolicyName: AppCookieStickinessPolicy CookieName: JSESSIONID AccessLoggingPolicy: S3BucketName: {"Fn::Join" : ["", ["system-", {"Ref" : "Prefix"}, "logs"]]} S3BucketPrefix: loadbalancerLog Enabled: true EmitInterval: 5
S3
s3contents: Type: AWS::S3::Bucket Properties: BucketName: {"Fn::Join" : ["", ["systemtest-",{"Ref" : "Prefix"}, "contents"]]} AccessControl: BucketOwnerFullControl s3contentsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: s3contents PolicyDocument: Statement : - Effect: "Allow" Sid: "IPAllow" Principal: "*" Action: - "s3:GetObject" Resource: {"Fn::Join" : ["", ["arn:aws:s3:::systemtest-", {"Ref" : "Prefix"}, "contents/*"]]} Condition: IpAddress: aws:SourceIp: { "Fn::FindInMap": [ Develop, Bucket, SourceIp ] }
SNS
SNS: Type: AWS::SNS::Topic Properties: DisplayName: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "system-sns"]]} TopicName: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "system-sns"]]}
SQS
QueuePushNotificationDeadLetterQueue: Type: AWS::SQS::Queue DeletionPolicy: Delete Properties: QueueName: {"Fn::Join" : ["", [{"Ref" : "PrefixUpper"}, "Push-Notification-Dead-Letter-Queue"]]} VisibilityTimeout: 30 QueuePushNotificationQueue: Type: AWS::SQS::Queue DeletionPolicy: Delete Properties: QueueName: {"Fn::Join" : ["", [{"Ref" : "PrefixUpper"}, "Push-Notification-Queue"]]} VisibilityTimeout: 30 ReceiveMessageWaitTimeSeconds: 20 RedrivePolicy: deadLetterTargetArn: {"Fn::GetAtt" : [ "QueuePushNotificationDeadLetterQueue" , "Arn" ]} maxReceiveCount: 1
RDS
RDSはパラメータグループやサブネットグループ(必要ならオプショングループも)のみ作成する。 インスタンスは手動で削除・復元をするためCloudFormationで管理しないことを勧める。
DBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription : {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "SubnetGroup"]]} SubnetIds: [{"Ref" : "PrivateSubnetA"}, {"Ref" : "PrivateSubnetC"}] ParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Description: {"Fn::Join" : ["", [{"Ref" : "Prefix"}, "pg"]]} Family: mysql5.6 Parameters: binlog_cache_size: 32768 binlog_format: MIXED character_set_client: utf8 character_set_connection: utf8 character_set_database: utf8 character_set_filesystem: utf8 character_set_results: utf8 character_set_server: utf8 collation_connection: utf8_general_ci explicit_defaults_for_timestamp: 1 general_log: 1 slow_query_log: 1 innodb_buffer_pool_size: "{DBInstanceClassMemory*3/4}" innodb_flush_method: O_DIRECT