5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AWS CDKでAWS::CloudFormation::Init タイプを使ってEC2インスタンスの環境構築ができるようにしてみた

Last updated at Posted at 2019-08-21

前回、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

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?