この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWSチームのすずきです。
ImageBuilder をサポートした CloudFormationと、AMI IDをサポートした パラメータストアを利用して、 AMI作成から、EC2のオートスケール起動まで 1つの CloudFormationのスタックでの実装を試す機会がありましたので、紹介させて頂きます。
CloudFormation
imagebuilder-install-kernelng-jq.yaml
IAM
- AMIの雛形となる EC2環境で利用するIAMロール(インスタンスプロファイル)を設定します。
- ImageBuilder が必須とする権限、管理ポリシー「AmazonSSMManagedInstanceCore」「EC2InstanceProfileForImageBuilder」を利用して付与します。
- S3へのログ出力を利用するため、ログ出力先とするS3の設定をインラインポリシーで追加しています。
Ec2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/EC2InstanceProfileForImageBuilder
Ec2RolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: Ec2RolePolicies
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:List*
Resource:
- '*'
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub 'arn:aws:s3:::${S3Bucketlog}'
- !Sub 'arn:aws:s3:::${S3Bucketlog}/*'
Roles:
- !Ref 'Ec2IAMRole'
Ec2IAMProfile:
Type: AWS::IAM::InstanceProfile
DependsOn: Ec2IAMRole
Properties:
Path: /
Roles:
- !Ref 'Ec2IAMRole'
S3
- Image Builder のログ出力先として利用するS3バケットを作成します。
- AMI作成時、System Manager「aws:runCommand」のログ出力先となります。
S3Bucketlog:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${AWS::StackName}-log-${AWS::Region}-${AWS::AccountId}'
LifecycleConfiguration:
Rules:
- Id: AutoDelete
Status: Enabled
ExpirationInDays: 14
ImageBuilder
BuildComponent
- ビルド用、テスト用、2つの設定を用意します。
- 「jq」コマンドを Amazon Linux2のリポジトリ、 新しいLinuxカーネルを拡張リポジトリからインストールしています。
BuildComponent:
Type: AWS::ImageBuilder::Component
Properties:
Data: |
name: yum_install
description: jq_install
schemaVersion: 1.0
phases:
- name: build
steps:
- name: UpdateOS
action: UpdateOS
- name: yum_update
action: ExecuteBash
inputs:
commands:
- yum update -y
- name: jq_install
action: ExecuteBash
inputs:
commands:
- yum install jq -y
- name: kernel_ng_install
action: ExecuteBash
inputs:
commands:
- amazon-linux-extras install -y kernel-ng
- name: validate
steps:
- name: jq_install
action: ExecuteBash
inputs:
commands:
- rpm -qi jq
Name: !Sub '${AWS::StackName}-build'
Platform: Linux
Version: 1.0.0
TestComponent
- テストは指定したコマンドの実行結果
$?
の値が 0 以外である場合、異常とみなします。 - 今回はインストールした jq コマンドが存在し、実行可能な状態である事を、バージョン情報の取得で判定する設定にしました。
TestComponent:
Type: AWS::ImageBuilder::Component
Properties:
Data: |
name: jq_test
description: jq_test
schemaVersion: 1.0
phases:
- name: test
steps:
- name: check_status
action: ExecuteBash
inputs:
commands:
- jq --version
Name: !Sub '${AWS::StackName}-test'
Platform: Linux
Version: 1.0.0
ImageRecipe
- ビルド用と、テスト用のコンポーネントを登録します。
- 利用するAMIは、imagebuilder に登録された Amazon Linux 2の最新AMIを利用する指定 (x.x.x) としました。
ImageRecipe:
Type: AWS::ImageBuilder::ImageRecipe
Properties:
Components:
- ComponentArn: !Ref 'BuildComponent'
- ComponentArn: !Ref 'TestComponent'
Name: !Sub '${AWS::StackName}-Recipe'
ParentImage: !Sub 'arn:aws:imagebuilder:${AWS::Region}:aws:image/amazon-linux-2-x86/x.x.x'
Version: 1.0.0
- 「ParentImage」は、SSM Agent がインストール済みの AMIを ID指定で利用する事も可能です。
- AmazonLinux 2のARM用AMI (ami-08360a37d07f61f88: amzn2-ami-hvm-2.0.20200406.0-arm64-gp2)も利用可能でした。
Properties:
ParentImage: ami-08360a37d07f61f88
InfrastructureConfiguration
- AMIの雛形となるEC2インスタンスと、ログ出力先の設定を行います。
InfrastructureConfiguration:
Type: AWS::ImageBuilder::InfrastructureConfiguration
Properties:
InstanceProfileName: !Ref 'Ec2IAMProfile'
InstanceTypes:
- t3.small
Name: !Sub '${AWS::StackName}-InfrastructureConfiguration'
SecurityGroupIds: []
TerminateInstanceOnFailure: true
Logging:
S3Logs:
S3BucketName: !Ref 'S3Bucketlog'
S3KeyPrefix: !Sub '${AWS::StackName}'
Image
- ImageRecipeを利用してAMIを作成する指定を行います。
Image:
Type: AWS::ImageBuilder::Image
Properties:
ImageRecipeArn: !Ref 'ImageRecipe'
InfrastructureConfigurationArn: !Ref 'InfrastructureConfiguration'
ImageTestsConfiguration:
ImageTestsEnabled: true
TimeoutMinutes: 60
SSM::Parameter
!GetAtt 'Image.ImageId'
で作成した AMIIDを取得し、パラメータストアに「aws:ec2:image」として登録します。
Parameter:
Type: AWS::SSM::Parameter
Properties:
DataType: aws:ec2:image
Name: !Sub '${AWS::StackName}-amiid'
Type: String
Value: !GetAtt 'Image.ImageId'
Description: !Sub '${AWS::StackName}-amiid'
LaunchTemplate
- パラメータストアに登録されたAMIIDを
!Sub '{{resolve:ssm:${Parameter}:1}}'
で呼び出し、EC2を起動するテンプレートを作成します。 - インスタンスプロファイル、今回は雛形用の設定をそのまま流用する設定としました。
Ec2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
IamInstanceProfile:
Arn: !GetAtt 'Ec2IAMProfile.Arn'
ImageId: !Sub '{{resolve:ssm:${Parameter}:1}}'
InstanceType: t3.small
AutoScalingGroup
- ImageBuilder で 作成したAMI を利用して、EC2インスタンスを1台 デフォルトVPCにスポットで起動する設定としました。
Ec2AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AvailabilityZones: !GetAZs ''
DesiredCapacity: 1
MinSize: 0
MaxSize: 1
HealthCheckType: EC2
MixedInstancesPolicy:
InstancesDistribution:
OnDemandBaseCapacity: 0
OnDemandPercentageAboveBaseCapacity: 0
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref 'Ec2LaunchTemplate'
Version: !GetAtt 'Ec2LaunchTemplate.LatestVersionNumber'
Overrides:
- InstanceType: t3a.micro
- InstanceType: t3.micro
実行例
CloudFormationの実行開始から、今回の設定では約24分でAMIが作成できました。
イベント | 実行時刻 | 経過時間 |
---|---|---|
CloudFormation実行開始 | 15:23:32 | - |
AMI作成開始 | 15:26:08 | 0:02:36 |
AMI作成完了 | 15:47:42 | 0:24:10 |
EC2起動開始 | 15:48:03 | 0:24:31 |
EC2起動完了 | 15:48:37 | 0:25:05 |
更新
ビルド、テスト用のコンポーネントを更新した場合、Component、ImageRecipe の それぞれの「Version」を 1.0.0 → 1.0.1 と更新し、CloudFormation管理リソースの置換を行うことで Update StackによるAMIの更新が可能です。
Type: AWS::ImageBuilder::Component
Properties:
Version: 1.0.1
Type: AWS::ImageBuilder::ImageRecipe
Properties:
Version: 1.0.1
CloudFormationの更新後、ImageBuilder上から、古い AMIは削除されます。 作成済みのAMIと、スナップショットはそのまま残り続けますので、適宜EC2コンソールなど利用して撤去して下さい。
まとめ
ImageBuilderを用いて、セキュリティパッチの反映や、動作テストまで完了したAMIを用意する事で、 EC2の起動時間短縮や、確実な起動が期待できます。
実際の利用にあたっては、ImageBuilderと、EC2の起動設定(起動テンプレート、オートスケール)は 別のCloudFormationスタック管理が望ましい場合もあると思われますが、 開発環境などでシンプルな管理が望ましい場合には、今回紹介した方法をお試し下さい。