CloudFormation入門 #3 「テンプレートのパラメーター化」


ここまでのテンプレートでは、常に同じ構成のインフラしか構築できませんでした。しかし、実際には状況に応じて変更したい設定もあります。
CloudFormationでは、そのような設定を「パラメーター」としてスタック作成時に設定できる機能があります。

# Parametersセクション

あらためてテンプレートの基本的な構造を以下に示します。

* Format Version（任意）
* Description（任意）
* Metadata（任意）
* Parameters（任意）
* Mappings（任意）
* Condition（任意）
* Resources（必須）
* Outputs（任意）

この中で、パラメーターを設定できるセクションは`Parameters`になります。このセクションの構造は以下のドキュメントに記載されています。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html

`Parameters`セクションの中には、次の構文でパラメーターを必要な数だけ定義することができます。

```json:パラメーター構文
{
  "パラメーター名" : {
    "プロパティー名" : "プロパティーの値",
    "プロパティー名" : "プロパティーの値",
      // 以下繰り返し
  }
}
```

パラメーター名には、パラメーターをテンプレート内で参照できるようにするための独自の名前を定義します。プロパティー名で使用できるものは、上記のドキュメントの中に定義されています。よく使われるものを、簡単に説明してみます。

| パラメーター名 | 説明 |
|------------|-----|
| Description | パラメーター入力時に表示される説明文 |
| Type | パラメーター値の型。文字や数字の他、AWS固有の型も指定できる |
| Default | あらかじめ設定されている初期値 |


以下、EC2インスタンスの作成でよく使われるパラメーターの具体例を示して、パラメーターの雰囲気を掴んでみます。

参考：[基本的なAmazon EC2インスタンス](ttps://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/deploying.applications.html)

## インスタンスタイプ

インスタンスタイプを選択するためのパラメーターです。`Type`は文字型ですが、あらかじめ`AllowedValues`で用意されたものしか選択できないようになっています。`ConstraintDescription`には、正しくない値が選択されたときに表示されるエラーメッセージが表示されます（今回の定義ではあらかじめ決められた値から選択するので、おそらく表示されることはないと思います）

```json:インスタンスタイプ
{
  "InstanceType" : {
    "Description" : "WebServer EC2 instance type",
    "Type" : "String",
    "Default" : "m1.small",
    "AllowedValues" : [ "t1.micro", "t2.micro", "t2.small", "t2.medium", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c1.medium", "c1.xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "g2.2xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge", "cg1.4xlarge"],
    "ConstraintDescription" : "Must be a valid EC2 instance type"
  }
}
```

## キーペア名

キーペアの型は文字列ではなく、"AWS::EC2::KeyPair::KeyName"という特別なものになっています。これは、AWS内で登録されているキーペアを指す特別な型です。

```json:キーペア名
{
  "KeyName": {
    "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instance",
    "Type": "AWS::EC2::KeyPair::KeyName",
    "ConstraintDescription" : "Can contain only ASCII characters."
  }  
}
```

## SSH接続可能なIPアドレスの範囲

IPアドレスの範囲は文字列ですが、文字長や正規表現などを使ってCIDRという形式にマッチした値のみが入力できるよう制限されています。

```json:SSH接続可能なIPアドレスの範囲
{
  "SSHLocation" : {
    "Description" : "The IP address range that can be used to SSH to the EC2 instances",
    "Type": "String",
    "MinLength": "9",
    "MaxLength": "18",
    "Default": "0.0.0.0/0",
    "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
    "ConstraintDescription": "Must be a valid IP CIDR range of the form x.x.x.x/x"
  } 
}
```

## リソースからパラメーターを指定する

パラメーターを作成したら、テンプレートの中からRef関数を使ってパラメーター名を指定できます。例えば、インスタンス名を指定する箇所は次のように置き換えることができます。

直値の場合：
`"InstanceType" : "t2.micro"`

パラメーターの場合：
`"InstanceType" : { "Ref" : "InstanceType" }`

_注意：パラメーターの場合には"InstanceType"という文字列が二回出てきていますが、最初の"InstanceType"は、EC2インスタンスのResourceで定義されているプロパティー名で、{ }の中の"InstanceType"は、Parametersセクションの中で独自に定義したパラメーター名となり、たまたま同じ名前になってしまいましたが別物です。_

## 完成したテンプレート

今回は、「インスタンスタイプ」「SSH接続可能なIPアドレス範囲」「キーペア」の三つをパラメーターとして定義されたテンプレートを利用します。だいぶ長くなりましたが、今まで説明してきた内容をすべてまとめただけです。

```json:cloudformation_study.template
{
  "Parameters" : {
    "KeyName": {
      "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instance",
      "Type": "AWS::EC2::KeyPair::KeyName",
      "ConstraintDescription" : "Can contain only ASCII characters."
    },
    "InstanceType" : {
      "Description" : "WebServer EC2 instance type",
      "Type" : "String",
      "Default" : "m1.small",
      "AllowedValues" : [ "t1.micro", "t2.micro", "t2.small", "t2.medium", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c1.medium", "c1.xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "g2.2xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge", "cg1.4xlarge"],
      "ConstraintDescription" : "Must be a valid EC2 instance type"
    },
    "SSHLocation" : {
      "Description" : "The IP address range that can be used to SSH to the EC2 instances",
      "Type": "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default": "0.0.0.0/0",
      "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription": "Must be a valid IP CIDR range of the form x.x.x.x/x"
    }
  },
  "Resources" : {
    "MyEC2Instance": {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "ami-383c1956",
        "InstanceType" : { "Ref" : "InstanceType" },
        "KeyName" : { "Ref" : "KeyName" },
        "SecurityGroupIds" : [
          { "Ref" : "MyEC2SecurityGroup" }
        ]
      }
    },
    "MyEC2SecurityGroup": {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Enable SSH access via port 22",
        "SecurityGroupIngress" : [{
          "IpProtocol" : "tcp",
          "FromPort" : "22",
          "ToPort" : "22",
          "CidrIp" : { "Ref" : "SSHLocation" }
        }]
      }
    }
  }
}
```

# スタック作成時のパラメーター指定方法

上記のテンプレートを使ってスタックを作成すると、スタック名を入力するところで、パラメーターも入力できるようになります。これにより、同じテンプレートからさまざまな環境や用途にあったスタックを生成することができるようになります。

![parameter01.png](https://qiita-image-store.s3.amazonaws.com/0/75307/c5e4e4f3-5392-6b38-e10f-43511e636e73.png "parameter01.png")