aws cdkを使ってec2にjmeterをインストールしたメモ

## 概要
ec2をcdkを使ってAWSに立ててみる。
ec2にはjmeterをインストールする。
[デプロイ時のソースコード](https://github.com/hibohiboo/develop/tree/1d36a6c8f53b7298208c37d7758335bd4e16036f/tutorial/lesson/aws/typescript/projects/ec2_sample)
## 環境
* windows 10
* Docker version 20.10.8, build 3967b7d
* aws-cdk 1.128.0
* aws-cdk-local 1.65.8
* aws-cli/2.2.46 Python/3.8.8 Windows/10 exe/AMD64 prompt/off
* node v14.18.1

## ローカルで確認
まずはローカルでstackを確認した。
ただし、localstackはEC2のデプロイができるかの確認のみ。
localstack上のEC2インスタンスはモックのIFの作成なのでで実際にsshアクセスすることはできない。

<details><summary>確認手順</summary><div>

[localStack確認時のソースコード](https://github.com/hibohiboo/develop/tree/8eef6f98c48682c27bbe3b178737b2d134fe1d13/tutorial/lesson/aws/typescript/projects/ec2_sample)

```
./bin/localstack.sh
```

```
cd cdk
npm run localstack-bootstrap
npm run ec2-localdeploy
```

</div></details>



## 実際にデプロイして確認

[デプロイ時のソースコード](https://github.com/hibohiboo/develop/tree/1d36a6c8f53b7298208c37d7758335bd4e16036f/tutorial/lesson/aws/typescript/projects/ec2_sample)

Amazon Linux2 にjavaは入っていないのでインストールする。
その後、[jmeter](https://jmeter.apache.org/download_jmeter.cgi)のインストールを行う。
起動時のコマンドで実行するようにcdkを設定。

<details><summary>Stackファイル</summary><div>

```bash:cdk/bin/src/config.sh
#!/bin/bash -xe

# JREをダウンロード
yum update -y
yum install java-1.8.0-openjdk.x86_64 -y

# jmetetをダウンロード
cd /home/ec2-user
wget https://downloads.apache.org//jmeter/binaries/apache-jmeter-5.4.tgz
tar -xf apache-jmeter-5.4.tgz
# 所有者をec2-userに
chown -R ec2-user apache-jmeter-5.4
```

```ts:cdk/lib/ec2-cdk-stack.ts
import * as ec2 from "@aws-cdk/aws-ec2";
import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam'
import * as path from 'path';
import { KeyPair } from 'cdk-ec2-key-pair';
import { Asset } from '@aws-cdk/aws-s3-assets';

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

    // Create a Key Pair to be used with this EC2 Instance
    const key = new KeyPair(this, 'ec2-cdkstack-KeyPair', {
      name: 'cdk-keypair',
      description: 'Key Pair created with CDK Deployment',
    });
    key.grantReadOnPublicKey

    // Create new VPC with 2 Subnets
    const vpc = new ec2.Vpc(this, 'ec2-cdkstack-VPC', {
      natGateways: 0,
      subnetConfiguration: [{
        cidrMask: 24,
        name: "asterisk",
        subnetType: ec2.SubnetType.PUBLIC
      }]
    });

    // Allow SSH (TCP Port 22) access from anywhere
    const securityGroup = new ec2.SecurityGroup(this, 'ec2-cdkstack-SecurityGroup', {
      vpc,
      description: 'Allow SSH (TCP port 22) in',
      allowAllOutbound: true
    });
    securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'Allow SSH Access')

    const role = new iam.Role(this, 'ec2-cdkstack-ec2Role', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
    })

    role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'))

    // Use Latest Amazon Linux Image
    const ami = new ec2.AmazonLinuxImage({
      generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
      cpuType: ec2.AmazonLinuxCpuType.X86_64
    });

    // Create the instance using the Security Group, AMI, and KeyPair defined in the VPC created
    const ec2Instance = new ec2.Instance(this, 'ec2-cdkstack-Instance', {
      vpc,
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.NANO),
      machineImage: ami,
      securityGroup: securityGroup,
      keyName: key.keyPairName,
      role: role
    });

    // Create an asset that will be used as part of User Data to run on first load
    const asset = new Asset(this, 'ec2-cdkstack-Asset', { path: path.join(__dirname, '../src/config.sh') });
    const localPath = ec2Instance.userData.addS3DownloadCommand({
      bucket: asset.bucket,
      bucketKey: asset.s3ObjectKey,
    });

    ec2Instance.userData.addExecuteFileCommand({
      filePath: localPath,
      arguments: '--verbose -y'
    });
    asset.grantRead(ec2Instance.role);

    // Create outputs for connecting
    new cdk.CfnOutput(this, 'IP Address', { value: ec2Instance.instancePublicIp });
    new cdk.CfnOutput(this, 'Key Name', { value: key.keyPairName })
    new cdk.CfnOutput(this, 'Download Key Command', { value: 'aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text > cdk-key.pem && chmod 400 cdk-key.pem' })
    new cdk.CfnOutput(this, 'ssh command', { value: 'ssh -i cdk-key.pem -o IdentitiesOnly=yes ec2-user@' + ec2Instance.instancePublicIp })
  }
}
```

実行
```
cd cdk
npm run ec2-deploy
```

</div></details>

デプロイ後、以下のようにOutputがされるので、IPAddressを確認。

```
Outputs:
Ec2CdkStack.DownloadKeyCommand = aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text 
> cdk-key.pem && chmod 400 cdk-key.pem
Ec2CdkStack.IPAddress = 52.68.26.214
Ec2CdkStack.KeyName = cdk-keypair
Ec2CdkStack.sshcommand = ssh -i cdk-key.pem -o IdentitiesOnly=yes ec2-user@52.68.26.214
```

sshでEC2にログインする。

```sh
# 鍵の入手
./bin/get_pem.sh
# ssh 接続 Ec2CdkStack.IPAddressで表示されるIPを入力
./bin/ssh.sh 52.68.26.214
```

jmeterの起動を試す。

```sh
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
[ec2-user@ip-10-0-0-170 ~]$ ls
apache-jmeter-5.4  apache-jmeter-5.4.tgz
[ec2-user@ip-10-0-0-170 ~]$ cd apache-jmeter-5.4/bin
[ec2-user@ip-10-0-0-170 bin]$  ./jmeter.sh -n -t examples/CSVSample.jmx -l log.jtx -e -o report
```

結果をzipでまとめる

```
[ec2-user@ip-10-0-0-170 bin]$ zip report -r report
[ec2-user@ip-10-0-0-170 bin]$ zip examples -r examples
```

zipをダウンロードする。

```
./bin/download.sh 52.68.26.214
```

ec2上でのjmeter起動を確認できた。

## 参考
[cdk example ec2-instance](https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/ec2-instance)
[Amazon Linux2 で Apache JMeterをインストールから実行まで](https://dev-hack.pw/archives/656)
[localstack + aws cdk でAWS S3をローカル環境に立ち上げてLambdaでアクセスするメモ](https://qiita.com/hibohiboo/items/e81573744466343aec2c)
[jmeter](https://jmeter.apache.org/download_jmeter.cgi)
[起動時のコマンド実行](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html)