CloudFormationのスタック作成をCSV+Powershellスクリプトで

タイトル通りですが、今回のお題は『パラメータ→構築自動化』です。

イメージとしては、
PowerShellスクリプト叩く
CSVからパラメータ読み込む、
・CFnのテンプレ(JSON)にパラメータを渡し、スタック作成。
という感じです。

先ずは簡単なところから…ということで、VPC~Subnetの作成までを行ってみます。 構成はVPC内にPublicなSubnet×2(マルチAZ)というシンプルなもの。

因みに、"AWS Tools for PowerShell"を使用していますが初期設定は割愛しています。

目次

CloudFormationテンプレートファイル作成

はじめにCFnのテンプレートファイルを作成します。
今回はVPCとSubnet作成用に2ファイル用意。(見やすいという理由で)
"Parameters"ブロックで受け取る引数を指定、
"Resources"ブロック内で作成するリソースに関する記述を行っています。

VPC作成用JSONファイル(vpctest.json)

{
 "AWSTemplateFormatVersion": "2010-09-09",
 "Parameters": {
 "vpccidrblock": {
 "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 "Default": "172.31.0.0/16",
 "Type": "String"
 },
 "vpcname":{
 "Type": "String"
 }
 },
 "Resources": {
 "VPC": {
 "Properties": {
 "CidrBlock": {
 "Ref": "vpccidrblock"
 },
 "Tags": [
 {
 "Key": "Application",
 "Value": {
 "Ref": "AWS::StackId"
 }
 },
 {
 "Key": "Name",
 "Value": {
 "Ref": "vpcname"
 }
 }
 ]
 },
 "Type": "AWS::EC2::VPC"
 }
 }
}

Subnet作成用JSONファイル(subnettest.json)

{
 "AWSTemplateFormatVersion": "2010-09-09",
 "Parameters": {
 "subnetname": {
 "Type": "String"
 },
 "subnetcidrblock": {
 "Type": "String"
 },
 "subnetazname": {
 "Type": "AWS::EC2::AvailabilityZone::Name"
 },
 "subnetpublicipflag": {
 "Type": "String"
 },
 "vpcid": {
 "Type": "String"
 }
 },
 "Resources": {
 "Subnet": {
 "Properties": {
 "CidrBlock": {
 "Ref": "subnetcidrblock"
 },
 "MapPublicIpOnLaunch" : {
 "Ref": "subnetpublicipflag"
 },
 "AvailabilityZone": {
 "Ref": "subnetazname"
 },
 "VpcId" : { "Ref" : "vpcid" },
 "Tags": [
 {
 "Key": "Name",
 "Value": {
 "Ref": "subnetname"
 }
 }
 ]
 },
 "Type": "AWS::EC2::Subnet"
 }
 }
}

また、作成したJSONファイルはS3にアップロードしておきます。

ここでは"my-cfn-templates-000"という名前でバケットを作成し、 その中にJSONファイルをアップロードしています。  

 

CSVファイルの準備

特筆するところもないですが、 前項で作成したCFnテンプレに渡す為のパラメータを記述したCSVを用意します。 見づらいので、Excelで開いたものを載せておきます。

"subnetazflag"は、東京リージョンのAZ "ap-northeast-1a"、"ap-northeast-1c"を判別するフラグになります。

また同一VPC内にSubnetを作成することを前提として作成しているので、 2行目はブランクにしています。

 

パラメータCSVファイル(param.csv)

PowerShellスクリプト作成

続いて、PowerShellスクリプトを作成します。
汚いコードですが、以下のような感じに書いてみました。
少し長いので3分割しています。

①変数設定等
Credential等の設定はEC2上から実行するのであれば不要ですね。

#Credentialファイルのパスを指定
$credentials_path = "<任意のパス>"

#リージョンの指定(今回は東京リージョン)
$aws_region = "ap-northeast-1"

#CFnテンプレートファイルを格納したS3のURLを指定
$template_url1 = "https://s3.amazonaws.com/my-cfn-templates-000/vpctest.json"
$template_url2 = "https://s3.amazonaws.com/my-cfn-templates-000/subnettest.json"

#Credintial、リージョンの設定
Set-AWSCredentials -StoreAs $credentials_path
Set-DefaultAWSRegion -Region $aws_Region

#CSVファイルの読み込み(デスクトップに配置したparam.csvを指定)
$csvfile = Get-ChildItem env:USERPROFILE | % {$_.value}
$csvfile += "\Desktop\param.csv"
$cfnparam = Get-Content $csvfile | ConvertFrom-Csv -Delimiter ","

VPC作成処理
スタック名はユニークにする必要があるので注意です。
"vpcname"ですがSubnet作成処理でVPCのidを特定するのに使う為、
スコープを"script"にしています。

#インスタンスを作成し、パラメータを付加
function Create_Object($param_key,$param_value){
$p = New-Object -Type Amazon.CloudFormation.Model.Parameter
$p.ParameterKey = $param_key
$p.ParameterValue = $param_value
return $p
}

#VPC作成処理
function Create_Vpc{
$stackname = "vpc-stack-00"
$script:vpcname = $cfnparam.vpcname
$vpccidrblock = $cfnparam.vpccidrblock
$p1 = Create_Object vpcname $vpcname
$p2 = Create_Object vpccidrblock $vpccidrblock
New-CFNStack -StackName $stackname `
-TemplateURL $template_url1 `
-Parameter @( $p1, $p2 ) `
-OnFailure "ROLLBACK"
}

③Subnet作成処理、Function実行
CSVファイルを見ればお察しかと思いますが、
"vpcname"パラメータを変数に代入する際、複数行だと当然ながら配列型になってしまう為、
文字列型かそうでないかを判別しています。(無理やり感満載ですが…)

Function実行部分では、"Start-Sleep"にて処理を待つようにしています。 が、入れなくても問題ない?気がしています…。

#Subnet作成処理
function Create_Subnet{
$stack_count = 0
if($vpcname.gettype().fullname -ne [System.String]){
$vpcid = (Get-EC2Tag -region $aws_Region | ? {$_.value -eq $vpcname[0]} | % {$_.resourceid})
}else{
$vpcid = (Get-EC2Tag -region $aws_Region | ? {$_.value -eq $vpcname} | % {$_.resourceid})
}
$avz = Get-EC2AvailabilityZone -region $aws_Region | % {$_.zonename}

foreach ($cfn_param in $cfnparam) {
$stackname = "subnet-stack-" + ("{0:00}" -F $stack_count)
$stack_count ++
$subnetname = $cfn_param.subnetname
$subnetcidrblock = $cfn_param.subnetcidrblock
$subnetazflag = $cfn_param.subnetazflag
$subnetpublicipflag = $cfn_param.subnetpublicipflag

$p3 = Create_Object subnetname $subnetname
$p4 = Create_Object subnetcidrblock $subnetcidrblock
$p5 = Create_Object subnetazname $avz[$subnetazflag]
$p6 = Create_Object subnetpublicipflag $subnetpublicipflag
$p7 = Create_Object vpcid $vpcid

New-CFNStack -StackName $stackname `
-TemplateURL $template_url2 `
-Parameter @( $p3, $p4, $p5, $p6, $p7 ) `
-OnFailure "ROLLBACK"
}
}

Create_Vpc
Start-Sleep -Seconds 60
Create_Subnet

スクリプト実行

前項で作成したスクリプトを叩くだけです…。

スタックの状態確認

マネジメントコンソールから確認してみます。 "CREATE_COMPLETE"となっていれば完了です。

 

リソースの確認

最後にVPC、Subnetをコマンドで確認してみましょう。
"Get-EC2Vpc"、"Get-EC2Subnet"を使用します。

 

CSVファイルに入力したパラメータ通り、作成できていることが確認できました。
以上が一連の流れとなります。

EC2の作成は割愛しましたので、中途半端ではありますが如何でしょうか。
頑張れば構築が楽になりそうな気が?しますね…。

また、デフォルトではスタックを削除するとリソースも削除されるのですが
オプションにて削除しないようにすることもできます。

JSONファイルの"Resources"ブロックにて
"DeletionPolicy" : "Retain"とすることで削除されなくなります。

それでは次の機会に。

 

 

 

アプリケーション開発バナー