コスト効率向上！「WakeOnLambda」CDK Constructが登場

## 背景

Amazon EC2インスタンスの常時起動にはコストがかかります。サービスが必要ない時間帯でもインスタンスが動いていると、無駄なコストが発生してしまいます。今回は、WebサービスにアクセスするだけでEC2インスタンスを起動できる「WakeOnLambda」CDK Constructを開発し、その利点について紹介します。

## コンストラクトの概要

「WakeOnLambda」は、AWS CDKを使用して、特定のURLにアクセスすることでEC2インスタンスを起動するLambda関数を簡単に構築できるConstructです。これにより、ユーザーは手動での操作なしに、Webサービスへのアクセスを通じてインスタンスをスタートできます。Construct Hub のリンクはこちら

[![View on Construct Hub](https://constructs.dev/badge?package=wake-on-lambda)](https://constructs.dev/packages/wake-on-lambda)

Construct Hubへの登録は以下の記事を参考にさせて頂きました。

https://qiita.com/hayao_k/items/194dfb051f18a38b6dbd


## 利点

- **利用のしやすさ**: 特定のURLにアクセスするだけでEC2インスタンスを起動できるため、ユーザーは手軽にサービスを利用できます。

- **コスト最適化**: インスタンスが不要なときに起動しないことで、無駄なコストを削減できます。必要なときにのみ起動することで、コスト対効果が向上します。

## インストール手順

AWS CDKアプリケーションにこのコンストラクトを統合するには、以下のnpmコマンドを使用してパッケージをインストールします。

```bash
npm install wake-on-lambda
```

## 使い方

以下のように使用することができます。

```typescript
import { Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { InstanceTarget, LambdaTarget} from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets'
import { Construct } from 'constructs';
import { WakeOnLambda } from 'wake-on-lambda';
import { Role, ServicePrincipal, ManagedPolicy } from 'aws-cdk-lib/aws-iam';

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

    const vpc = new ec2.Vpc(this, 'TheVPC', {
      ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16')
    })

    const instanceRole = new Role(this, 'InstanceRole', {
      assumedBy: new ServicePrincipal('ec2.amazonaws.com')
    })

    instanceRole.addManagedPolicy(
      ManagedPolicy.fromAwsManagedPolicyName(
        'AmazonSSMManagedInstanceCore'
      )
    )

    const albSg = new ec2.SecurityGroup(this, 'AlbSg', {
      vpc: vpc,
      allowAllOutbound: true
    })
    albSg.addIngressRule(
      ec2.Peer.ipv4('myip'),
      ec2.Port.tcp(80)
    )

    const instanceSg = new ec2.SecurityGroup(this, 'InstanceSg', {
      vpc: vpc,
      allowAllOutbound: true
    })
    instanceSg.addIngressRule(
      albSg,
      ec2.Port.tcp(80)
    )

    const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
      vpc,
      securityGroup: albSg,
      vpcSubnets: {subnetType: ec2.SubnetType.PUBLIC},
      internetFacing: true
    })


    const instance = new ec2.Instance(this, 'TargetInstance', {
      vpc: vpc,
      vpcSubnets: {subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS},
      securityGroup: instanceSg,
      role: instanceRole,
      requireImdsv2: true,
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.BURSTABLE2, 
        ec2.InstanceSize.MICRO
        ),
      machineImage: new ec2.AmazonLinuxImage(
        { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }
        )
    })

    const wakeOnLambda = new WakeOnLambda(this, 'Default', {
      instanceId: instance.instanceId,
      albDnsName: lb.loadBalancerDnsName
    })

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

    const lambdaTarget = new LambdaTarget(wakeOnLambda.lambdaFn)
    const LambdaTargetGroup = listener.addTargets('LambdaTaget', {
      targets: [lambdaTarget]
    })

    new elbv2.ApplicationListenerRule(this, 'ApplicationListenerRule', {
      listener: listener,
      priority: 100,
      conditions: [elbv2.ListenerCondition.pathPatterns(['/entry']),],
      targetGroups: [LambdaTargetGroup],
    });


    const instanceTarget = new InstanceTarget(instance, 80);
    listener.addTargets('MainTarget', {
      port: 80,
      targets: [instanceTarget]
    })
  }
}
```

上記の例では、`http://${albDnsName}/entry` にアクセスすることで、 `http://${albDnsName}` にリダイレクトされます。そのとき、背後のEC2インスタンスが起動していない場合には起動コマンドを発砲します。


## 結論
「WakeOnLambda」CDK Constructを導入することで、AWS CDKを利用して簡単にEC2インスタンスをWebサービスのアクセスにより自動的に起動できます。AWS CDKを採用している場合は、ぜひこのConstructをお試しください！

## 関連記事

https://qiita.com/yayami3/items/4188b46ec5b288e9d344