EC2 AutoScalingを利用している環境では、OS内の更新に伴い起動元AMIをアップデートする必要が出てきます。
例えば、下記のようにAMI更新用のインスタンス(AutoScalingグループに所属しない)を用意しておき、

- AMI更新用インスタンスで、OS内の更新作業を実施
- AMI更新用インスタンスを元にAMIを作成
- 作成したAMIを元にAutoScaling起動設定を作成
- 対象のAutoScalingグループを、作成した起動設定を参照するよう更新
といった流れで行います。
今回は、SSM Automation + CloudWatch Events を利用し、(2)~(4)をスケジュール実行させてみます。
設定方法
CloudFormationスタック作成
以下のテンプレートを利用しCloudFormationスタックを作成してください。
AWSTemplateFormatVersion: "2010-09-09" Description: IAM Role and SSM Automation Document for Updating AutoScaling AMI. # ------------------------------------------------------------# # METADATA # ------------------------------------------------------------# Metadata: "AWS::CloudFormation::Interface": ParameterGroups: - Label: default: "IAM Role: CloudWatch Events executes SSM Automation" Parameters: - CloudWatchEventsRoleName - CloudWatchEventsRolePolicyName - Label: default: "IAM Role: SSM Automation updates AutoScalingGroup AMI" Parameters: - SSMAutomationRoleName - SSMAutomationRolePolicyName ParameterLabels: CloudWatchEventsRoleName: default: "IAM Role Name" CloudWatchEventsRolePolicyName: default: "IAM Policy Name" SSMAutomationRoleName: default: "IAM Role Name" SSMAutomationRolePolicyName: default: "IAM Policy Name" # ------------------------------------------------------------# # PARAMETERS # ------------------------------------------------------------# Parameters: CloudWatchEventsRoleName: Type: String Default: "EventsRoleForExecSSMAutomation" CloudWatchEventsRolePolicyName: Type: String Default: "PolicyForExecSSMAutomation" SSMAutomationRoleName: Type: String Default: "SSMRoleForUpdateAutoScalingGroupAMI" SSMAutomationRolePolicyName: Type: String Default: "PolicyForUpdateAutoScalingGroupAMI" # ------------------------------------------------------------# # RESOURCES # ------------------------------------------------------------# Resources: # IAM Role: CloudWatch Events executes SSM Automation CloudWatchEventsRole: Type: AWS::IAM::Role Properties: RoleName: !Ref CloudWatchEventsRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: !Ref CloudWatchEventsRolePolicyName PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "ssm:StartAutomationExecution" - "iam:PassRole" Resource: "*" # IAM Role: SSM Automation updates AutoScalingGroup AMI SSMAutomationRole: Type: AWS::IAM::Role Properties: RoleName: !Ref SSMAutomationRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: !Ref SSMAutomationRolePolicyName PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "autoscaling:CreateLaunchConfiguration" - "autoscaling:UpdateAutoScalingGroup" - "ec2:CreateImage" - "ec2:DescribeImages" Resource: "*" # SSM Automation Document AutomationDocument: Type: "AWS::SSM::Document" Properties: DocumentType: Automation Content: description: Automation Document for Updating AMI for AutoScaling Group schemaVersion: '0.3' assumeRole: "{{ AutomationAssumeRole }}" parameters: AutomationAssumeRole: type: String description: "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf." default: !GetAtt SSMAutomationRole.Arn InstanceId: type: String description: "(Required) Instance id of instance that ami is created from." LaunchConfigPrefix: type: String description: "(Required) Name Prefix of Launch Configuration to create." AutoScalingGroupName: type: String description: "(Required) Name of AutoScaling Group which already exists." mainSteps: - name: createImage action: aws:createImage inputs: InstanceId: "{{ InstanceId }}" ImageName: "{{ InstanceId }}_{{ global:DATE }}" NoReboot: true ImageDescription: "{{ InstanceId }}_{{ global:DATE }}" - name: CreateLaunchConfiguration action: aws:executeAwsApi inputs: Service: autoscaling Api: CreateLaunchConfiguration InstanceId: "{{ InstanceId }}" ImageId: "{{ createImage.ImageId }}" LaunchConfigurationName: "{{ LaunchConfigPrefix }}_{{ global:DATE }}" - name: UpdateAutoScalingGroup action: aws:executeAwsApi inputs: Service: autoscaling Api: UpdateAutoScalingGroup AutoScalingGroupName: "{{ AutoScalingGroupName }}" LaunchConfigurationName: "{{ LaunchConfigPrefix }}_{{ global:DATE }}" # ------------------------------------------------------------# # OUTPUTS # ------------------------------------------------------------# Outputs: AutomationDocument: Description: Automation Document Name Value: !Ref AutomationDocument
このテンプレートで、以下リソースが作成されます。
- (2)~(4)を行う為のSSM Automationドキュメント
- SSM Automationドキュメントの内容(AutoScaling AMI更新)を実行する為のIAMロール
- CloudWatch Events から SSM Automationを実行する為のIAMロール
CloudWatch Events ルールの作成
CloudWatchの操作画面で、ルールを作成します。

AutoScalingの起動元AMI更新を実施するスケジュールを設定します。
以下の場合、日本時間で毎日14:30になります。
また[ターゲットの追加]を選択しておきます。

以下の通りターゲットを設定します。
ドキュメント | [スタック名]-AutomationDocument-[ランダム文字列]
(CFnにより作成されたSSMドキュメント名) |
InstanceId | AMI更新用インスタンスのID |
AutoScalingGroupName | 対象のAutoScalingグループ名 |
LaunchConfigPrefix | 新しく作成される起動設定の接頭辞(プレフィックス) |
既存のロールを使用 | EventsRoleForExecSSMAutomation (既定のIAMロール名) |

適当な名前を設定し、ルールを作成します。

稼働確認
実際に起動元AMIが更新されているか確認してみましょう。
[インスタンスID]_[YY-MM-DD] という名前でAMIが作成されていて、

そのAMIを指定した起動設定が [指定したプレフィックス]_[YY-MM-DD] という名前で作成されていて、

対象のAutoScalingグループでその起動設定が参照されていればOKです。

更新処理の詳細はSystems Manager オートメーションの画面で確認できます。
実行IDを選択するとより詳細な内容が確認できます。

ステップごと(AMI作成、起動設定作成、AutoScalingグループ更新)の状況を確認したい場合はステップIDを選択します。

ステップ(AMI作成)の詳細が確認できました。

設定内容(CloudFormationテンプレート内容解説)
SSM Automationを実行する為のCloudWatch Events用IAMロール
CloudWatch Events(events.amazonaws.com)から、SSM Automationが実行可能なロールになっています。
... # IAM Role: CloudWatch Events executes SSM Automation CloudWatchEventsRole: Type: AWS::IAM::Role Properties: RoleName: !Ref CloudWatchEventsRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: !Ref CloudWatchEventsRolePolicyName PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "ssm:StartAutomationExecution" - "iam:PassRole" Resource: "*" ...
AutoScalingグループを更新する為のSSM用IAMロール
Systems Manager(ssm.amazonaws.com)から、AMI作成・起動設定作成・AutoScalingグループ更新が実行可能なロールになっています。
... # IAM Role: SSM Automation updates AutoScalingGroup AMI SSMAutomationRole: Type: AWS::IAM::Role Properties: RoleName: !Ref SSMAutomationRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: !Ref SSMAutomationRolePolicyName PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "autoscaling:CreateLaunchConfiguration" - "autoscaling:UpdateAutoScalingGroup" - "ec2:CreateImage" - "ec2:DescribeImages" Resource: "*" ...
SSM Automationドキュメント
CloudFormationテンプレートもSSMドキュメントもYAMLなので分かりにくいですが、
Content以下がSSMドキュメントの内容です。
... # SSM Automation Document AutomationDocument: Type: "AWS::SSM::Document" Properties: DocumentType: Automation Content: description: Automation Document for Updating AMI for AutoScaling Group schemaVersion: '0.3' assumeRole: "{{ AutomationAssumeRole }}" parameters: AutomationAssumeRole: type: String description: "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf." default: !GetAtt SSMAutomationRole.Arn InstanceId: type: String description: "(Required) Instance id of instance that ami is created from." LaunchConfigPrefix: type: String description: "(Required) Name Prefix of Launch Configuration to create." AutoScalingGroupName: type: String description: "(Required) Name of AutoScaling Group which already exists." mainSteps: - name: createImage action: aws:createImage inputs: InstanceId: "{{ InstanceId }}" ImageName: "{{ InstanceId }}_{{ global:DATE }}" NoReboot: true ImageDescription: "{{ InstanceId }}_{{ global:DATE }}" - name: CreateLaunchConfiguration action: aws:executeAwsApi inputs: Service: autoscaling Api: CreateLaunchConfiguration InstanceId: "{{ InstanceId }}" ImageId: "{{ createImage.ImageId }}" LaunchConfigurationName: "{{ LaunchConfigPrefix }}_{{ global:DATE }}" - name: UpdateAutoScalingGroup action: aws:executeAwsApi inputs: Service: autoscaling Api: UpdateAutoScalingGroup AutoScalingGroupName: "{{ AutoScalingGroupName }}" LaunchConfigurationName: "{{ LaunchConfigPrefix }}_{{ global:DATE }}" ...
- createImageステップで(インスタンス再起動無しで) [インスタンスID]_[YY-MM-DD] というAMIを作成し、
- CreateLaunchConfigurationステップでそのAMIを元に [指定したプレフィックス]_[YY-MM-DD] という起動設定を作成し、
- UpdateAutoScalingGroupステップで、その起動設定を参照するよう対象のAutoScalingグループを更新しています。
また、CreateLaunchConfigurationステップではInstanceIdというオプションを指定しています。
これは指定したインスタンスのプロパティを引き継いだ起動設定を作成してくれるオプションです。
以上です。
投稿者プロフィール
- 2015年8月入社。弊社はインフラ屋ですが、アプリも作ってみたいです。