【AWS】リソースからスタックを喰わせるの巻

2021年1月28日

 自分現場でAWS環境の開発・運用担当もやってるんで作業依頼対応なんていうものは切っても切り離せぬ飯のタネであるわけなんですが、お客さんのところで本格的に舵を切ったこともあり利用率が爆上りで、さらに先行対応していた案件が軒並みテスト行程に入ってきて急に立て込んでるという塩梅です。
 これまた基本は共用基盤として利用想定で、型ありきという方針で無駄開発リソースを抑えるのでバックアップとかはの取得は世代含めて仕様決まっててリストアも基盤担保してますよという基盤屋としてはご同輩の雇用を奪う方面の活動なんで若干後ろ暗いところもあるわけですがこれも時代の流れなんでしょう。
 と思いきやまだまだ時代に逆光するのが泥臭さ満載の基盤構築対応ってやつですよ。オンプレ忘れてたまるか的な動きが正直、たまらないですね。

 当たりまちゃ当たり前なんですが当然、環境に提供依頼は基本CloudFormation スタックを利用しています。
 そんな中で最近大いに悩まされているのが『リストアテスト依頼』なんですな。

いや!ちょっと待て!だから担保してるってつってんだろーが!

と、AWS部隊側のお客様の間で「なんでこっちでリスク持ってるから大丈夫だと説明しているのにやりたがるんだ」と若干キレ気味です。
でもねぇ仕方ないんですよ。だって請負パートナーからするとリスク性のあるテストだし確認こみで1日仕事でしょ。
開発・ステージング・本番ってやればそこそこの人月確保できるもん。そりゃ、やりたがりますよ。
 ましてや運用依頼でリストアは作業提供元持ちですわよ。
 自分たちがバックアップとリストアやらないなら明らかにボーナスステージです。
 だって俺もその立場ならすっとボケてテスト行程に工数積んで見積るもの。

 で結局のところお金の絡む契約というお大人の事情でやらないの選択は無いので依頼作業をこちらが受けることになります。
 そういうのに限って便利な言葉「緊急」をつけた短スパン依頼なんですね。準備もへったくれもありません。
 リストア自体はマネコンポチポチすれば良いのでわけないんですが、
  「リストア後はスタックの管理から外れてしまう
 というのが大きな悩みのタネなんであります。

 でもCloudFormation スタックにインポートは確か2019年の11月頃に機能が追加されているのです。
 便利そうな機能ですが情報少なくて面倒くさくて試してなかったので良い機会なんでついでに一つ実験してみることにしました。

 実は個人手持ちのAWS環境のリソースはCloudFormation スタックからほぼ作ってないので、試しにEC2をスタック登録してみることにしました。
 リソース自体をCloudFormation スタックに登録させる様に仕込むのは実に簡単。
 以下はYAMLの場合ですがこんな感じにリソースのTypeの指定の下に DeletionPolicy: Retain を入れるだけ。
 元々はリソース自体を削除せずに、スタックだけ消す場合に使う指定ですね。

Resources:
  【適当にリソースの名前】:
    Type: 【リソースタイプ】
    DeletionPolicy: Retain
<以下、略>

で、今回実験に使う EC2はこんな構成。
・OS:Amazon Linux 2
・データボリューム用に15GBnのgp2のEBSを追加
・KMSの暗号化無し
・IPv4 パブリック IP は有効
とりあえず、DeletionPolicy: Retainを仕込んだスタックを作成済環境にそって以下の様に作って見ます。

WSTemplateFormatVersion: 2010-09-09

Resources:
  #-----------------------------------------------------------------------------
  # 【EC2ホスト名】
  #-----------------------------------------------------------------------------
  【EC2ホスト名】:                                               # ここは - (ハイフン)とか使えないので、ホスト名に入っている場合ここは別名で
    Type: AWS::EC2::Instance
    DeletionPolicy: Retain
    Properties:
      AvailabilityZone: ap-northeast-1a                 # AZは適宜変更
      BlockDeviceMappings:
        - DeviceName: /dev/xvda                             #    RHELとかWindowsとかだと違うので適宜変更
          Ebs:
            VolumeType: gp2                                      # io1とかio2使う場合はIopsもセットで定義
            VolumeSize: 【システムディスクの容量】
      DisableApiTermination: false
      EbsOptimized: false
      IamInstanceProfile: ec2-devrole
      ImageId: 【利用するAMI ID】
      InstanceType: 【利用するインスタンスタイプ】
      InstanceInitiatedShutdownBehavior: stop
      KeyName: 【キーペア名】
      Monitoring: true
      PrivateIpAddress : 【プライベート IP】
      SecurityGroupIds:
        - 【セキュリティグループID】                    #複数設定する同じ様にこの下に追加
      SubnetId: 【サブネット ID】
      Tenancy: default
      NetworkInterfaces:                                         #パブリックを有効にしている場合は必要
      - GroupSet:
        - 【セキュリティグループID】                    #複数設定する同じ様にこの下に追加
        AssociatePublicIpAddress: 'true'
        DeviceIndex: '0'
        DeleteOnTermination: 'true'
        SubnetId:
          【サブネット ID】
      Tags:
        - Key: Name
          Value: 【 EC2ホスト名】
        - Key: System
          Value: 【好きにどうぞ】
      UserData:                                                     #以下ユーザデータは趣味
        Fn::Base64: !Sub |
          #! /bin/bash
          sudo su -
          instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
          echo $instance_id >> /home/ec2-user/instance.txt
 
  【EC2ホスト名】AddVolumes01:                 # ここは - (ハイフン)とか使えないので、ホスト名に入っている場合ここは別名で           
    Type: AWS::EC2::Volume
    DeletionPolicy: Retain
    Properties:
      AvailabilityZone: ap-northeast-1a            # AZは適宜変更
#      Encrypted: true                                        # KMSで暗号化する場合は有効
#      KmsKeyId: 【KMSキーのARN】             # KMSで暗号化する場合は上と合わせ設定
      Size: 【追加EBSの容量】
      VolumeType: gp2                             # io1とかio2使う場合はIopsもセットで定義
      Tags:
        - Key: Name
          Value: 【EC2ホスト名】-datavol 
        - Key: System
          Value: 【お好きにどうぞ】

上記のスタックは急ごしらえなので突っ込み所もあるかと思うのでご指摘あればコメント等いただけると嬉しいです。
このスタックを「すべのサービス>CloudFormation>スタック」に移動してスタックの作成から「既存のリソースを使用(リソースをインポート)」を選択します。

「概要をインポート」の画面が表示されますが、テンプレートや識別子を準備しとけ的なページなのでさっと一読したら「次へ」
「テンプレートの指定」は新規作成の時と変わらないです。今回はローカルからアップロードのなので以下のように選択したらファイルを選択して「次へ」

新規と違うのはインポートするリソースの指定があります。以下の画面でスタックでインポートしたい対象のリソースのIDを入力して「次へ」

リソースの詳細のページが表示された、以下の様に登録したいスタックの名前を入力して「次へ」

概要をインポートの画面が表示されたら、一番下の「変更」の結果を確認します。
対象のリソースが「import」で表示されていることを確認したらスタックを実行します。

<中略>

スタックが完了したら、対象リソースの「タグ」を確認します。
スタックで作成していなかったリソースにも以下のようなcloufformationの管理タグが追加されていれば成功です。
以降はインポートで登録したスタックを変更・更新して管理できます。

ちなみに、スタックだけを消してリソースを登録しなおす場合は値が変更されます。
あと、DeletionPolicy: Retainを追加すると対象のリソースは当然、スタックの削除をしても消えずに残ります。
スタックを削除しても以下の様にスキップされます。

 便利なんですけど、システム運用廃止とかでまとめて管理リソースを消すとかに使うなら事前にDeletionPolicy: Retainを消したスタックで更新しないといけないので注意ですね。あと運用変更で消すのと登録が混ざる場合は事故るとまずいので事前のドライランの確認がキモですかね。
 この程度のなんちゃってスタックならいいですが、業務本物のスタックを扱うなら自前で支援ツール作るか、部品化とかとないと素で使うのはちょっと危ないかなぁ・・