ImageBuilder をサポートした CloudFormation で AMI作成から EC2のオートスケール起動まで実装してみた
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スタック管理が望ましい場合もあると思われますが、 開発環境などでシンプルな管理が望ましい場合には、今回紹介した方法をお試し下さい。