SAA

インスタンスのAMIを作成して別リージョンにコピーするAutomationランブック

インスタンスのAMIを作成して別リージョンにコピーするAutomationランブック

AWS SAAの出題範囲の1つである、弾力性に優れたアーキテクチャの設計に関する内容です。

AMIは別リージョンにコピーすることができます。

AWS リージョン内またはリージョンをまたいで Amazon マシンイメージ (AMI) をコピーできます。

AMI のコピー

今回はSSM Automationランブックを作成して、既存のEC2インスタンスからAMIを作成し、これを別リージョンにコピーします。

構築する環境

Diagram of Automation runbook to create AMI and copy to another region.

プライベートサブネット内にEC2インスタンスを作成します。
インスタンスは最新のAmazon Linux 2とします。

SSM Automationランブックを作成します。
このランブックの内容は以下の通りです。

  1. インスタンスのAMIを作成する。
  2. 作成したAMIを別リージョンにコピーする。

EC2インスタンスが設置されているリージョンはap-northeast-1、AMIをコピーするリージョンはus-east-1とします。

このランブックとインスタンスの関連付けも作成します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

awstut-saa/01/005 at main · awstut-an-r/awstut-saa
Contribute to awstut-an-r/awstut-saa development by creating an account on GitHub.

テンプレートファイルのポイント解説

(参考)EC2

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PrivateSubnet
          GroupSet:
            - !Ref InstanceSecurityGroup
      Tags:
        - Key: !Ref TagKey
          Value: !Ref TagValue
Code language: YAML (yaml)

タグ設定がポイントです。
後述のSSM関連付けでは、このタグ情報に基づいて対象のインスタンスを指定するためです。

今回は以下の通りにタグを設定します。

  • タグ名:MyRunbook
  • タグの値:true

SSM Automationランブック

Resources:
  CreateAndCopyImageRunbook:
    Type: AWS::SSM::Document
    Properties: 
      Content:
        assumeRole: "{{AutomationAssumeRole}}"
        description: Create and Copy AMI to another region.
        schemaVersion: "0.3"
        parameters:
          AutomationAssumeRole:
            type: String
            description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
            default: ""
          DestinationRegion:
            type: String
            description: (Required) The Region to copy image to.
          InstanceId:
            type: String
            description: (Required) The instance ID you want to run commands on.
            default: ""
        mainSteps:
          - name: createImage
            action: aws:createImage
            maxAttempts: 1
            onFailure: Abort
            inputs:
              InstanceId: "{{InstanceId}}"
              ImageName: "{{InstanceId}}_{{global:DATE_TIME}}"
              NoReboot: true
          - name: copyImage
            action: aws:executeScript
            inputs:
              Runtime: python3.8
              Handler: handler
              InputPayload:
                DestinationRegion: "{{DestinationRegion}}"
                InstanceId: "{{InstanceId}}"
                SourceImageId: "{{createImage.ImageId}}"
                SourceRegion: "{{global:REGION}}"
              Script: |-
                import boto3
                import datetime
                
                def handler(events, context):
                  destination_region = events['DestinationRegion']
                  instance_id = events['InstanceId']
                  source_image_id = events['SourceImageId']
                  source_region = events['SourceRegion']
                  
                  now = datetime.datetime.now()
                  d = now.strftime('%Y-%m-%d_%H.%M.%S')
                  
                  client = boto3.client('ec2', region_name=destination_region)
                  response = client.copy_image(
                    Description='test copy',
                    Name='{instance_id}_{datetime}'.format(instance_id=instance_id, datetime=d),
                    SourceImageId=source_image_id,
                    SourceRegion=source_region
                  )
                  
                  return response
      DocumentFormat: YAML
      DocumentType: Automation
      Name: !Sub "${Prefix}-CreateAndCopyImageRunbook"
      TargetType: /AWS::EC2::Instance
Code language: YAML (yaml)

カスタムランブックを作成します。
ランブックの作成については、以下のページをご確認ください。

Contentプロパティでランブックの中身を定義します。

parametersデータエレメントで、このランブックを実行するためのパラメータを指定します。
今回は以下の3つのパラメータを受け取ります。

  • AutomationAssumeRole:Autometionがこのランブックを実行するために使用するサービスロールのARN
  • DestinationRegion:AMIのコピー先のリージョン
  • InstanceId:AMIを作成するインスタンスのID

mainStepsデータエレメントにランブックで実行する処理を記載します。
このランブックは2つのステップで構成されています。

1ステップ目

1つ目のステップはインスタンスからAMIを作成します。

AMIの作成はSSM Automationが提供するaws:createImageアクションを使用します。

aws:createImage – Amazon マシンイメージ (AMI) を作成する - AWS Systems Manager
実行中、一時停止中、または停止したインスタンスから、AMI を作成します。

inputsにaws:createImageを実行するために必要なパラメータを指定します。
このアクションを実行する際に与えることができるパラメータについては、上記のページを確認できますが、今回は3つ(InstanceId, ImageName, NoReboot)を設定します。

なおImageNameに渡すパラメータを指定する際に、オートメーションシステム変数を参照しています。
「global:DATE_TIME」で実行時の日時を取得することができます。
オートメーションシステム変数の詳細につきましては、以下のページをご確認ください。

オートメーションシステム変数 - AWS Systems Manager
Systems Manager Automation ランブックで使用される変数について説明します。

2ステップ目

2つ目のステップでは、先ほど作成したAMIを別リージョンにコピーします。

AMIのコピーはSSM Automationが提供するアクションaws:executeScriptを使用します。

指定されたランタイムとハンドラを使用して、提供された Python または PowerShell スクリプトを実行します。

aws:executeScript – スクリプトを実行する

inputsにaws:executeScriptを実行するために必要なパラメータを指定します。
特にInputPayloadとScriptが重要なパラメータです。

前者は後述のスクリプトに渡すパラメータを指定するものです。
SourceImageIdでは、1ステップ目のaws:createImageの実行結果として受け取れるImageIdを参照します。
SourceRegionでは、オートメーションシステム変数global:REGIONを参照します。
このリージョンは、EC2インスタンスが生成され、かつAutomationが実行されるリージョン、つまりAMIのコピー元リージョンです。

Scriptパラメータに実行するスクリプトを記述します。
今回はPythonコードを指定します。
実行するコードの内容は以下の通りです。

  • InputPayloadで設定した変数を受け取る。
  • boto3のEC2用クライアントオブジェクトを作成する。
  • クライアントオブジェクトのcopy_imageメソッドを実行して、AMIをコピーする。
  • メソッドの実行結果を返す。

AMIをコピーする上で、クライアントオブジェクトの作成がポイントです。
オブジェクトを作成する際に、region_nameパラメータにコピー先を指定します。
これでAMIを目的にリージョンにコピーすることができます。

なおSSM Automationにおいて、単純にAMIのコピーしたい場合は、aws:copyImageアクションを実行する方法もあります。

aws:copyImage — Amazon Machine Image のコピーまたは暗号化 - AWS Systems Manager
任意の AWS リージョン から現在のリージョンに AMI をコピーします。このアクションでは、新しい AMI を暗号化することもできます。

ただこのアクションでは、コピー元リージョンは指定できますが、コピー先リージョンが指定できないため、今回の要件とは合わなかったため、使用しておりません。

SSM関連付け

Resources:
  CreateAndCopyImageAssociation:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-CreateAndCopyImageAssociation"
      AutomationTargetParameterName: InstanceId
      Name: !Ref CreateAndCopyImageRunbook
      Parameters:
        AutomationAssumeRole:
          - !GetAtt CreateAndCopyImageRunbookRole.Arn
        DestinationRegion:
          - !Ref DestinationRegion
        InstanceId:
          - "{{RESOURCE_ID}}"
      Targets:
        - Key: !Sub "tag:${TagKey}"
          Values:
            - !Ref TagValue
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

先述のランブックとEC2インスタンスを関連付けます。

SSM関連付けを作成して、EC2インスタンスに対してSSM Automationランブックを実行するため方法については、以下のページをご確認ください。

Targetsプロパティで、先述のEC2インスタンスが関連付けの対象となるように、タグ情報を設定します。

SSM用IAMロール

Resources:
  CreateAndCopyImageRunbookRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ssm.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole
      Policies:
        - PolicyName: CreateAndCopyImagePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - iam:PassRole
                Resource:
                  - "*"
Code language: YAML (yaml)

通常、サービスロールを指定しない場合は、デフォルトのサービスリンクロール(SLR)であるAWSServiceRoleforAmazonSSMが使用されます。
今回は以下のAWS公式ページに従って、サービスロールを作成します。

方法 2: IAM を使用して、オートメーションのロールを設定する - AWS Systems Manager
IAM を使用して、Systems Manager Automation のサービスロールを作成します。

さらにAMIの作成および共有に必要な権限(iam:PassRole)を、インラインポリシーとして付与します。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • EC2インスタンス:i-07bd1e5c166136c88
  • SSM Automationランブック:saa-01-005-CreateAndCopyImageRunbook
  • SSM関連付け:9954eb73-83f6-4652-aa5b-4e29f78d4cab

動作確認

準備が整いましたので、AWS Management Consoleから各リソースを確認します。

EC2インスタンス

Detail of EC2 1.

正常にインスタンスが作成されています。
タグ情報を見ると、関連付けの対象を指定するタグが設定されていることがわかります。

SSM Automationランブック

作成したランブックを確認します。

Detail of SSM 1.
Detail of SSM 2.
Detail of SSM 3.

ランブックが正常に作成されていることがわかります。

このランブックには3つのパラメータが存在し、EC2インスタンスのAMIを作成後、別リージョンにコピーする内容です。

SSM関連付け

関連付けを確認します。

Detail of SSM 4.

先述のランブックに対する関連付けが作成されていることがわかります。

Detail of SSM 6.

ランブックを実行するためのパラメータです。
IAMロール、インスタンスID、コピー先リージョンを指定します。
なおインスタンスIDは疑似パラメータを使用しています。

AWS Systems Manager
Detail of SSM 5.

タグ条件を満たしているインスタンスと関連付けが作成されています。

SSM Automation

Automationの実行履歴を確認します。

Detail of SSM 7.

インスタンスに対してAutomationが開始されています。

ステップ1の履歴を確認します。

Detail of SSM 8.

aws:createImageが実行されて、インスタンスのAMIが作成されました。
今回作成されたAMIのIDは「ami-011aba43717b3cfcd」です。

続いてステップ2を確認します。

Detail of SSM 9.

aws:executeScriptが実行されて、ステップ1で作成したAMIが別リージョンにコピーされました。
今回作成されたAMIのIDは「ami-056701e3b4d8001d8」です。

作成されたAMIを確認します。
まずコピー元のAMIです。

Detail of EC2 2.

確かに東京リージョン(ap-northeast-1)にAMIが作成されています。

続いてコピー先のAMIです。

Detail of EC2 3.

確かにバージニアリージョン(us-east-1)にAMIがコピーされています。

まとめ

SSM Automationランブックを作成して、既存のEC2インスタンスからAMIを作成し、これを別リージョンにコピーする方法をご紹介しました。

タイトルとURLをコピーしました