AWS コマンドラインインターフェース (CLI) でEC2インスタンスに触れてみる

この記事は、株式会社エイチームフィナジーの[Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ateam-finergy) 9日目の記事になります。
テクニカルソリューション部エンジニアの@andmorefineが担当いたします。

# はじめに

わたし自身は業務で、あまりAWSに触れる機会はありません。
なぜなら、自分が担当しているシステムのインフラ環境がほぼほぼ整備されており、ECSで構築されてデプロイもCI/CDで自動的にテストを実施できているためです。なんと素晴らしいことでしょう。
ただ、完璧でもう手を加えることはないのかと言われるとそこまでではなく、`FagateSpot`にしてサーバーのコストを抑えてみたり、ECSで構築できてはいるものの、スケーリングはできていないので`Auto Scaling`対応を行い、「負荷分散」と「可用性向上」も進めていきたいと考えています。

やりたいことや、やらなければいけないことは明確にあるので、今回はその第一歩として、AWS CLIを利用してEC2インスタンスを触れてみます。

基本的にEC2インスタンスを扱う方法として3つの方法があります。

- AWS Cloud Development Kit (CDK) 
- AWS コマンドラインインターフェース (CLI) 
- AWSコンソール

今回は勉強がてら`AWS CLI`でEC2を触りながら、立ち上げたり、停止させたり、削除していきます。

##　事前設定

- https://github.com/aws/aws-cli

`AWS CLI`は`v2`を利用します。

```sh
aws --version
aws-cli/2.4.5 Python/3.8.8 Darwin/20.6.0 exe/x86_64 prompt/off
```

アカウントをまたがる機会があると思いますので、今回はprofileオプションを付与して実施していきます。

```sh
--profile ec2-test
```

`aws　configure`の設定は下記

```sh
# ~/.aws/config
[default]
region=ap-northeast-1
output = json
```

```sh
# ~/.aws/credentials
[ec2-test]
aws_access_key_id=xxxxxxxxxxxxx
aws_secret_access_key=xxxxxxxxxxxxx
region=ap-northeast-1 # You must specify a region. You can also configure your region by running "aws configure".
```

## EC2(Elastic Compute Cloud)コマンド確認

- https://aws.amazon.com/jp/ec2/ 概要

```
$ aws ec2
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help
```

と、入力すると使い方を教えてくれます

これから何度もhelpを打っていきます

```
aws ec2 help --profile ec2-test
```

2021/12の時点だと`aws ec2`のコマンドは516個ほどありました。
これからも増えそうですが、要素別に整理します。

EC2のインスタンス制御の機能だと26個ほどありましたが、そこからさらにリザーブドインスタンス系と区別が出来そうです。

```
accept-reserved-instances-exchange-quote
cancel-reserved-instances-listing
create-reserved-instances-listing
delete-queued-reserved-instances
describe-reserved-instances
describe-reserved-instances-listings
describe-reserved-instances-modifications
describe-reserved-instances-offerings
get-reserved-instances-exchange-quote
modify-reserved-instances
purchase-reserved-instances-offering
```

今回はインスタンス制御の13個の中から、作成、ステータス確認、停止、起動、モニタリング、終了を確認していきます

```
describe-classic-link-instances
describe-fleet-instances
describe-instances
describe-scheduled-instances
describe-spot-fleet-instances
monitor-instances
purchase-scheduled-instances
reboot-instances
request-spot-instances
run-instances
run-scheduled-instances
start-instances
stop-instances
terminate-instances
unmonitor-instances
```

##　EC2インスタンス・作成

ドキュメントを確認します。多くかつ詳細なオプションがあることがわかります。
一通り確認すると、`--dry-run`があるようなので、こちらのオプションを付与して実行していきます。

```
aws ec2 run-instances help --profile ec2-test
SYNOPSIS
            run-instances
          [--block-device-mappings <value>]
          [--image-id <value>]
          [--instance-type <value>]
          [--kernel-id <value>]
          [--key-name <value>]
          [--monitoring <value>]
          [--security-group-ids <value>]
          [--security-groups <value>]
          [--subnet-id <value>]
          [--user-data <value>]
          [--additional-info <value>]
          [--dry-run | --no-dry-run]
...
```

では、ドライランを付与して実施してみます。

```
aws ec2 run-instances \
  --dry-run \
  --profile ec2-test

An error occurred (MissingParameter) when calling the RunInstances operation: The request must contain the parameter ImageId
```

`ImageId`は必須項目みたいですので付与しましょう。[Amazonマシンイメージ (AMI) ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html)のことです。

![スクリーンショット 2021-12-07 3.15.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/8d70815f-f016-7560-4f95-953afd9b6965.png)


今回は、CLIで最新のAmazon Linux2のAMI IDを取得してみます

```
aws ssm get-parameter \
  --name /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 \
  --query "Parameter.Value" \
  --profile ec2-test
"ami-0abaa5b0faf689830" <- 返り値
```

```
aws ec2 run-instances \
  --image-id ami-0abaa5b0faf689830 \
  --dry-run \
  --profile ec2-test

An error occurred (DryRunOperation) when calling the RunInstances operation: Request would have succeeded, but DryRun flag is set.
```

成功してそうですので、`--dry-run`のコマンドを外して再度実施してみます。

```
aws ec2 run-instances \
  --image-id ami-0abaa5b0faf689830 \
  --profile ec2-test
```

無事、インスタンス作成に成功できました。

![スクリーンショット 2021-12-07 3.25.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/88a7a4a9-20cc-529d-3ae6-18b59a3b9ac3.png)

<details><summary>インスタンス作成成功の返り値</summary><div>

```json
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-0abaa5b0faf689830",
            "InstanceId": "i-0000ea724aa4b5633",
            "InstanceType": "m1.small",
            "LaunchTime": "2021-12-06T18:21:18+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "ap-northeast-1a",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-172-31-21-231.ap-northeast-1.compute.internal",
            "PrivateIpAddress": "172.31.21.231",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "StateTransitionReason": "",
            "SubnetId": "subnet-e3210095",
            "VpcId": "vpc-7b5cc21f",
            "Architecture": "x86_64",
            "BlockDeviceMappings": [],
            "ClientToken": "5ee60c26-0df1-4630-a4a7-5d8653798651",
            "EbsOptimized": false,
            "EnaSupport": true,
            "Hypervisor": "xen",
            "NetworkInterfaces": [
                {
                    "Attachment": {
                        "AttachTime": "2021-12-06T18:21:18+00:00",
                        "AttachmentId": "eni-attach-07d63576ded6f8663",
                        "DeleteOnTermination": true,
                        "DeviceIndex": 0,
                        "Status": "attaching",
                        "NetworkCardIndex": 0
                    },
                    "Description": "",
                    "Groups": [
                        {
                            "GroupName": "default",
                            "GroupId": "sg-90565df7"
                        }
                    ],
                    "Ipv6Addresses": [],
                    "MacAddress": "06:3d:7a:fa:5e:3d",
                    "NetworkInterfaceId": "eni-0e5a48c8fff75250e",
                    "OwnerId": "316224805545",
                    "PrivateDnsName": "ip-172-31-21-231.ap-northeast-1.compute.internal",
                    "PrivateIpAddress": "172.31.21.231",
                    "PrivateIpAddresses": [
                        {
                            "Primary": true,
                            "PrivateDnsName": "ip-172-31-21-231.ap-northeast-1.compute.inter
nal",
                            "PrivateIpAddress": "172.31.21.231"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Status": "in-use",
                    "SubnetId": "subnet-e3210095",
                    "VpcId": "vpc-7b5cc21f",
                    "InterfaceType": "interface"
                }
            ],
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SecurityGroups": [
                {
                    "GroupName": "default",
                    "GroupId": "sg-90565df7"
                }
            ],
            "SourceDestCheck": true,
            "StateReason": {
                "Code": "pending",
                "Message": "pending"
            },
            "VirtualizationType": "hvm",
            "CpuOptions": {
                "CoreCount": 1,
                "ThreadsPerCore": 1
            },
            "CapacityReservationSpecification": {
                "CapacityReservationPreference": "open"
            },
            "MetadataOptions": {
                "State": "pending",
                "HttpTokens": "optional",
                "HttpPutResponseHopLimit": 1,
                "HttpEndpoint": "enabled",
                "HttpProtocolIpv6": "disabled"
            },
            "EnclaveOptions": {
                "Enabled": false
            },
            "PrivateDnsNameOptions": {
                "HostnameType": "ip-name",
                "EnableResourceNameDnsARecord": false,
                "EnableResourceNameDnsAAAARecord": false
            }
        }
    ],
    "OwnerId": "316224805545",
    "ReservationId": "r-07ad68f6dc72ac9df"
}
```

</div></details>

##　EC2インスタンス・ステータス確認

`help`でドキュメントを確認しながらExampleもチェックします。

```
aws ec2 describe-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test
```

`--query`のオブションで表示の絞り込みができたので今のインスタンスIDのステータス（状態）を確認します

```
aws ec2 describe-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --query 'Reservations[*].Instances[*].{Instance:InstanceId,StateName:State.Name}' \
  --profile ec2-test

[
    [
        {
            "Instance": "i-0000ea724aa4b5633",
            "StateName": "running"
        }
    ]
]
```

実行中（`running`）のステータスを確認することがきました

##　EC2インスタンス・停止

`--dry-run`があるなら最初は付与しておきた方がよいでしょう。

```
aws ec2 stop-instances help --profile ec2-test
SYNOPSIS
            stop-instances
          --instance-ids <value>
          [--hibernate | --no-hibernate]
          [--dry-run | --no-dry-run]
...
```

`--dry-run`で実行します。

```
aws ec2 stop-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --dry-run \
  --profile ec2-test

An error occurred (DryRunOperation) when calling the StopInstances operation: Request would have succeeded, but DryRun flag is set.
```

問題なさそうですので、`--dry-run`を外して、実施します

```
aws ec2 stop-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test

{
    "StoppingInstances": [
        {
            "CurrentState": {
                "Code": 64,
                "Name": "stopping"
            },
            "InstanceId": "i-0000ea724aa4b5633",
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            }
        }
    ]
}
```

停止中（`stopping`）を確認

![スクリーンショット 2021-12-07 3.50.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/44961c23-bc60-917d-4072-91aca1e50e79.png)

停止中（`stopping`） -> 停止済み（`stopped`）に移行できたことを確認できました

![スクリーンショット 2021-12-07 3.52.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/d0529aa5-d68c-7c52-b1cb-4093b491350d.png)

<details><summary>先程のステータスの確認コマンドでも期待通りの値が返ってきてます</summary><div>

```
aws ec2 describe-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --query 'Reservations[*].Instances[*].{Instance:InstanceId,StateName:State.Name}' \
  --profile ec2-test

[
    [
        {
            "Instance": "i-0000ea724aa4b5633",
            "StateName": "stopped"
        }
    ]
]
```

</div></details>

##　EC2インスタンス・起動

起動方法は、停止とあまり変わらないので`--dry-run`は付与せず実行してします

```
aws ec2 start-instances help --profile ec2-test
SYNOPSIS
            start-instances
          --instance-ids <value>
          [--additional-info <value>]
          [--dry-run | --no-dry-run]
...
```

```
aws ec2 start-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test

{
    "StartingInstances": [
        {
            "CurrentState": {
                "Code": 0,
                "Name": "pending"
            },
            "InstanceId": "i-0000ea724aa4b5633",
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        }
    ]
}
```

保留中（`pending`） -> 実行中（`running`）に移行できたことを確認できました

![スクリーンショット 2021-12-07 4.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/88e4177f-5a24-f6ed-a010-180bc341b2ea.png)
![スクリーンショット 2021-12-07 4.03.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/1079f48b-0227-8d83-0139-20ddab7248ee.png)

##　EC2インスタンス・詳細モニタリング

EC2インスタンス・詳細モニタリング設定の有効化と無効化の操作を実行します

実行中のインスタンスの詳細なモニタリングを有効にします。

それ以外の場合は、基本的な監視を有効にします。
詳細については、Amazon EC2 User Guide の [Monitor your instances using CloudWatch](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-cloudwatch.html) を参照してください。

![スクリーンショット 2021-12-07 4.14.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/e9a136be-c3ea-6706-3b45-3a05ab61791c.png)

AWSコンソール上の右上のボタンの同様のものになります。追加料金が適応されるのでご注意ください。

![スクリーンショット 2021-12-07 4.15.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/797994a0-ba36-b2c2-7f04-a1d70e06d04f.png)

```
aws ec2 monitor-instances help --profile ec2-test

SYNOPSIS
            monitor-instances
          --instance-ids <value>
          [--dry-run | --no-dry-run]
...
```

```
aws ec2 monitor-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test
```

モニタリングを無効化は下記です。

```
aws ec2 unmonitor-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test
```

##　EC2インスタンス・終了/削除

指定されたインスタンスをシャットダウンします。この操作は冪等です。

複数回インスタンスを終了させた場合は、それぞれの呼び出しが成功します。

```
aws ec2 terminate-instances help --profile ec2-test
SYNOPSIS
            terminate-instances
          --instance-ids <value>
          [--dry-run | --no-dry-run]
...
```

```
aws ec2 terminate-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --dry-run \
  --profile ec2-test

An error occurred (DryRunOperation) when calling the TerminateInstances operation: Request would have succeeded, but DryRun flag is set.
```

インスタンス・終了/削除します

```
aws ec2 terminate-instances \
  --instance-ids i-0000ea724aa4b5633 \
  --profile ec2-test
```

![スクリーンショット 2021-12-07 4.31.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/e67118e2-4703-8a75-fe31-e36c119a19c0.png)
![スクリーンショット 2021-12-07 4.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/a4d3b68c-c2b6-e139-c7aa-42910937ecde.png)

正常に`terminated`にステータスが変化していることを確認できました

![スクリーンショット 2021-12-07 4.35.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42432/db863b9e-55a9-0f57-c271-5bd43e006113.png)

しばらくするとインスタンス一覧からも削除されます。

# まとめ

ドキュメント大事ですね。わからなければ何度も何度も何度も読み返しましょう。


明日は、我がチームメイトである期待の鬼新星スーパールーキー、@mizunomi32さんの記事になります！

乞うご期待です！

**参考文献**

- https://dev.classmethod.jp/articles/get-the-latest-amazon-linux-2-ami-id-with-cloudformation/
- https://aws.amazon.com/jp/cli/
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html