0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS Lambdaでなんちゃってオートスケーリング

Last updated at Posted at 2024-09-29

現在運用中のELB配下にあるEC2インスタンスの負荷が高くなってきたため、負荷の高い時間帯のみEC2インスタンスを追加してELBに登録させるという処理をLambdaを使って行った際の備忘録です。

※運用中のELBはNLBですが、ALBでもだいたい同じだと思います。

・負荷の高い時間帯になったら:EC2インスタンスの起動>ELBへの登録
・負荷の低い時間帯になったら:ELBから削除>EC2インスタンスの停止

1. ポリシーの作成(EC2インスタンスの起動・停止用)

「IAM > ポリシー > ポリシーの作成」に進みます。

サービスからEC2を選択して下記アクションを許可します。

ec2:Describe
ec2:Start
ec2:Stop
ポリシー名:Auto_EC2-Policy

※分かりやすい適当な名前を入力して保存

2. ポリシーの作成(ELBへの登録・削除用)

再度「IAM > ポリシー > ポリシーの作成」に進みます。

サービスからELB v2を選択して下記アクションを許可します。

RegisterTargets
DeregisterTargets
ポリシー名:Auto_ELB-Policy

※ポリシー名に分かりやすい適当な名前を入力して保存

3. ロールの作成(EC2インスタンスの起動・停止用)

「IAM > ロール > ロールの作成」に進みます。

下記を選択して次へ

信頼されたエンティティタイプ:AWSのサービス
ユースケース:Lambda
許可を追加で「Auto_EC2-Policy」を選択して次へ
ロール名:Auto_EC2-Role

※分かりやすい適当な名前を入力して保存

4. ロールの作成(ELBへの登録・削除用)

再度「IAM > ロール > ロールの作成」に進みます。

下記を選択して次へ

信頼されたエンティティタイプ:AWSのサービス
ユースケース:Lambda
許可を追加で「Auto_ELB-Policy」を選択して次へ
ロール名:Auto_ELB-Role

※分かりやすい適当な名前を入力して保存

5. Lambdaの設定(EC2インスタンスの起動用)

「Lambda > 関数 > 関数の作成」に進みます。

下記を入力・選択して次へ

関数名:EC2_Start_Service (※分かりやすい適当な名前を入力)
ランタイム:Node.js 18.xを選択
アーキテクチャ:x86_64
デフォルトの実行ロールの変更:既存のロールを使用する
既存のロール:Auto_EC2-Role

コードのindex.mjsタブに下記を入力

import { EC2Client, DescribeInstancesCommand, StartInstancesCommand, StopInstancesCommand } from '@aws-sdk/client-ec2';

const INSTANCE_ID = ['インスタンスID1', 'インスタンスID2']; 

const ec2 = new EC2Client({
    region: "ap-northeast-1",
});

export const handler = async (event) => {
    await ec2.send(new StartInstancesCommand({ InstanceIds: INSTANCE_ID }));

    let message = INSTANCE_ID.length + '台のインスタンスが起動されました。( ';
    message += INSTANCE_ID.join(" / ") + ' )';

    return { message };
};

6. Lambdaの設定(EC2インスタンスの停止用)

「Lambda > 関数 > 関数の作成」に進みます。

下記を入力・選択して次へ

関数名:EC2_Stop_Service (※分かりやすい適当な名前を入力)
ランタイム:Node.js 18.xを選択
アーキテクチャ:x86_64
デフォルトの実行ロールの変更:既存のロールを使用する
既存のロール:Auto_EC2-Role

コードのindex.mjsタブに下記を入力

import { EC2Client, DescribeInstancesCommand, StartInstancesCommand, StopInstancesCommand } from '@aws-sdk/client-ec2';

const INSTANCE_ID = ['インスタンスID1', 'インスタンスID2']; 

const ec2 = new EC2Client({
    region: "ap-northeast-1",
});

export const handler = async (event) => {
    await ec2.send(new StopInstancesCommand({ InstanceIds: INSTANCE_ID }));

    let message = INSTANCE_ID.length + '台のインスタンスが停止されました。( ';
    message += INSTANCE_ID.join(" / ") + ' )';

    return { message };
};

7. Lambdaの設定(ELBへの登録用)

「Lambda > 関数 > 関数の作成」に進みます。

下記を入力・選択して次へ

関数名:ELB_Register_Service (※分かりやすい適当な名前を入力)
ランタイム:Node.js 18.xを選択
アーキテクチャ:x86_64
デフォルトの実行ロールの変更:既存のロールを使用する
既存のロール:Auto_ELB-Role

コードのindex.mjsタブに下記を入力

import { ElasticLoadBalancingV2Client, RegisterTargetsCommand , DeregisterTargetsCommand } from '@aws-sdk/client-elastic-load-balancing-v2';

const ARN = [
    {
        arn: 'ターゲットグループ1',
        ec2: [
            {
                id: 'インスタンスID1',
                port: 80
            },
            {
                id: 'インスタンスID2',
                port: 80
            }
        ]
    },
    {
        arn: 'ターゲットグループ2',
        ec2: [
            {
                id: 'インスタンスID1',
                port: 443
            },
            {
                id: 'インスタンスID2',
                port: 443
            }
        ]
    }
];

const elbv2 = new ElasticLoadBalancingV2Client({
    region: "ap-northeast-1",
});

export const handler = async (event) => {
    let message = "RegisterTargets : ";

    for (let i = 0; i < ARN.length; i++) {
        if (i > 0) message += ' / ';
        message += ARN[i].arn + ' -> ';

        let input = {
            TargetGroupArn: ARN[i].arn, 
            Targets: []
        };

        const ec2 = ARN[i].ec2;

        message += '[ ';

        for (let j = 0; j < ec2.length; j++) {
            input.Targets.push(
                { 
                    Id: ec2[j].id,
                    Port: ec2[j].port
                }
            );

            if (j > 0) message += ', ';
            message += ec2[j].id+':'+ec2[j].port;
        }

        message += ' ]';

        await elbv2.send(new RegisterTargetsCommand(input));
    }

    return { message };

};

※ターゲットグループ(ARN)は「EC2 > ロードバランサー > 対象のLB名 > リスナー」にあるターゲットグループ名をクリックするとARNの詳細を確認できます。

8. Lambdaの設定(ELBからの削除用)

「Lambda > 関数 > 関数の作成」に進みます。

下記を入力・選択して次へ

関数名:ELB_Deregister_Service (※分かりやすい適当な名前を入力)
ランタイム:Node.js 18.xを選択
アーキテクチャ:x86_64
デフォルトの実行ロールの変更:既存のロールを使用する
既存のロール:Auto_ELB-Role

コードのindex.mjsタブに下記を入力

import { ElasticLoadBalancingV2Client, RegisterTargetsCommand , DeregisterTargetsCommand } from '@aws-sdk/client-elastic-load-balancing-v2';

const ARN = [
    {
        arn: 'ターゲットグループ1',
        ec2: [
            {
                id: 'インスタンスID1',
                port: 80
            },
            {
                id: 'インスタンスID2',
                port: 80
            }
        ]
    },
    {
        arn: 'ターゲットグループ2',
        ec2: [
            {
                id: 'インスタンスID1',
                port: 443
            },
            {
                id: 'インスタンスID2',
                port: 443
            }
        ]
    }
];

const elbv2 = new ElasticLoadBalancingV2Client({
    region: "ap-northeast-1",
});

export const handler = async (event) => {
    let message = "DeregisterTargets : ";

    for (let i = 0; i < ARN.length; i++) {
        if (i > 0) message += ' / ';
        message += ARN[i].arn + ' -> ';

        let input = {
            TargetGroupArn: ARN[i].arn, 
            Targets: []
        };

        const ec2 = ARN[i].ec2;

        message += '[ ';

        for (let j = 0; j < ec2.length; j++) {
            input.Targets.push(
                { 
                    Id: ec2[j].id,
                    Port: ec2[j].port
                }
            );

            if (j > 0) message += ', ';
            message += ec2[j].id+':'+ec2[j].port;
        }

        message += ' ]';

        await elbv2.send(new DeregisterTargetsCommand(input));
    }

    return { message };

};

※ターゲットグループ(ARN)は「EC2 > ロードバランサー > 対象のLB名 > リスナー」にあるターゲットグループ名をクリックするとARNの詳細を確認できます。

9. テストの実施

それぞれ設定が終わったらコードタブにある「Test」を実行してエラーが無いか確認します。

※実際に実行されるので慎重に行いましょう。

10. トリガーの登録(EC2インスタンスの起動用)

「Lambda > 関数 > EC2_Start_Service」にアクセスして「トリガーを追加」をクリックします。

下記を入力・選択して追加をクリック

トリガーの設定:EventBridge (CloudWatch Events)を選択
既存のルール:EC2_Start_Service (作成したEC2インスタンス起動用関数名)
スケジュール式:cron(0 23 * * ? *)

※毎日23時にEC2インスタンスの起動を実施

11. トリガーの登録(ELBへの登録用)

「Lambda > 関数 > ELB_Register_Service」にアクセスして「トリガーを追加」をクリックします。

下記の入力・選択して追加をクリック

トリガーの設定:EventBridge (CloudWatch Events)を選択
既存のルール:ELB_Register_Service (作成したELB登録用関数名)
スケジュール式:cron(50 23 * * ? *)

※毎日23時50分にELBへの登録を実施

12. トリガーの登録(ELBからの削除用)

「Lambda > 関数 > ELB_Deregister_Service」にアクセスして「トリガーを追加」をクリックします。

下記を入力・選択して追加をクリック

トリガーの設定:EventBridge (CloudWatch Events)を選択
既存のルール:ELB_Deregister_Service (作成したELB削除用関数名)
スケジュール式:cron(10 6 * * ? *)

※毎日6時10分にELBからの削除を実施

13. トリガーの登録(EC2インスタンスの停止用)

「Lambda > 関数 > EC2_Stop_Service」にアクセスして「トリガーを追加」をクリックします。

下記を入力・選択して追加をクリック

トリガーの設定:EventBridge (CloudWatch Events)を選択
既存のルール:EC2_Stop_Service (作成したEC2インスタンス停止用関数名)
スケジュール式:cron(0 7 * * ? *)

※毎日7時にEC2インスタンスの停止を実施

これで
23時00分:EC2インスタンスが2台が起動
23時50分:ELBへEC2インスタンス2台を登録
06時10分:ELBからEC2インスタンス2台を削除
07時00分:EC2インスタンス2台を停止
という時限式なんちゃってオートスケーリングの完成です!

※参考
https://qiita.com/mighty-n/items/e667f4380c372e5cef40
https://qiita.com/mighty-n/items/f6dd823a26a6809dca80
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ec2/
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/elastic-load-balancing-v2/

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?