現在運用中の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/