こんにちは、クラウドCoEの西村です。
前回の記事では、Infrastructure as Code(以下、IaCと略します。)について紹介させていただきました。IaCを導入する目的やメリットについてはご理解いただけたかと思います。また、その中でIaCを実現するためのAWSサービスとして、AWS CloudFormationについて簡単に触れています。概念を理解しても、実際にインフラをコード化するイメージがわかない方もいらっしゃるかと思いますので、導入部分についてご紹介したいと思います。
ということで、今回のBTC Tech Blogの内容は「Infrastructure as Codeを理解する(第2回)AWS CloudFormationの導入」です。
本記事ではAWS CloudFormationはどういったサービスなのか、基本的な使い方と注意点についてまとめていきたいと思います。
AWS CloudFormationは、テンプレートを使用して、アプリケーションに必要とされるAWSリソースをプロビジョニングできるサービスです。
プロビジョニングされたAWSリソースに対する変更も可能で、ソフトウェアの管理と同じ方法でインフラを管理できます。コード化することで、バージョン管理やコードの共有が可能となり、共同作業がしやすくなります。
また、AWS CloudFormationの利用に対する追加料金は発生しません。
AWS CloudFormationには、以下のような特徴があります。
特に、テンプレート化したことで実際の環境とテンプレート間で差異が生じることはよくありますので、ChangeSetの機能は便利です。
AWS CloudFormationは多くのAWSサービスをサポートしていますが、すべてのサービスをコードに落とし込めばいいというわけでもないと思います。また、テンプレートは一枚岩で作成するのではなく、ライフサイクル別に分割し、ネストスタック形式で実装すべきです。
AWS CloudFormationを利用する場合の全体像のイメージは以下の通りです。
YAML/JSON形式でテンプレートを作成(リソースを定義)し、AWS CloudFormationを利用してスタックと呼ばれる単位でリソース群をプロビジョニングします。
テンプレートはAWS CloudFormationの心臓部となるもので、スタックの設計図です。
リソースを定義し、どのように起動するかをJSON/YAML形式で記述します。
リソース間の依存関係はAWS CloudFormationが自動で判別しますが、テンプレート上では依存関係がない形で定義していても、実際のリソース間に依存関係が必要な場合は、後述する「DependsOn」などで明確に前後関係を作る必要があります。
--- AWSTemplateFormatVersion: "version date" Description: String Metadata: template metadata Parameters: set of parameters Mappings: set of mappings Conditions: set of conditions Transform: set of transforms Resources: set of resources Outputs: set of outputs
多用する要素はParameters、Resources、Outputsですので、これらを取り入れたサンプルテンプレートを以下に記載します。
--- AWSTemplateFormatVersion: 2010-09-09 Description: Creates New VPC Parameters: VpcCidr: AllowedPattern: "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(1[6-9]|2[0-8]))$" ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.0.0.0/16 Description: CIDR block for the VPC Type: String VpcTenancy: AllowedValues: - default - dedicated Default: default Description: The allowed tenancy of instances launched into the VPC Type: String PublicSubnetCidr: AllowedPattern: "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(1[6-9]|2[0-8]))$" ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Default: 10.0.10.0/24 Description: CIDR block for Public subnet Type: String Resources: Vpc: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Join [ '', [ 'Vpc / ', !Ref 'AWS::AccountId' ] ] PublicSubnet: Type: AWS::EC2::Subnet Properties: CidrBlock: !Ref PublicSubnetCidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Join [ '', [ 'PublicSubnet / ', !Ref 'AWS::AccountId' ] ] - Key: SubnetType Value: Public VpcId: !Ref Vpc InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Join [ '', [ 'InternetGateway / ', !Ref 'AWS::AccountId' ] ] AttachInternetGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref Vpc PublicRoute: Type: AWS::EC2::Route DependsOn: AttachInternetGateway Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable Properties: Tags: - Key: Name Value: !Join [ '', [ 'PublicRouteTable / ', !Ref 'AWS::AccountId' ] ] - Key: Network Value: Public VpcId: !Ref Vpc PublicRouteTableAssociation0: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable Outputs: Vpc: Value: !Ref Vpc VpcCidr: Value: !Ref VpcCidr PublicSubnet: Value: !Ref PublicSubnet
Parameterで入力変数として受け取った値をResourceセクションの組み込み関数「!Ref」などで受け取っています。
「!Join」は一連の文字列を結合する組み込み関数、「AWS::AccountId」はアカウントIDを取得する疑似パラメータです。
また、OutputではParameterやResourceで定義したリソース情報を出力できます。
多種多様な疑似パラメータや組み込み関数も用意されていますので、AWS CloudFormationの扱いに慣れてきたら試してみるとよいかと思います。
テンプレートからプロビジョニングされるリソース群で、スタック単位でリソースの管理が可能です。定義されたリソースを一斉に作成/削除することができるため、運用負荷を軽減できます。
スタックの展開にはマネジメントコンソール、コマンドラインツール、各種SDKが利用できますので、慣れている方法で実行することをお勧めします。
AWS CloudFormationを利用してリソースを作成した場合、テンプレートで定義したリソースについては、テンプレートを更新していくことになります。
基本的にはマネジメントコンソールからリソースの設定を変更しません。
マネジメントコンソールから設定を変更し、テンプレートに変更を反映していない状態でスタックを展開してしまうと、デグレが発生したり、エラーにより更新ができなくなってしまったりすることがあります。
また、テンプレートは一枚岩で作成するのではなく、「依存関係」、「ライフサイクル」、「ステートレス/ステートフル」、「所有権」によって分割することが望ましいです。
テンプレートを分割して運用していく際に使用する機能としては、「クロススタック参照(Cross Stack Reference)」と「ネストスタック(Nested Stacks)」が用意されています。
特に定義するリソースが増加し、テンプレートが巨大化していく可能性のある場合はこれらの機能を活用しましょう。
これまでAWS CloudFormationの基本について説明してきました。
インフラをコード化することで全く同じ構成のインフラを簡単に再現できたり、設定パラメータをコードとして管理したりすることができたりといったメリットがあります。
しかし、適切にテンプレートを管理・運用していかないと逆に運用負荷が上がってしまうこともありますので、しっかりと理解した上で活用していただければと思います。
では、また次の記事でお会いしましょう。