【AWS】VPCを定義したものとは別のスタックでEC2を構築する【CloudFormation】

# すなわち、クロススタック参照のやり方


## 経緯
VPC, サブネット, ルートテーブル など、ネットワーク関係のスタックと
EC2インスタンスのスタックを分けたい
が、EC2インスタンスではサブネットを指定しないといけない
そんな時にクロススタック参照が使える

## 使い方概要

参照される側(今回はSubnet)のテンプレートで、`Output:`を追加する
参照する側(今回はEC2)のテンプレートで`ImportValue`で値を取得する

## 用意するもの

- [前回](https://qiita.com/c0ba1t_coke/items/be7c85b2b5def746778b)VPCを作成したテンプレート(Yaml)
- EC2作成用のテンプレートファイル(空,Yaml)

## やってみた

[参考](https://dev.classmethod.jp/articles/cfn-cross-stack-reference/)

### 1. VPC側のテンプレートでOutputを設定する

```yaml:vpc.yaml
Resoueces:

## 略 ##

  # Subnet
  mySubnet1:
    Type: AWS::EC2::Subnet
    DeletionPolicy: Retain
    Properties: 
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 192.168.1.0/24
      MapPublicIpOnLaunch: false
      Tags: 
        - Key: Name
          Value: my-public-1
      VpcId:
        Ref: myVPC
  mySubnet2:
    Type: AWS::EC2::Subnet
    DeletionPolicy: Retain
    Properties: 
      AvailabilityZone: ap-northeast-1d
      CidrBlock: 192.168.2.0/24
      MapPublicIpOnLaunch: false
      Tags: 
        - Key: Name
          Value: my-public-2
      VpcId:
        Ref: myVPC

  ## 略 ##

# 一番下に追記
Outputs:
  
  PublicSubnet1:
    Value: 
      Ref: mySubnet1
    Export:
      Name:
        Fn::Sub: ${AWS::StackName}-PublicSubnet1
  PublicSubnet2:
    Value: 
      Ref: mySubnet2
    Export:
      Name:
        Fn::Sub: ${AWS::StackName}-PublicSubnet2
```

- Value, Export の二つを指定する
  - Valueは宣言したリソースをRefで参照する
  - Nameは呼び出す際の名前を指定する
- Fn::Sub : スタックを作成、更新するまで使用できない値を含むコマンドを作成するために使う関数(例:StackName)
  - ${AWS::StackName} : このテンプレートで作成する時に指定するStack名が格納された変数

### 2. EC2インスタンス作成のテンプレートで指定したOutputをImportする

2台EC2を作成
PublicSubnet1,2 にそれぞれ配置

```yaml:ec2.yaml
  myEC2instance1:
    Type: AWS::EC2::Instance
    Properties: 
      BlockDeviceMappings: 
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: true
            VolumeSize: 10
      ImageId: ami-0ddf5ff463ff76656
      InstanceType: t2.nano
      KeyName: my-key
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          SubnetId: !ImportValue my-network-PublicSubnet1 # ←こんな感じで指定
          GroupSet:
            Ref: InstanceSecurityGroup
      Tags: 
        - Key: Name
          Value: 
            Ref: InstanceName1
```

- !ImportValue Value : Outputで指定したリソース宣言をImportする

- [公式](https://aws.amazon.com/jp/blogs/news/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/)では

```yaml
SecurityGroups:
  - !ImportValue AccountSG
```
こんな感じで改行＆インデント＋ - つけてたけどこれだとうまく動かなかった (SubnetIdはString型じゃないとだめで済みたいなエラー文 多分Nullになってた？)

- 全文

```yaml
# 一部修正してます
AWSTemplateFormatVersion: 2010-09-09
Description: EC2 Instances

# Specify Parameter
Parameters:
  InstanceName1:
    Description: Specify Instance Name.
    Type: String
    Default: my-aws01
  InstanceName2:
    Description: Specify Instance Name.
    Type: String
    Default: my-aws02

  InstanceSecurityGroup:
    Description: Specify Secutiry Group.
    Type: List<AWS::EC2::SecurityGroup::Id>

Resources: 
  # EC2 Instance
  myEC2instance1:
    Type: AWS::EC2::Instance
    Properties: 
      BlockDeviceMappings: 
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: true
            VolumeSize: 10
      ImageId: ami-0ddf5ff463ff76656
      InstanceType: t2.nano
      KeyName: my-key
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          SubnetId: !ImportValue my-network-PublicSubnet1
          GroupSet:
            Ref: InstanceSecurityGroup
      Tags: 
        - Key: Name
          Value: 
            Ref: InstanceName1
  myEC2instance2:
    Type: AWS::EC2::Instance
    Properties: 
      BlockDeviceMappings: 
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: true
            VolumeSize: 10
      ImageId: ami-0ddf5ff463ff76656
      InstanceType: t2.nano
      KeyName: my-key
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          SubnetId: !ImportValue my-network-PublicSubnet2
          GroupSet:
            Ref: InstanceSecurityGroup
      Tags: 
        - Key: Name
          Value: 
            Ref: InstanceName2
```

### 3. 作成実行

エラーがでたら都度デバッグ

問題なければサブネットを分けてインスタンスが2つできる

### 4. 確認

SSHしてみて問題なければOK