実践・Systems Manager Automation〜「EC2の立ち上げからDNSレコード登録まで」を自動で〜

実践・Systems Manager Automation〜「EC2の立ち上げからDNSレコード登録まで」を自動で〜

はじめに

西藤です。

皆さんはEC2インスタンスを使ってウェブアプリケーションの開発・検証をするとき、動作確認はどのように行なっていますか?

個人用途で、CI/CDも組まない、とてもシンプルな構成であれば、

  1. EC2インスタンスを立ち上げる
  2. インスタンス内でアプリケーションを実装する
  3. インスタンスのパブリックIPと紐付けてDNSレコードを作成し、そのドメイン名にアクセスする

という具合ではないでしょうか?

しかし、これだとEC2インスタンスの起動のたびにDNSレコードの更新の手間がかかります。また、手間を省くために"ElasticIP"を利用して、IPアドレスの固定を行なっても、それ自体にAWS利用料が発生します。

そこで、今回は、AWS Systems Manager Automationの仕組みを使って、

  • EC2インスタンスを起動する
  • インスタンスのIPアドレスを取得し、DNSレコードを追加する

を自動化して、利用料を節約しながら、運用上の手間も省いてみることにしました。

前提の確認と現状の課題

準備方法は割愛しますが、まずは、冒頭に触れたように動作確認を行いたいウェブサーバーが稼働しているEC2インスタンスを準備します。
インスタンス内にApacheをインストールして、簡易的なページを表示させるようにしました。

EC2インスタンスの詳細画面を見ると「パブリックIPv4アドレス」が表示されています。

このIPアドレスへブラウザでアクセスすると

のように表示されます。

そして、Route53のレコード設定画面で、この52.xxx.xxx.xxx のIPアドレスをターゲットにDNSレコードを追加して、ドメイン名ベースでアクセスできるようにします。

DNSレコードを追加した後該当のドメイン名でアクセスすると・・・・

先ほど同じページが表示されました。

以上で準備が完了です。

この後、一度でもEC2インスタンスを停止しまうと、今度起動した時には先ほどと同じ 52.xxx.xxx.xxx になることが確約されず、異なるIPアドレスが割り当てられます。そして、その際には今のDNS名にアクセスしても接続ができないわけです。

そのため、DNSレコードの再設定やElasticIPでのIPアドレス固定化が通常必要になります。

それらの手間を省くための次のように自動化の設定を行います。

IAMロールの作成

まずは後述するSystems Managerで使用するためのIAMロールを作成します。

「AWSサービス用」で"Systems Manager"のユースケースで作成します。

そして、EC2用の権限とRoute53用の権限を付与します。
(今回は FullAccessで割り当ててしまっていますが、運用時には適切な粒度で最低限の権限のみを付与するようにしてください。)


入力を終えたら作成します。

作成が完了したらそのIAMロールの「ロールARN」を控えておいてください。


IAMロールの設定は完了です。
そして、次のステップに進んでください。

Systems Managerドキュメント設定

今回の自動化を行う仕組みとしてはAWS Systems Managerの"Automation"の仕組みを利用します。
これはAWS上における設定操作などをあらかじめ定義された手順(「ドキュメント」)に基づいて、自動化するものです。

まず、AWS Systems Managerの画面より「ドキュメント」の画面を開きます。

そして、今回は "Automation"のドキュメントを作成したいので、「オートメーションを作成する」をクリック

すると、編集画面になります。


これは「ビルダー」の画面でAutomationの動作をステップ毎にオプションなどを選択していきながら編集していくものとなります。
必要項目を埋めていけば、ymlベースのドキュメントが完成し、設定ファイルを共有しやすくなるわけです。

今回は「ビルダー」画面ではなく、ymlを入力するので「エディタ」の画面を選択し、次の内容を入力欄に反映してください。
その際の注意点としては assumeRole の部分に先ほど作成したIAMロールの「ロールARN」を記述してください。

description: Start EC2 And Set Dns Record Of Instance IP Without EIP
schemaVersion: "0.3"
assumeRole: <ロールARNの内容をここに記載>
parameters:
  InstanceID:
    type: StringList
    description: (Required) Target EC2 Instance to start.
  HostedZoneID:
    type: String
    description: (Required) Route53 Hosted Zone ID to add DNS Record in.
  DomainName:
    type: String
    description: (Required) DNS Record Name to add.
mainSteps:
  - name: StartEC2
    action: "aws:changeInstanceState"
    inputs:
      InstanceIds: "{{InstanceID}}"
      DesiredState: running
      CheckStateOnly: false
  - name: GetEC2InstanceIP
    action: "aws:executeAwsApi"
    inputs:
      Service: ec2
      Api: DescribeInstances
      InstanceIds: "{{InstanceID}}"
    outputs:
      - Selector: "$.Reservations[0].Instances[0].PublicIpAddress"
        Type: String
        Name: IP
  - name: AddRoute53Record
    action: "aws:executeScript"
    inputs:
      Runtime: python3.7
      Handler: script_handler
      Script: |-
        import boto3
        import json

        def script_handler(events, context):

            IP = events["IP"]
            HostedZoneID = events["HostedZoneID"]
            DomainName = events["DomainName"]

            client = boto3.client("route53")

            response = client.change_resource_record_sets(
                HostedZoneId=HostedZoneID,
                ChangeBatch={
                    "Changes": [
                        {
                            "Action": "UPSERT",
                            "ResourceRecordSet": {
                                "Name": DomainName,
                                "Type": "A",
                                "TTL": 300,
                                "ResourceRecords": [
                                    {"Value": IP},
                                ],
                            },
                        },
                    ]
                },
            )
            print(response)
      InputPayload:
        IP: "{{GetEC2InstanceIP.IP}}"
        HostedZoneID: "{{HostedZoneID}}"
        DomainName: "{{DomainName}}"

Systems Managerドキュメントの実行方法

作成できたら、Systems Managerの「自己所有」のドキュメントとして保存されます。
作成したドキュメントを開いてみます。

すると、このドキュメントの概要が表示されます。

「このドキュメントがどういうものであるかの説明」や「各ステップ毎に何が行われるのか」などが表示されています。
今回の場合は、

  • EC2インスタンスを起動する
  • 起動したEC2インスタンスに自動的に割り当てられたパブリックIPアドレスを取得する
  • 取得したIPアドレスを対象にRoute53のDNSレコードを編集する

という内容になっています。
これにより、EC2の起動からDNSの書き換えまでが自動化されるので、このドキュメントを実行すれば、EC2の起動を含めた各AWS操作を行なってくれるのです。

このドキュメントを実行するために「オートメーションを実行する」を選びます。

すると実行のためのオプション選択画面が表示されます。
実行方法は「シンプルな実行」を選び、
入力パラメータのところで

  • 起動したいEC2インスタンスID
  • DNSレコードを追加したいRoute53のホストゾーンID
  • 追加したいDNSレコード名

を入力してください。

そして、入力を終えたら
「AWS CLIコマンドと共有可能な実行リンク」の欄に注目してください。

入力パラメータの欄で入力された内容を含んだ形でのURLと、AWS CLIでの実行コマンドが生成されます。
そのため、このURLをブックマークしておけば、今後再度実行する時には入力パラメーターを入力することなく実行画面まで進むことができます。AWS CLIであれば実行コマンドを叩くだけで同じ処理が実行できるようになります。

Systems Managerドキュメントの実行結果

上記までの準備ができたらドキュメントの画面上の「実行」を押します。
(なお、検証のため、あらかじめEC2インスタンスは停止しておきます。)

すると、ステップの進行状況がリアルタイムに表示されます。

まず初めはEC2インスタンスの起動です。


次に、起動したEC2インスタンスのIPアドレスが取得されて・・・

最後にRoute53でのDNSレコードが書き換えられて完了です。

では、ちゃんと機能したのかそれぞれの設定を見てみましょう
まず、EC2インスタンスは次の通り

自動的にEC2インスタンスは起動されており、「パブリックIPv4アドレス」には新しい値が割り当てられています。
Route53ではこのIPアドレスでDNSレコードが自動的に作られていると嬉しいわけです。

では、Route53の該当のDNSレコードを見てみますと・・・・

先ほどの 52.xxx.xxx.xxx ではなく、今回EC2が起動してから新たに割り当てられた 54.xxx.xxx.xxxが反映されています。

なので、冒頭にテストページを表示させていたドメイン名にアクセスすると・・・・

EC2インスタンスのIPアドレスが変わっていても同じようにアクセスできました!

まとめ

以上の設定により、ElasticIPアドレスの固定費用もかからず、EC2インスタンスの起動のたび必要だったDNSレコードの設定からも解放されたわけです。

Systems Managerは今回の"Automation"を含めてAWS内でシステムを運用する際の自動化にとても便利な機能が詰まっています。
引き続きSystems Managerに触れていき、運用の自動化にも役立てたいと思います。

今回はとても具体的な、細かいケースでしたが、何か運用自動化のヒントになれば幸いです。