LoginSignup
4
0

More than 3 years have passed since last update.

AWS CDKでEC2 Auto Scalingをデプロイしてみる

Last updated at Posted at 2020-06-21

はじめに

Auto Scalingのテスト環境の構築をAWS CDKの勉強も兼ねて行ってみました。
EC2にCPUの負荷を与えて、想定通りにEC2がスケールアウトすることを確認したかったため、作業内容を備忘録のつもりでまとめます。

環境

  • OS: macOS Cataline 10.15.5
  • VSCode: 1.46.0
  • Node.js: v14.4.0
  • npm: 6.14.5
  • TypeScript: 3.9.5
  • CDK: 1.45.0

AWS CDKのインストール

公式の情報を参考にインストールします。

$ npm install -g aws-cdk

インストールできているか、念のため確認します。

$ cdk --version
1.45.0 (build 0cfab15)

プロジェクトの作成

CDKのプロジェクトを公式に沿って作成します。

$ mkdir test-asg
$ cd test-asg
$ cdk init app --language=typescript

コードの実装

必要なCDKのモジュールをインストールします。

$ npm install @aws-cdk/aws-autoscaling @aws-cdk/aws-ec2 @aws-cdk/aws-elasticloadbalancingv2

なお、自分が検証した際にはこのエラーに遭遇したため、package.jsonを編集して@aws-cdk/core@aws-cdk/assertのバージョンを合わせます。

package.json
{

  : (省略)

  "devDependencies": {
    // 1.45.0 -> 1.46.0
    "@aws-cdk/assert": "^1.46.0",
    "@types/jest": "^25.2.1",
    "@types/node": "10.17.5",
    "jest": "^25.5.0",
    "ts-jest": "^25.3.1",
    "aws-cdk": "1.45.0",
    "ts-node": "^8.1.0",
    "typescript": "~3.7.2"
  },
  "dependencies": {
    "@aws-cdk/aws-autoscaling": "^1.46.0",
    "@aws-cdk/aws-ec2": "^1.46.0",
    "@aws-cdk/aws-elasticloadbalancingv2": "^1.46.0",
    // 1.45.0 -> 1.46.0
    "@aws-cdk/core": "^1.46.0",
    "source-map-support": "^0.5.16"
  }
}

node_modulesディレクトリを削除し、再度インストールします。これでエラーが解消され、ビルドも可能になりました。(CDKのバージョンを最初から上げていれば、このようなことはしなくても良かったかもしれません…)

$ rm -rf node_modules
$ npm install

lib/test-asg-stack.tsを編集します。以下の点に留意して作成しました。

  • 予めAWSのコンソールでTestAsgEnvという名前のキーペアを作成しておき、SSHでログインできるようにする。
  • EC2起動時にsudo yum update -yが実行されるようにする。
  • CPU使用率が50%でスケールアウトするようにする。
  • スタック作成完了時にALBのDNS名が表示されるようにする。
lib/test-asg-stack.ts
import * as cdk from '@aws-cdk/core';
import * as autoscaling from '@aws-cdk/aws-autoscaling';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2';

export class TestAsgStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);

        const cidr = '10.0.0.0/16';

        const vpc = new ec2.Vpc(
            this,
            'test-asg-vpc', {
            cidr,
            natGateways: 1,
            subnetConfiguration: [
                {
                    cidrMask: 18,
                    name: 'public',
                    subnetType: ec2.SubnetType.PUBLIC,
                },
                {
                    cidrMask: 18,
                    name: 'private',
                    subnetType: ec2.SubnetType.PRIVATE,
                },
            ],
        }
        );

        const securityGroup = new ec2.SecurityGroup(
            this,
            'test-asg-security-group',
            {
                vpc,
                securityGroupName: 'test-asg-security-group',
                allowAllOutbound: true
            }
        );

        securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'SSH from anywhere');
        securityGroup.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.allTraffic());

        const userData = ec2.UserData.forLinux();
        userData.addCommands('sudo yum update -y');

        const alb = new elbv2.ApplicationLoadBalancer(this, 'TestAsgALB', {
            vpc,
            vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
            internetFacing: true,
            loadBalancerName: 'test-asg-alb'
        });

        const asg = new autoscaling.AutoScalingGroup(this, 'TestAutoScalingGroup', {
            vpc,
            instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.MICRO),
            machineImage: new ec2.AmazonLinuxImage(),
            desiredCapacity: 1,
            maxCapacity: 3,
            keyName: 'TestAsgEnv',
            associatePublicIpAddress: true,
            vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
            userData,
        });

        asg.addSecurityGroup(securityGroup);

        asg.scaleOnCpuUtilization('CPU50Percent', {
            targetUtilizationPercent: 50
        });

        const listener = alb.addListener('Listener', {
            port: 80
        });

        listener.addTargets('Target', {
            targets: [asg],
            port: 80
        });

        new cdk.CfnOutput(this, 'Application LoadBalancer DNS', { value: alb.loadBalancerDnsName });
    }
}

デプロイ

アプリケーションをビルドします。

$ npm run build

AWS CloudFormationのスタックをデプロイします。デプロイが完了するまで待ちます。

$ cdk deploy

Auto Scalingのテスト

CloudWatch Alarmに2つ登録されていました。もっと細かく設定すれば、条件をカスタマイズできると思います。
スクリーンショット 2020-06-21 11.10.51.png

Chaos EngineeringのツールであるGremlinでEC2にCPUの負荷(CPU 51%の攻撃を300秒間実行)を与えてみたところ、無事にスケールアウトできました。
(結果のスクリーンショットを取るのを忘れていました… 既に環境は削除済みで、GremlinのFreeアカウントの制約でターゲット数が限られているようなので事象の再現は控えます…)

おわりに

CloudFormationのyamlファイルよりも、コードで記述できるため作りやすかったですね。
ただ、思いの外「これだ!」といえる情報を見つけられなかったので、公式の仕様のドキュメントを眺めてパラメータを推測しながら、そしてIDEの補完を駆使してゴリ押ししながら作成しました。
EKSの環境もCDKで作れるので、こういうものにもチャレンジしていきたいです。

参考

AWS CDKでAutoScaling環境を作成(Single Stack / Nested Stack)
Deploy your Auto-Scaling Stack with AWS-CDK
Gremlinを使ってCPU負荷を注入する

4
0
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
4
0