前回、AWS Cloud Development Kit(AWS CDK)を利用してEC2インスタンスを立ち上げてみたのですが、AWS CDKでAWS::CloudFormation::Initタイプが利用できるのかも確認してみました。
AWS Cloud Development Kit(AWS CDK)でEC2インスタンスを立ち上げてみる - Qiita
https://qiita.com/kai_kou/items/e35fd8c6af7dff9f2624
AWS::CloudFormation::Init タイプについては下記をご参考ください。
AWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた - Qiita
https://qiita.com/kai_kou/items/e1ef9fa6fb0375dcf15f
前提
- AWSアカウントがある
- AWS CLIが利用できる
- Node.jsがインストール済み
実装
前回記事の実装をベースにしてAWS::CloudFormation::Initタイプの定義を追加しました。
AWS Cloud Development Kit(AWS CDK)でEC2インスタンスを立ち上げてみる - Qiita
https://qiita.com/kai_kou/items/e35fd8c6af7dff9f2624
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://qiita.com/kai_kou/items/e35fd8c6af7dff9f2624
AWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた - Qiita
https://qiita.com/kai_kou/items/e1ef9fa6fb0375dcf15f
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