【AWS作業効率化Tips】AWS CLIはpecoと組み合わせて業務効率を３倍にする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163591/256ea7f6-81da-7d8b-e45f-58d8bcb49807.png)

こんにちは G-awa です。
aws-cli、使い倒していますか？？

AWSを毎日使ってる皆さん、
AWSのコンソール画面をポチポチしていると時間かかっちゃいますよね？
現在動いているEC2の情報を見たいだけなのにブラウザを開いてログインして・・・
ちょっと面倒です:sweat_smile:できればシェルから全てを完結したい！！

作業の効率化のためにシェルでAWSの各種リソースの情報が取得できるスクリプトを書いてみました。
これでプロビジョニングされている各種リソースの情報がサクッと取得できます。

githubのソースコードは[こちら:octocat:](https://github.com/daisuke-awaji/awj)

これで最近はターミナルから離れることなく作業できてます:smirk:

# 実行イメージ

### EC2の一覧から詳細情報を取得する（describe_ec2）

EC2の一覧から選択して詳細情報を取得できます。
選択する際は文字列で検索できたり、ctrl-n, ctrl-pで上下にカーソルを移動できるので最高です。

![ec2.gif](https://qiita-image-store.s3.amazonaws.com/0/163591/a43595aa-8f0b-08e7-4de0-8a6cda11d9bc.gif)

### スタックの一覧から選択してChromeで開く（describe_stack_url）
aws cliでCloudformationのテンプレートからスタックを作成する際なんかに便利です。
スタックでLambdaを立てたならもちろんLambdaの情報だって取得できます。

```shell
$ aws cloudformation create-stack --template-body file://template.yaml --stack-name stackname
```

からの以下のようなかんじですね

![stack.gif](https://qiita-image-store.s3.amazonaws.com/0/163591/1c98c3a8-103a-4da0-7eca-7281251f5711.gif)



# 使い方
awjコマンドでリストアップされたコマンドを選んで<Enter>押すだけです。
このエイリアスは適当に決めてください。私はaをエイリアスにしています。
上記の実行イメージ以外にもいろいろ用意してあります。
これがそろってればだいたい困らないかなーというのを載せてます。

```shell
$ awj <Enter>
describe_stacks          # スタックの一覧　
describe_stack_url       # スタックの一覧　
describe_change_set_url  # 変更セットの一覧
describe_ec2             # EC2の一覧　　
describe_elb             # ELBの一覧　　
describe_alb             # ALBの一覧　　
describe_lambda          # Lambdaの一覧
describe_rds             # RDSの一覧
describe_s3              # S3の一覧
describe_logs            # CloudWatchLogsの一覧
describe_aws_batch_jobs  # aws batchのジョブ定義
```

# 必要なもの

- jq
- peco
- column

macならどれも

```
$ brew insatll <インストールしたいツール>
```

でオッケーです:ok_hand:

詳しく知りたい方は以下が参考になります。

- [jq コマンドを使う日常のご紹介](https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)
- [え、まだpecoを使ってないの？？？](https://qiita.com/vintersnow/items/08852df841e8d5faa7c2)
- [Linuxテキスト編集コマンドのすべて](https://qiita.com/kenju/items/5777322e485a30aa6269)


# 仕組み

## describe-instances コマンド

`aws ec2 describe-instances`を実行するとec2の一覧が取得できますが
これだととても読めたもんじゃないですね・・・
日常的に使うにはちょっと抵抗がありすぎます。

```bash
$ aws ec2 describe-instances
{
    "Reservations": [
        {
            "Instances": [
                {
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "PublicDnsName": "ec2-54-165-183-11.compute-1.amazonaws.com",
                    "State": {
                        "Code": 0,
                        "Name": "pending"
                    },
                    "EbsOptimized": false,
                    "LaunchTime": "2018-07-07T09:45:37.000Z",
                    "PublicIpAddress": "54.165.183.11",
                    "PrivateIpAddress": "172.31.26.36",
                    "ProductCodes": [],
                    "VpcId": "vpc-42cd1e3b",
                    "StateTransitionReason": "",
                    "InstanceId": "i-0fb18b222fb6e9f28",
                    "EnaSupport": true,
                    "ImageId": "ami-b70554c8",
                    "PrivateDnsName": "ip-172-31-26-36.ec2.internal",
                    "SecurityGroups": [
                        {
                            "GroupName": "default",
                            "GroupId": "sg-b6e6e7c8"
                        }
                    ],
                    "ClientToken": "ec2-EC2-1FNBR75FMLBZU",
                    "SubnetId": "subnet-ee22b4a6",
                    "InstanceType": "t2.nano",
                    "NetworkInterfaces": [
                        {
                            "Status": "in-use",
                            "MacAddress": "0a:c9:00:3e:5b:7e",
                            "SourceDestCheck": true,
                            "VpcId": "vpc-42cd1e3b",
                            "Description": "",
                            "NetworkInterfaceId": "eni-ff609d9b",
                            "PrivateIpAddresses": [
                                {
                                    "PrivateDnsName": "ip-172-31-26-36.ec2.internal",
                                    "PrivateIpAddress": "172.31.26.36",
                                    "Primary": true,
                                    "Association": {
                                        "PublicIp": "54.165.183.11",
                                        "PublicDnsName": "ec2-54-165-183-11.compute-1.amazonaws.com",
                                        "IpOwnerId": "amazon"
                                    }
                                }
                            ],
                            "PrivateDnsName": "ip-172-31-26-36.ec2.internal",
                            "Attachment": {
                                "Status": "attaching",
                                "DeviceIndex": 0,
                                "DeleteOnTermination": true,
                                "AttachmentId": "eni-attach-b4171212",
                                "AttachTime": "2018-07-07T09:45:37.000Z"
                            },
                            "Groups": [
                                {
                                    "GroupName": "default",
                                    "GroupId": "sg-b6e6e7c8"
                                }
                            ],
                            "Ipv6Addresses": [],
                            "OwnerId": "703976800898",
                            "PrivateIpAddress": "172.31.26.36",
                            "SubnetId": "subnet-ee22b4a6",
                            "Association": {
                                "PublicIp": "54.165.183.11",
                                "PublicDnsName": "ec2-54-165-183-11.compute-1.amazonaws.com",
                                "IpOwnerId": "amazon"
                            }
                        }
                    ],
                    "SourceDestCheck": true,
                    "Placement": {
                        "Tenancy": "default",
                        "GroupName": "",
                        "AvailabilityZone": "us-east-1d"
                    },
                    "Hypervisor": "xen",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "Status": "attaching",
                                "DeleteOnTermination": true,
                                "VolumeId": "vol-01a4f09d7f3e3b42b",
                                "AttachTime": "2018-07-07T09:45:38.000Z"
                            }
                        }
                    ],
                    "Architecture": "x86_64",
                    "RootDeviceType": "ebs",
                    "RootDeviceName": "/dev/xvda",
                    "VirtualizationType": "hvm",
                    "Tags": [
                        {
                            "Value": "arn:aws:cloudformation:us-east-1:703976800898:stack/ec2/7a967de0-81ca-11e8-9cc9-503aca26168d",
                            "Key": "aws:cloudformation:stack-id"
                        },
                        {
                            "Value": "d2-web",
                            "Key": "Name"
                        },
                        {
                            "Value": "ec2",
                            "Key": "aws:cloudformation:stack-name"
                        },
                        {
                            "Value": "EC2",
                            "Key": "aws:cloudformation:logical-id"
                        }
                    ],
                    "AmiLaunchIndex": 0
                }
            ],
            "ReservationId": "r-00cb877e9b4367e97",
            "RequesterId": "043234062703",
            "Groups": [],
            "OwnerId": "703976800898"
        }
    ]
}
```

## jqで出力する対象を絞る

そこでまずは jq コマンドを使って表示する項目を絞ってやりましょう。
必要な項目だけ出力することにして、さらに@tsv形式で出力すればだいぶ見やすくなりましたね

```shell
$ aws ec2 describe-instances | \
    jq -r '.[][].Instances[] | [.InstanceId, [.Tags[] | select(.Key == "Name").Value][], .InstanceType, .NetworkInterfaces[].PrivateIpAddress, .State.Name] | @tsv'

i-0d96d020302c97f4b	s3-nginx	t2.micro	172.31.77.105	running
i-00d96629eb4b3880d	d2-web	t2.nano	172.31.26.180	running
i-0fb18b222fb6e9f28	d2-web	t2.nano	172.31.26.36	running
i-0bda7a20e17745130	d2-web	t2.nano	172.31.27.242	running
i-0cc48ad51a63fb123	d1-wordpress	t2.micro	172.31.66.51	pending
```

## columnで整形

でも、このままだとタブがずれていて見にくいので column をつかって見やすく整形しましょう。
これでタブの間隔をいい感じに表示してくれます。

```bash
~$ aws ec2 describe-instances | \
       jq -r '.[][].Instances[] | [.InstanceId, [.Tags[] | select(.Key == "Name").Value][], .InstanceType, .NetworkInterfaces[].PrivateIpAddress, .State.Name] | @tsv' | \
       column -t

i-0d96d020302c97f4b  s3-nginx      t2.micro  172.31.77.105  running
i-00d96629eb4b3880d  d2-web        t2.nano   172.31.26.180  running
i-0fb18b222fb6e9f28  d2-web        t2.nano   172.31.26.36   running
i-0bda7a20e17745130  d2-web        t2.nano   172.31.27.242  running
i-0cc48ad51a63fb123  d1-wordpress  t2.micro  172.31.66.51   running
```

## pecoでインタラクティブに

ここまでできたらあとは peco でインスタンスIDを選択できるようにしましょう
取得したインスタンスIDをもとにインスタンスを絞って表示してやればいい感じです

```shell
# EC2の一覧から選択して詳細情報を取得します
describe_ec2() {
  INSTANCE_ID=`aws ec2 describe-instances | \
      jq -r '.[][].Instances[] | [.InstanceId, [.Tags[] | select(.Key == "Name").Value][], .InstanceType, .NetworkInterfaces[].PrivateIpAddress, .State.Name] | @tsv' | \
      column -t | peco | cut -d ' ' -f 1`
  echo "aws ec2 describe-instances --instance-ids ${INSTANCE_ID}"
  aws ec2 describe-instances --instance-ids $INSTANCE_ID | jq .
}
```

![ec2.gif](https://qiita-image-store.s3.amazonaws.com/0/163591/a43595aa-8f0b-08e7-4de0-8a6cda11d9bc.gif)

# まとめ

1. aws-cliは日常的に使うのはそのままではしんどい
2. pecoというツールによってインタラクティブに操作できるようになる
3. [awj](https://github.com/daisuke-awaji/awj)をインストールして使ってね

これでAWSのコンソール画面を開かずとも、大体の作業が行えるようになるんではないでしょうか？
わたしはCloudformationを使用してAWSリソースを立てているので、このスクリプトをつくってから本当にブラウザを開くことが少なくなりました。
ローカルでCloudformationのテンプレートを書いて、デプロイして、awjコマンドで確認する。
マウスを使わないだけで随分効率的に作業ができています。

是非一度お試しください:blush:
そのうち python とかで書いてちゃんとしたコマンドツールにしようかなぁ