前回、AWS Cloud Development Kit(AWS CDK)を利用してEC2インスタンスを立ち上げてみたのですが、AWS CDKでAWS::CloudFormation::Initタイプが利用できるのかも確認してみました。
AWS Cloud Development Kit(AWS CDK)でEC2インスタンスを立ち上げてみる – Qiita
https://cloudpack.media/48912
AWS::CloudFormation::Init タイプについては下記をご参考ください。
AWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた – Qiita
https://cloudpack.media/48540
前提
- AWSアカウントがある
- AWS CLIが利用できる
- Node.jsがインストール済み
実装
前回記事の実装をベースにしてAWS::CloudFormation::Initタイプの定義を追加しました。
AWS Cloud Development Kit(AWS CDK)でEC2インスタンスを立ち上げてみる – Qiita
https://cloudpack.media/48912
import cdk = require('@aws-cdk/core'); import ec2 = require('@aws-cdk/aws-ec2/lib'); export class UseCdkEc2Stack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); let vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcId: this.node.tryGetContext('vpc_id') }); const cidrIp = this.node.tryGetContext('cidr_ip'); const securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc }); securityGroup.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.allTraffic()); securityGroup.addIngressRule(ec2.Peer.ipv4(cidrIp), ec2.Port.tcp(22)); let ec2Instance = new ec2.CfnInstance(this, 'myInstance', { imageId: new ec2.AmazonLinuxImage().getImage(this).imageId, instanceType: new ec2.InstanceType('t3.small').toString(), networkInterfaces: [{ associatePublicIpAddress: true, deviceIndex: '0', groupSet: [securityGroup.securityGroupId], subnetId: vpc.publicSubnets[0].subnetId }], keyName: this.node.tryGetContext('key_pair') }); ec2Instance.addOverride('Metadata', { 'AWS::CloudFormation::Init': { 'config': { 'commands': { 'test': { 'command': "echo $STACK_NAME test", 'env': { 'STACK_NAME': this.stackName } } }, } } }); let userData = ec2.UserData.forLinux(); userData.addCommands( '/opt/aws/bin/cfn-init', `--region ${this.region}`, `--stack ${this.stackName}`, `--resource ${ec2Instance.logicalId}` ); userData.addCommands('echo', 'hoge!'); ec2Instance.userData = cdk.Fn.base64(userData.render()); new cdk.CfnOutput(this, 'Id', { value: ec2Instance.ref }); new cdk.CfnOutput(this, 'PublicIp', { value: ec2Instance.attrPublicIp }); } }
公式ドキュメントを漁ってみたものの良い情報が得られず、下記Issueを参考にしました。
Add support for AWS::CloudFormation::Init · Issue #777 · aws/aws-cdk
https://github.com/aws/aws-cdk/issues/777
ec2: cfn-init support in ASGs · Issue #1413 · aws/aws-cdk
https://github.com/aws/aws-cdk/issues/1413
feat(aws-ec2): add support for CloudFormation::Init by rix0rrr · Pull Request #792 · aws/aws-cdk
https://github.com/aws/aws-cdk/pull/792
追加した実装は以下となります。
ポイントとしてec2Instance.addOverride()
でメタデータを追加してAWS::CloudFormation::Init
タイプで定義を追加します。/opt/aws/bin/cfn-init
の--resource
オプションでリソース名を指定するのにec2Instance
を作ってからuserData
を設定することで、ec2Instance.logicalId
が利用できるようにしています。ベタ書きでもいいっちゃいいですね。
ec2Instance.addOverride('Metadata', { 'AWS::CloudFormation::Init': { 'config': { 'commands': { 'test': { 'command': "echo $STACK_NAME test", 'env': { 'STACK_NAME': this.stackName } } }, } } }); let userData = ec2.UserData.forLinux(); userData.addCommands( '/opt/aws/bin/cfn-init', `--region ${this.region}`, `--stack ${this.stackName}`, `--resource ${ec2Instance.logicalId}` ); userData.addCommands('echo', 'hoge!'); ec2Instance.userData = cdk.Fn.base64(userData.render()); (略)
デプロイしてみる
> cdk deploy \ -c vpc_id=vpc-xxxxxxxx \ -c key_pair=cdk-test-ec2-key \ -c cidr_ip=xxx.xxx.xxx.xxx/32 This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening). Please confirm you intend to make the following modifications: Security Group Changes ┌───┬──────────────────────────┬─────┬────────────┬────────────────────┐ │ │ Group │ Dir │ Protocol │ Peer │ ├───┼──────────────────────────┼─────┼────────────┼────────────────────┤ │ + │ ${SecurityGroup.GroupId} │ In │ TCP 22 │ xxx.xxx.xxx.xxx/32 │ │ + │ ${SecurityGroup.GroupId} │ Out │ Everything │ Everyone (IPv4) │ └───┴──────────────────────────┴─────┴────────────┴────────────────────┘ (NOTE: There may be security-related changes not in this list. See http://bit.ly/cdk-2EhF7Np) Do you wish to deploy these changes (y/n)? y UseCdkEc2Stack: deploying... useCdkEc2Stack: creating CloudFormation changeset... 0/4 | 14:30:29 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata 0/4 | 14:30:30 | CREATE_IN_PROGRESS | AWS::EC2::SecurityGroup | SecurityGroup (SecurityGroupDD263621) 0/4 | 14:30:32 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated 1/4 | 14:30:32 | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata 1/4 | 14:30:35 | CREATE_IN_PROGRESS | AWS::EC2::SecurityGroup | SecurityGroup (SecurityGroupDD263621) Resource creation Initiated 2/4 | 14:30:37 | CREATE_COMPLETE | AWS::EC2::SecurityGroup | SecurityGroup (SecurityGroupDD263621) 2/4 | 14:30:39 | CREATE_IN_PROGRESS | AWS::EC2::Instance | myInstance 2/4 | 14:30:40 | CREATE_IN_PROGRESS | AWS::EC2::Instance | myInstance Resource creation Initiated`` 3/4 | 14:30:56 | CREATE_COMPLETE | AWS::EC2::Instance | myInstance 4/4 | 14:30:59 | CREATE_COMPLETE | AWS::CloudFormation::Stack | UseCdkEc2Stack ☑︎ UseCdkEc2Stack Outputs: UseCdkEc2Stack.PublicIp = xxx.xxx.xxx.xxx UseCdkEc2Stack.Id = i-xxxxxxxxxxxxxxxxx Stack ARN: arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/UseCdkEc2Stack/72304c90-b41d-11e9-b604-129cd46a326a
デプロイできたらSSHアクセスして実行ログを確認してみます。
> ssh -i cdk-test-ec2-key \ ec2-user@xxx.xxx.xxx.xxx $ cat /var/log/cfn-init.log 2019-08-01 05:31:11,740 [INFO] -----------------------Starting build----------------------- 2019-08-01 05:31:11,740 [INFO] Running configSets: default 2019-08-01 05:31:11,741 [INFO] Running configSet default 2019-08-01 05:31:11,742 [INFO] Running config config 2019-08-01 05:31:11,746 [INFO] Command test succeeded 2019-08-01 05:31:11,746 [INFO] ConfigSets completed 2019-08-01 05:31:11,746 [INFO] -----------------------Build complete----------------------- $ cat /var/log/cfn-init-cmd.log 2019-08-01 05:31:11,742 P2090 [INFO] ************************************************************ 2019-08-01 05:31:11,742 P2090 [INFO] ConfigSet default 2019-08-01 05:31:11,743 P2090 [INFO] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2019-08-01 05:31:11,743 P2090 [INFO] Config config 2019-08-01 05:31:11,743 P2090 [INFO] ============================================================ 2019-08-01 05:31:11,743 P2090 [INFO] Command test 2019-08-01 05:31:11,746 P2090 [INFO] -----------------------Command Output----------------------- 2019-08-01 05:31:11,746 P2090 [INFO] UseCdkEc2Stack test 2019-08-01 05:31:11,746 P2090 [INFO] ------------------------------------------------------------ 2019-08-01 05:31:11,746 P2090 [INFO] Completed successfully. $ cat /var/log/cloud-init-output.log (略) Updated: bind-libs.x86_64 32:9.8.2-0.68.rc1.60.amzn1 bind-utils.x86_64 32:9.8.2-0.68.rc1.60.amzn1 kernel-tools.x86_64 0:4.14.133-88.105.amzn1 python27-jinja2.noarch 0:2.7.2-3.16.amzn1 vim-common.x86_64 2:8.0.0503-1.46.amzn1 vim-enhanced.x86_64 2:8.0.0503-1.46.amzn1 vim-filesystem.x86_64 2:8.0.0503-1.46.amzn1 vim-minimal.x86_64 2:8.0.0503-1.46.amzn1 Complete! Cloud-init v. 0.7.6 running 'modules:final' at Thu, 01 Aug 2019 05:31:11 +0000. Up 18.18 seconds. hoge! Cloud-init v. 0.7.6 finished at Thu, 01 Aug 2019 05:31:11 +0000. Datasource DataSourceEc2. Up 18.77 seconds
ユーザーデータの/opt/aws/bin/cfn-init
コマンド実行でメタデータにAWS::CloudFormation::Init
タイプで指定したコマンドが実行されました。やったぜ。
まとめ
メタデータの指定について、もっと良い実装ができそうですが、ひとまずAWS CDKでもAWS::CloudFormation::Init
タイプを利用できるのが確認できたので満足です。
参考
AWS Cloud Development Kit(AWS CDK)でEC2インスタンスを立ち上げてみる – Qiita
https://cloudpack.media/48912
AWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた – Qiita
https://cloudpack.media/48540
Add support for AWS::CloudFormation::Init · Issue #777 · aws/aws-cdk
https://github.com/aws/aws-cdk/issues/777
ec2: cfn-init support in ASGs · Issue #1413 · aws/aws-cdk
https://github.com/aws/aws-cdk/issues/1413
feat(aws-ec2): add support for CloudFormation::Init by rix0rrr · Pull Request #792 · aws/aws-cdk
https://github.com/aws/aws-cdk/pull/792
元記事はこちら
「AWS CDKでAWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた」