こんにちは。AWS CLIが好きな福島です。
はじめに
今回は、AWS CLIを使い、CloudFormationの複数のテンプレートで定義したParametersの値を1つのファイルで管理する方法をご紹介いたします。
AWS CLIを使ったCloudformationの操作については、以下にまとめているため、興味がありましたら、ご確認ください。
https://blog.serverworks.co.jp/2020/08/14/190000
概要図
例として、VPCとSubnetを作るケースで概要図を記載いたしました。
※VPCとSubnetは同一テンプレートで作るケースが多いかと存じますが、説明のために分割しました。
Before
赤字の箇所が重複しておりますが、CloudFormationでパラメーターをファイル(以降、パラメーターファイルと記載)で管理するためには、 テンプレートで定義したParametersのみをファイルに記載する必要があります。
Parametersの値が全て同一のテンプレートというのは、ほとんどのないかと存じますため、 基本的にパラメーターファイルは、テンプレートごとに作成する必要が出てきてしまいますが、そうなると管理が煩雑になるかと存じます。
After
上記図のようにパラメーターを1つのファイルで管理できれば、Beforeと比べると管理が楽になるのではないでしょうか。 ということでその方法をここから説明いたします。
結論
冒頭でも記載しましたが、パラメーターファイルには、テンプレートで定義したParametersのみを記載する必要があるため、 パラメーターをまとめたファイルからスクリプトによってテンプレートで使う値のみを抽出し、スタックの作成を行います。
使い方
内容を細かく説明する前にスクリプトの使い方を記載した方がいいかなと思ったため、先に使用方法を記載いたします。
# ./create-stack.sh [テンプレート] [パラメーターファイル]
実行例
VPC
# ./create-stack.sh serverworks-vpc.yml prd-fk-param.json 以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。" ############################################################## CFN_STACK_NAME : prd-fk-serverworks-vpc ## PARAMETERS EnvironmentName : prd OwnerName : Serverworks SystemName : fk VpcCIDR : 10.0.0.0/16 ## 実行コマンド aws cloudformation create-stack --stack-name prd-fk-serverworks-vpc --capabilities CAPABILITY_NAMED_IAM --template-body file://serverworks-vpc.yml --parameters ParameterKey=EnvironmentName,ParameterValue=prd ParameterKey=OwnerName,ParameterValue=Serverworks ParameterKey=SystemName,ParameterValue=fk ParameterKey=VpcCIDR,ParameterValue=10.0.0.0/16 ############################################################## yes { "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/prd-fk-serverworks-vpc/fd6159d0-0951-11ed-bfd7-0650087e107d" } #
Subnet
# ./create-stack.sh serverworks-subnet.yml prd-fk-param.json 以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。" ############################################################## CFN_STACK_NAME : prd-fk-serverworks-subnet ## PARAMETERS EnvironmentName : prd ImportStackName : prd-fk-serverworks-vpc OwnerName : Serverworks PublicSubnet1CIDR : 10.0.1.0/24 PublicSubnet2CIDR : 10.0.2.0/24 SystemName : fk ## 実行コマンド aws cloudformation create-stack --stack-name prd-fk-serverworks-subnet --capabilities CAPABILITY_NAMED_IAM --template-body file://serverworks-subnet.yml --parameters ParameterKey=EnvironmentName,ParameterValue=prd ParameterKey=ImportStackName,ParameterValue=prd-fk-serverworks-vpc ParameterKey=OwnerName,ParameterValue=Serverworks ParameterKey=PublicSubnet1CIDR,ParameterValue=10.0.1.0/24 ParameterKey=PublicSubnet2CIDR,ParameterValue=10.0.2.0/24 ParameterKey=SystemName,ParameterValue=fk ############################################################## yes { "StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/prd-fk-serverworks-subnet/960d5da0-0952-11ed-ac36-0eec3649f2d5" } #
詳細
ファイル構成
- ①prd-fk-param.json: パラメーターファイル
※スクリプトの都合、末尾は「-pamarm.json」とする必要があります。 - ②serverworks-vpc.yml: VPC作成のテンプレート
- ③serverworks-subnet.yml: サブネット作成のテンプレート
- ④create-stack.sh: 上記スクリプト
①prd-fk-param.json
[ { "ParameterKey": "SystemName", "ParameterValue": "fk" }, { "ParameterKey": "OwnerName", "ParameterValue": "Serverworks" }, { "ParameterKey": "EnvironmentName", "ParameterValue": "prd" }, { "ParameterKey": "VpcCIDR", "ParameterValue": "10.0.0.0/16" }, { "ParameterKey": "ImportStackName", "ParameterValue": "prd-fk-serverworks-vpc" }, { "ParameterKey": "PublicSubnet1CIDR", "ParameterValue": "10.0.1.0/24" }, { "ParameterKey": "PublicSubnet2CIDR", "ParameterValue": "10.0.2.0/24" } ]
②serverworks-vpc.yml
AWSTemplateFormatVersion: 2010-09-09 Description: This template deploys a VPC Parameters: SystemName: Description: Please specify the system name of the resource Type: String OwnerName: Description: Please specify the owner name of the resource Type: String EnvironmentName: Description: Please specify the environment name of the resource Type: String AllowedValues: - prd - stg - dev - poc VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-vpc - Key: System Value: !Sub ${SystemName} - Key: Owner Value: !Sub ${OwnerName} - Key: Environment Value: !Sub ${EnvironmentName} Outputs: VPC: Description: A reference to the created VPC Value: !Ref VPC Export: Name: Fn::Sub: ${AWS::StackName}-VPC
③serverworks-subnet.yml
AWSTemplateFormatVersion: 2010-09-09 Description: This template deploys a VPC Parameters: SystemName: Description: Please specify the system name of the resource Type: String OwnerName: Description: Please specify the owner name of the resource Type: String EnvironmentName: Description: Please specify the environment name of the resource Type: String AllowedValues: - prd - stg - dev - poc ImportStackName: Description: Please specify the stack name you want to import Type: String PublicSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone Type: String PublicSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone Type: String Resources: PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: Fn::ImportValue: !Sub "${ImportStackName}-VPC" AvailabilityZone: ap-northeast-1a CidrBlock: !Ref PublicSubnet1CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-public-subnet-1a-001 - Key: System Value: !Sub ${SystemName} - Key: Owner Value: !Sub ${OwnerName} - Key: Environment Value: !Sub ${EnvironmentName} PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: Fn::ImportValue: !Sub "${ImportStackName}-VPC" AvailabilityZone: ap-northeast-1c CidrBlock: !Ref PublicSubnet2CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-public-subnet-1c-001 - Key: System Value: !Sub ${SystemName} - Key: Owner Value: !Sub ${OwnerName} - Key: Environment Value: !Sub ${EnvironmentName} Outputs: PublicSubnet1: Description: A reference to the public subnet in the 1st Availability Zone Value: !Ref PublicSubnet1 Export: Name: Fn::Sub: ${AWS::StackName}-PublicSubnet1 PublicSubnet2: Description: A reference to the public subnet in the 2nd Availability Zone Value: !Ref PublicSubnet2 Export: Name: Fn::Sub: ${AWS::StackName}-PublicSubnet2
④create-stack.sh
スクリプトを使うためには、AWS CLIおよびjqが導入されている必要があります。
#!/bin/bash ## 1. スクリプトの引数に指定されたテンプレートとパラメーターファイルを変数に定義 CFN_TEMP=${1} CFN_PARAM=${2} ## 2. スタックの名前をパラメーターファイルおよびテンプレートファイル名から抽出 CFN_STACK_NAME=$(echo ${CFN_PARAM}-${CFN_TEMP##*/} | sed 's/-param.json//g' | awk -F. '{print $1}') ## 3. 変数(引数)がなかった場合、メッセージを出力し、処理を終了 if [[ -z ${CFN_TEMP} || -z ${CFN_PARAM} ]] ; then echo "第1引数: 使用するテンプレートを指定ください。" echo "第2引数: 使用するパラメーターを指定ください。" exit 9 fi ## 5. 4で抽出した値をkey変数に1つずつ代入 while read key do ## 6. jqコマンドを使い、key変数に定義された情報を基にパラメーターファイルから必要な情報を抽出 temp_value=$(cat ${CFN_PARAM} \ | jq --arg key $key -r '.[] | select(.ParameterKey == $key) | .ParameterValue') ## 7. 6で抽出した情報をparameters変数に代入 parameters+="ParameterKey=$key,ParameterValue=$temp_value " ## 4. テンプレートに定義したParametersのParameterKeyを1つずつ抽出 done << EOL $(aws cloudformation validate-template \ --template-body file://${CFN_TEMP} \ --query "Parameters[].[ParameterKey]" \ --output text | sort) EOL ## 8. 抽出したパラメーター,スタック名および実行コマンドを出力 cat << EOF 以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。" ############################################################## CFN_STACK_NAME : ${CFN_STACK_NAME} ## PARAMETERS $(echo ${parameters} | tr " " "\n" \ | sed -e 's/ParameterKey=//g' -e 's/,ParameterValue=/ : /g' \ | column -t) ## 実行コマンド aws cloudformation create-stack --stack-name ${CFN_STACK_NAME} --capabilities CAPABILITY_NAMED_IAM --template-body file://${CFN_TEMP} --parameters ${parameters} ############################################################## EOF ## 9. 8の内容に問題ないか確認するため、ユーザーから入力を待つ。 read answer ## 10. ユーザーからyesが入力された場合、スタックを作成 if [[ ${answer} == "yes" ]] ; then aws cloudformation create-stack \ --stack-name ${CFN_STACK_NAME} \ --capabilities CAPABILITY_NAMED_IAM \ --template-body file://${CFN_TEMP} \ --parameters ${parameters} ## 11. yes以外が入力された場合、処理を中断 else echo "処理を中断しました。" exit 9 fi
終わりに
今回は複数のテンプレートで定義したParametersの値を1つのファイルで管理する方法をご紹介いたしました。 もう少し簡単に出来れば良かったのですが、これを実現するためにはスクリプトを作らざるを得なそうでした。
どなたかのお役に立てれば幸いです。