CloudFormation - 既存リソースのインポート方法メモ
概要
- すでに手動で作成してあるVPCをyamlファイル化(?)する
- CloudFormationを使って新たにEC2インスタンスをVPC上に構築する
参考
検証用に用意したもの
-
手動作成リソース
- VPC
- インターネットゲートウェイ
- サブネット
- ルートテーブル
- セキュリティグループ
-
各リソースの識別子(ID)をメモしておく(インポート実行時に指定することになる)
- VPC : vpc-xxxxxxxxxxxx
- rtb : rtb-xxxxxxxxx
- igw : igw-xxxxxxxxx
- sg : sg-xxxxxxxxx
- sub : subnet-xxxxxxxxxxx
手順
1. 既存リソースからのスタック作成(VPC,igw,subnet,rt,sg)
- まずインポートするためのyamlファイルを作る
AWSTemplateFormatVersion: "2010-09-09"
Description: my imported VPC resources
Resources:
# VPC
myVPC:
Type: AWS::EC2::VPC
DeletionPolicy: Retain
Properties:
CidrBlock: 192.168.0.0/16
EnableDnsHostnames: false
EnableDnsSupport: true
InstanceTenancy: Default
Tags:
- Key: Name
Value: vpcName
# InternetGateway
myInternetGateway:
Type: AWS::EC2::InternetGateway
DeletionPolicy: Retain
Properties:
Tags:
- Key: Name
Value: igwName
# 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: publicSubnetName1
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: publicSubnetName2
VpcId:
Ref: myVPC
# Routetable
myRoutetablePublic:
Type: AWS::EC2::RouteTable
DeletionPolicy: Retain
Properties:
Tags:
- Key: Name
Value: publicRouteName
VpcId:
Ref: myVPC
myRoutetablePrivate:
Type: AWS::EC2::RouteTable
DeletionPolicy: Retain
Properties:
Tags:
- Key: Name
Value: privateRouteName
VpcId:
Ref: myVPC
# SecuriryGroup
mySecuritygroup:
Type: AWS::EC2::SecurityGroup
DeletionPolicy: Retain
Properties:
GroupDescription: allow-all-from-my-vm
VpcId:
Ref: myVPC
SecurityGroupIngress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: ssh元のIP
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
インポートしたいリソースの設定内容をとりあえず入れていく
作成時デフォルトで作った場合、必須項目以外は記載無しでもデフォルトでインポートされる(...はず)
==Point==
DeletionPolicy: Retain
をすべてのリソースに設定する
これはスタックを削除しても実際のリソースはそのまま残るようにする設定
インポートに関してはこの設定がついてないとエラーで実行できない
セキュリティグループで「すべて」を指定したい場合
FromPort
とかに「すべて」を指定したい場合は、"-1" にする
all とかにすると実行したときにFAILEDになる (Non numeric は サポートされていません みたいなエラー文だった)
インポートできないリソースもある
今回の場合、AWS::EC2::Route
はインポート対象外といわれてインポートできなかった
他のリソースをインポートした後Routeの宣言を追加して、変更セット実行したらどうなる??→要検証
2. スタック作成実行
-
スタックの作成プルダウンから、既存リソースを使用(リソースをインポート)を選択する
-
必要なものを教えてくれる 次へ をクリック
-
テンプレートの指定でさっき作ったyamlファイルをアップロードする
事前にS3にアップしておいてURL指定すると余計なバケットが作成されなくて済む -
インポートするリソースのリソースIDの入力を求められたら、実際のリソースをコンソールなどで確認して、正しく入力する
-
スタックの名前 好きな名前を適当につけてOK
-
「変更」欄で変更内容を確認して(importがずらっと並ぶはず) 「リソースをインポート」をクリック
-
普通にスタック作成したときみたいにステータスが流れ始める
エラーが出た場合はエラー文読んでデバッグしていく
3. ドリフト検出
ステータスが「IMPORT_COMPLETE」になったら、確認のためにドリフトを検出する
スタックを選択して「スタックアクション」プルダウンから「ドリフトの検出」→「ドリフト結果を表示」
全項目のドリフトステータスが「IN_SYNC」になってたらOK
ドリフトステータス | 説明 |
---|---|
DELETED | リソースが削除されたため、リソースは意図したテンプレート設定と異なります。 |
MODIFIED | リソースは意図したテンプレート設定とは異なります。 |
NOT_CHECKED | CloudFormation は、リソースが意図したテンプレート設定と異なるかどうかを確認していません。 |
IN_SYNC | リソースの現在の設定は、意図したテンプレート設定と一致します。 |
yamlファイルの中身が間違っている場合
どうなるのか検証してみたところ、
実際のリソースの設定に合わされるようにMODIFYされる
ことがわかった
試しにVPCで EnableDnsSupport: true → false
にした(わざと値を間違えた)ものを使ってimport実行してみたところ、
ドリフトを検出→ドリフトの結果→ドリフトの詳細を見ると、自動で true に修正されていることが分かった
これぞフォールトトレランス!!
3. スタックによるリソースの作成(EC2)
ここからおまけ
# 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: !Ref mySubnet1
GroupSet:
- !Ref mySecuritygroup
Tags:
- Key: Name
Value:
Ref: InstanceName
-
Ref:
宣言したリソース名を指定することで特定のパラメータを戻り値で受け取ることができる。
戻り値の内容はリソースによって変わるので、ドキュメントを見て確認するしかない。
基本的にIDが返ってくる VPC→VPC ID -
VolumeType: gp2, gp3, io1, io2 とかを選ぶ gp2が一番標準のSSD
-
gp2はiopsを指定できない (使用要領によってiopsが変動するらしい)
-
ImageId: RockyLinux8を使用 一度インスタンスを作成して、概要からコピってきた
[求]何もわからない状態からAMIを調べる方法 -
NetworkInterfaces: インターフェース設定 この中でサブネットとセキュリティグループを指定する
-
SubnetId: !Ref mySubnet1
!Ref mySubnet1とすることで SubnetID(subnet-xxxxxx) が Stringで返ってくる
Ref mySubnet1だとエラー起きるので、Stringではない何かが返ってきているようだ
- GroupSet:
- !Ref mySecuritygroup
この書き方じゃないとうまくいかなかった
GroupSet(サブネット)はID(String型)じゃなくて、IDのリスト型じゃないとだめらしい(List<AWS::EC2::SecurityGroup::Id>
)
エラー起きたときの出力↓
Value of property SecurityGroupIds must be of type List of String
改良
- Parametersを使ってインスタンス名とセキュリティグループを指定できるようにした
- EIPをアタッチした
AWSTemplateFormatVersion: "2010-09-09"
Description: my imported VPC resources
# Specify Parameter
Parameters:
InstanceName:
Description: Specify Instance Name.
Type: String
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: !Ref mySubnet2
GroupSet:
Ref: InstanceSecurityGroup
Tags:
- Key: Name
Value:
Ref: InstanceName
# Elastic IP
myElasticIP1:
Type: AWS::EC2::EIP
Properties:
InstanceId:
Ref: myEC2instance1
Tags:
- Key: Name
Value: !Ref InstanceName
4. スタック更新実行
-
さっきインポートしたスタックを選択して、更新をクリック
-
既存のテンプレートを置き換える → 修正したyamlファイルをアップロードして 次へ
-
パラメータを指定して 次へ
-
スタックオプションは特に指定なし 次へ
-
スタックの更新を実行 (不安なら 変更セットの表示)
5. 問題なければ完成!
EC2に指定したKeypairでsshできたら無事完成!