話題の記事

【アップデート】ついに来た!CloudFormationで手動で作成したリソースをStackにインポート可能になりました

CloudFormationで既存リソースをインポートできるようになりました。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

大栗です。

ついにCloudFormation以外で作成したリソースもCloudFormationの管理化にできるアップデートが来ました!!!長期的にCloudFormationで環境を管理すると辛くなってくる部分を解消できると思います。早速レポートします。

既存リソースのインポート

CloudFormationはInfrastructure as Codeを実現する良いサービスなのですが、緊急の場合などにどうしてもCloudFormationを使わずにCLIや手動でリソースを作成してしまうことがありCloudFormationによる環境の管理を挫折せざるを得なくなることがあります。今回のアップデートにより、別途作成したリソースをCloudFormationnスタックの管理に組み込めるようになります。

既存のリソースをスタックへ組み込む場合は、以下のような手順で行います。

  1. テンプレート上に既存リソースと同様の内容を追加する
    1. で変更したテンプレートと追加するリソースのIDを指定して、インポート操作を行う
  2. スタックに既存リソースが追加される

インポートは、新規でスタックを作成する事も、既存のスタックに追加することも可能です。

注意点

インポートするリソースは、テンプレート上でDeletionPolicyRetainにする必要があります。

また、インポートできるものはドリフト検出ができるリソースのみです。具体的なリソースは以下のドキュメントで確認して下さい。

Resources that Support Import Operations

やってみた

以下のような流れで試してみます。リソースをスタックに追加して、最終的にCloudFormation経由で削除してみます。

  1. DynamoDBをCloudFormationを使わずに作成する
  2. DynamoDBをインポートしつつ新規にCloudFormationスタックを作成する
  3. EC2とSecurity GroupをCloudFormationを使わずに作成する
  4. EC2とSecurity Groupをインポートしつつ新規にCloudFormationスタックを作成する
  5. CloudFormationのDeletionPolicyを変更する
  6. CloudFormationと共にリソースを削除する

前提として、東京リージョンで実行しています。

DynamoDBをCloudFormationを使わずに作成する

まずDynamoDBを作成します。ここではAWS CLIで作成します。ここでは2個のテーブルを作成します。aws dynamodb create-tableコマンドで作成します。

$ aws dynamodb create-table \
>   --region ap-northeast-1 \
>   --attribute-definitions AttributeName=key,AttributeType=S \
>   --table-name Service \
>   --key-schema AttributeName=key,KeyType=HASH \
>   --billing-mode PAY_PER_REQUEST
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/Service",
        "AttributeDefinitions": [
            {
                "AttributeName": "key",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 0,
            "ReadCapacityUnits": 0
        },
        "TableSizeBytes": 0,
        "TableName": "Service",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST"
        },
        "TableStatus": "CREATING",
        "TableId": "12345678-1234-1234-1234-123456789012",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "key"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1573712546.942
    }
}
$ aws dynamodb create-table \
>   --region ap-northeast-1 \
>   --attribute-definitions AttributeName=key,AttributeType=S \
>   --table-name Games \
>   --key-schema AttributeName=key,KeyType=HASH \
>   --billing-mode PAY_PER_REQUEST
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/Games",
        "AttributeDefinitions": [
            {
                "AttributeName": "key",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 0,
            "ReadCapacityUnits": 0
        },
        "TableSizeBytes": 0,
        "TableName": "Service",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST"
        },
        "TableStatus": "CREATING",
        "TableId": "12345678-1234-1234-1234-123456789012",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "key"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1573712546.942
    }
}

DynamoDBをインポートしつつ新規にCloudFormationスタックを作成する

作成したDynamoDBと同じ内容のテンプレートを作成して、インポートします。

作成したDynamoDBと同様のテンプレートを用意します。

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Import test
Resources:
  ServiceTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Retain
    Properties:
      TableName: Service
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH
  GamesTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Retain
    Properties:
      TableName: Games
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH

ここでCloudFormationのコンソールを開きます。スタックの作成から既存のリソースを使用 (リソースをインポート)をクリックします。

次へをクリックします。

用意したテンプレートをアップロードして次へをクリックします。

作成したDynamoDBのIDを以下の様に入力して次へをクリックします。

リソース論理ID 識別子の値
GamesTable Games
ServiceTable Service

スタックの名前に任意の名前を入力して次へをクリックします。ここではImportStackと入力しています。

一番下の変更で、アクションがImportになっていることを確認して、リソースをインポートをクリックします。

少しすると、リソースがインポートされます。

スタック上でリソースが見えてます。

EC2とSecurity GroupをCloudFormationを使わずに作成する

次はEC2とSecurity Groupをスタックに追加するためにAW CLIで作成します。

Security Groupを作成します。

$ aws ec2 create-security-group \
  --description cfn-import-test \
  --group-name cfn-import-test \
  --vpc-id vpc-abcdefgh
{
    "GroupId": "sg-1234567890abcdefg"
}

EC2を作成します。

$ aws ec2 run-instances --image-id ami-0064e711cbc7a825e \
  --instance-type m5.large \
  --subnet-id subnet-12345678 \
  --security-group-ids sg-1234567890abcdefg \
{
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": "",
            "StateReason": {
                "Message": "pending",
                "Code": "pending"
            },

            ・・・

        }
    ],
    "ReservationId": "r-abcdefg1234567890",
    "Groups": [],
    "OwnerId": "123456789012"
}

EC2とSecurity Groupをインポートしつつ新規にCloudFormationスタックを作成する

EC2とSecurity Groupを追加したテンプレートを用意します。

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Import test
Parameters: 
  VPCID: 
    Type: String
  GROUPID:
    Type: String
  SUBNETID:
    Type: String
Resources:
  ServiceTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Retain
    Properties:
      TableName: Service
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH
  GamesTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Retain
    Properties:
      TableName: Games
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH
  TestGroup:
    Type: AWS::EC2::SecurityGroup
    DeletionPolicy: Retain
    Properties: 
      GroupDescription: cfn-import-test
      GroupName: cfn-import-test
      VpcId: !Ref VPCID
  TestInstance:
    Type: AWS::EC2::Instance
    DeletionPolicy: Retain
    Properties: 
      ImageId: ami-0064e711cbc7a825e
      InstanceType: m5.large
      SecurityGroupIds: 
        - !Ref GROUPID
      SubnetId: !Ref SUBNETID

ここでCloudFormationのコンソールを開きます。対象のスタックを選択して、スタックアクションからスタックへのリソースのインポートをクリックします。

次へをクリックします。

用意したテンプレートをアップロードして次へをクリックします。

作成したEC2のIDを以下の様に入力して次へをクリックします。

リソース論理ID 識別子の値
TestInstance <作成したEC2のID>
TestGroup <作成したSecurity GroupのID>

パラメータを入力して次へをクリックします。

リソース論理ID 識別子の値
GROUPID <作成したSecurity GroupのID>
SUBNETID <EC2を配置したサブネットのID>
VPCID <作成したSecurity GroupのVPC>

一番下の変更で、アクションがImportになっていることを確認して、リソースをインポートをクリックします。

少しすると、リソースがインポートされます。

スタックを新規作成したときと同様に、スタック上でリソースが見えてます。

CloudFormationのDeletionPolicyを変更する

リソースを削除するために、DeletionPolicyを削除したテンプレートを用意します。

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Import test
Parameters: 
  VPCID: 
    Type: String
  GROUPID:
    Type: String
  SUBNETID:
    Type: String
Resources:
  ServiceTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Delete
    Properties:
      TableName: Service
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH
  GamesTable:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Delete
    Properties:
      TableName: Games
      AttributeDefinitions:
      - AttributeName: key
        AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
      - AttributeName: key
        KeyType: HASH
  TestGroup:
    Type: AWS::EC2::SecurityGroup
    DeletionPolicy: Delete
    Properties: 
      GroupDescription: cfn-import-test
      GroupName: cfn-import-test
      VpcId: !Ref VPCID
  TestInstance:
    Type: AWS::EC2::Instance
    DeletionPolicy: Delete
    Properties: 
      ImageId: ami-0064e711cbc7a825e
      InstanceType: m5.large
      SecurityGroupIds: 
        - !Ref GROUPID
      SubnetId: !Ref SUBNETID

ここでCloudFormationのコンソールを開きます。対象のスタックを選択して、更新するをクリックします。

既存テンプレートを置き換えるを選択して、更新したテンプレートをアップロードして次へをクリックします。

パラメータを変更せずに次へをクリックします。

次へをクリックします。

変更セットのプレビューに何もないことを確認して、スタックの更新をクリックします。

UPDATE_COMPLETE になるのを待ちます。

CloudFormationと共にリソースを削除する

CloudFormationスタックを削除して、インポートしたリソースも消えることを確認します。

削除前のリソースを確認します。

DynamoDBにテーブルが2個あります。

Security Groupです。

EC2です。

ここでスタックを削除します。ここでCloudFormationのコンソールで対象のスタックを選択して、削除をクリックします。

スタックの削除をクリックします。

スタックが削除されていきます。

各リソースもDELETE_COMPLETEになっています。

各々の画面でも確認してみます。

DynamoDBのテーブルが消えています。

Security Groupも消えています。

EC2もterminatedになっています。

CloudFormationの管理として削除できました。

さいごに

既存リソースのインポートは、ずっと待っていてようやく出てきた機能でした。これがあると環境をCloudFormationで管理して長期で運用することがしやすくなると思われます。私にもいくつかCloudFormationで管理している環境が、手動で作成してしまった場合は、一旦削除してCloudFormationで再作成したりといった大変手間がかかる運用となっていました。今回のアップデートをどんどん使っていきたいと思います。