CFnでクローン作成時にUser Dataでアプリを削除してみた
■経緯
現在担当している企業で、企業のメインサイトに障害が発生し、
アクセス出来なくなる事象が発生しました。
結局障害発生の原因は分からなかったのですが、
バックアップからリストアする事で復旧しました。
ただ、今後の事を考慮してメインサイトのクローンを
Event Bridge、Lambda、Cloud Formationで作成する方針になりましたが、
色々苦戦したので、記録します。
今回はEC2のクローンに絞って記載します。
■環境
AWS
■構成
Webサーバー:EC2
DB:Oracle for MySQL
■使用するAWSサービス
Event Bridge:時間になったらクローンサーバーを作成するようにスケジュール設定
Lambda:最新のバックアップからクローンを作成するようCloud FormationにIDを連携
Cloud Formation:EC2、RDSを作成
S3:Cloud Formationのyamlファイルの格納場所
1⃣私が書いたLambdaのコードは下記になります。
import boto3
import datetime
cf = boto3.client('cloudformation')
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
# ① イベントから TemplateURL を取得
template_url = event.get('TemplateURL')
if not template_url:
raise Exception("TemplateURL が event に指定されていません")
# ② 自分のアカウントが所有するすべての利用可能なAMIを取得(フィルタなし)
images = ec2.describe_images(
Owners=['self'], # 自分が作成したAMIのみ対象
Filters=[
{'Name': 'state', 'Values': ['available']}
]
)['Images']
if not images:
raise Exception("利用可能なAMIが見つかりません")
# ③ 最新のAMIを選択(作成日時が最も新しいもの)
latest_ami = max(images, key=lambda x: x['CreationDate'])['ImageId']
# ④ タイムスタンプ付きのインスタンス・スタック名
timestamp = datetime.datetime.utcnow().strftime("%Y%m%d%H%M")
instance_name = f"ec2-clone-{timestamp}"
stack_name = f"ec2-clone-stack-{timestamp}"
# ⑤ CloudFormationスタック作成
cf.create_stack(
StackName=stack_name,
TemplateURL=template_url,
Parameters=[
{'ParameterKey': 'InstanceName', 'ParameterValue': instance_name},
{'ParameterKey': 'AMIId', 'ParameterValue': latest_ami}
],
Capabilities=['CAPABILITY_NAMED_IAM']
)
return {
'status': 'EC2クローン作成開始',
'stack_name': stack_name,
'ami_id': latest_ami
}
2⃣私が書いたCloud Formationのyamlコードは下記になります。
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2クローン作成
Parameters:
InstanceName:
Type: String
AMIId:
Type: String
Resources:
ClonedEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AMIId
InstanceType: t3.nano
SubnetId: subnet-0b4536555ab5ff7f4
SecurityGroupIds:
- sg-086365a4a63319c97
Tags:
- Key: Name
Value: !Ref InstanceName
上記のコードでEC2は無事にクローンすることができたのですが、
問題が発生しました。
なんとクローン元のEC2には監視アプリが入っており、
クローン先にも当然監視アプリが複製されてしまうのですが、
監視対象のサーバーは1台だけであるため、
2台に監視エージェントが入っていることは完全にライセンス違反!
そのため、クローンした直後に監視を依頼している会社から電話連絡が入る始末!
そのため、クローン直後に監視エージェントをアンインストールする必要が出てきました。
対応策:EC2のUserDataの機能を使用して、起動時に監視エージェントをアンインストールする
処理を実装
家では監視アプリではなく、サクラエディタをクローン元にインストールしておいて、
クローン後にアンインストールされるかの検証を行いました。
サクラエディタをアンインストールするために、
修正したのはCloud Formationのyamlファイルのみです。
アプリ名は固定なので、Lambdaは修正する必要はなく、
修正したCloud FormationのyamlをS3に追加格納しました。
yamlファイルは「ec2-clone-sakuradelete-hostsadd.yaml 」です。
一応、ついでにhostsに文字を追記できるかも検証したので上記のファイル名です。

実際のyamlコードは下記です。
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2クローン作成
Parameters:
InstanceName:
Type: String
AMIId:
Type: String
Resources:
ClonedEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AMIId
InstanceType: t3.nano
SubnetId: subnet-0b4536555ab5ff7f4
SecurityGroupIds:
- sg-086365a4a63319c97
Tags:
- Key: Name
Value: !Ref InstanceName
UserData:
Fn::Base64: !Sub |
# 1. hostsファイルのパス
$hostsPath = "C:\Windows\System32\drivers\etc\hosts"
# 2. 管理者権限でファイル末尾に "test" を追記
Add-Content -Path $hostsPath -Value "`ntest"
</powershell>
上記コードを作成するにあたって引っかかった点は下記です。
User Dataの仕様として、サーバーの初回起動時のみ処理が走るようになっています。
クローンを作成することになったサーバーOSはWindows Server 2012 R2だったのですが、
EC2インスタンス起動時の User Data(ユーザーデータ) の実行可否は、
EC2Configによって管理されており、下記のファイルで
実行可否が記載されています。
C:\Program Files\Amazon\Ec2ConfigService\Settings\Config.xml
Ec2HandleUserDataがtrueの時、
実行され、falseの時は実行されません。
<Config>
...
<Ec2HandleUserData>true</Ec2HandleUserData>
...
</Config>
しかし、初回起動時は上記の値はtrueなのですが、
起動完了後はfalseになる仕様で、falseになった状態のバックアップを取って、
そのバックアップからクローンするので、クローン先の設定でもfalseとなっており、
実行されることはありません。
そのため、上記ファイルにて初回起動が完了してfalseになった後、
手動でtrueにする必要があります。
それに気づくのに随分時間がかかりました。。。
Discussion