bauer's diary

凡人の凡人による凡人のための備忘録

AWS EC2インスタンスのIPアドレスを即座に確認する

はじめに

サービスを運用しているエンジニアなら障害検知システムを導入して、日々の障害に備えているかと思います。

自身が所属するプロジェクトではAWSをメインに使っていて、監視サービスが異常を検知した場合、slackにインスタンスのホスト名を表示しています。
すぐにsshして詳細を確認したいけど、DNS設定していないインスタンスはIPでなければsshできません。

一刻も早く確認したいのに、毎回AWSコンソールに入ってEC2ダッシュボードからパブリックIP か プライベートIPを確認しなければいけないのは効率が悪い…。

これを機に インスタンス名やIPアドレスを一覧するコマンド を準備しようと思います。
※今回のやり方以外にも色々やりようはあるかと思いますが、自己流のやり方を記事に残しておきます。

前提
  1. aws-cli インストール・アクセスキー設定済
  2. EC2の各インスタンスタグにホスト名と環境名をつけて運用している

自身のプロジェクトでそれらのタグをつけていない場合は、今回のコマンドから不要な部分のコマンドを削除すればよいです。

1. とりあえず全て表示してみる

ベースとなるコマンドは aws ec2 describe-instancesです。
AWSで運用しているインスタンスの数によりますが、このまま叩くとEC2インスタンス情報が膨大なJSONにて表示されます。

2. 表示要素を絞り込む

JSONにはEC2インスタンスの様々な情報が含まれているため、必要最低限の要素だけを表示するようにします。

--query オプションを使うことでそれを指定できます。
検索パイプで渡して jq コマンドを実行している例もありますが、今は --query だけで事足りるようです。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].{Env:Tags[?Key==`Environment`]|[0].Value,InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,PrivateIp:PrivateIpAddress,PublicIp:PublicIpAddress}'

[
    {
        "InstanceId": "i-XXXXXXX",
        "PublicIp": null,
        "Name": "host1",
        "Env": "Development",
        "PrivateIp": "10.XX.XXX.XXX"
    },
    {
        "InstanceId": "i-XXXXXXX",
        "PublicIp": "13.XXX.XX.XX",
        "Name": "host2",
        "Env": "Production",
        "PrivateIp": "10.XX.XXX.XXX"
    },
    {
        "InstanceId": "i-XXXXXXX",
        "PublicIp": null,
        "Name": "host3",
        "Env": "Staging",
        "PrivateIp": "10.XX.XXX.XXX"
    },
…
]

自分のプロジェクトでは、Environmentタグに環境名を、Nameタグにインスタンス名を設定しています。
"[?~]" で条件による絞り込みが可能です。値はバッククォートで囲います。
デフォルトだと配列形式の出力となり、Valueに対する項目名がわかりにくいので、MultiSelect Hash連想配列にしています。
尚、Reservation とは インスタンスを起動するアクション のことです。

3. テーブル形式で出力する

JSON形式よりもヒューマンリーダブルなテーブル形式にします。
こちらはコマンドに --output table を追加するだけです。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].{Env:Tags[?Key==`Environment`]|[0].Value,InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,PrivateIp:PrivateIpAddress,PublicIp:PublicIpAddress}' --output table

---------------------------------------------------------------------------------------------------------
|                                           DescribeInstances                                           |
+-------------+----------------------+------------------------------+----------------+------------------+
|     Env     |     InstanceId       |            Name              |   PrivateIp    |    PublicIp      |
+-------------+----------------------+------------------------------+----------------+------------------+
|  Production |  i-XXXXX1            |  host1                       |  10.XXX.X.XXX  |  13.XXX.XXX.XXX  |
|  Staging    |  i-XXXXX3            |  host3                       |  10.XXX.X.XXX  |  None            |
|  Staging    |  i-XXXXX4            |  host4                       |  10.XXX.X.XXX  |  13.XXX.XXX.XXX  |
|  Development|  i-XXXXX6            |  host6                       |  10.XXX.X.XXX  |  None            |
|  Production |  i-XXXXX2            |  host2                       |  10.XXX.X.XXX  |  None            |
|  Staging    |  i-XXXXX5            |  host5                       |  10.XXX.X.XXX  |  None            |
…
4. 環境でソートする(最終形)

バラバラなまま表示することは運用上少ないので、環境名でソートします。
3. のコマンドの結果をパイプでつないで sort_by というソート関数を噛ませます。

今回ここが割りと肝だったのですが、Environmentタグを定義していないインスタンスがある場合、ソート関数を単純に追加すると下記エラーが起きます。

In function sort_by(), invalid type for value: None, expected one of: ['string'], received: "null"

なので、 not_null という関数で、Environmentタグの値がnullのインスタンスを事前に除外します。


上記2点を踏まえて変更した最終形のコマンドがこちらです。

$ aws ec2 describe-instances --query 'Reservations[].Instances[?not_null(Tags[?Key==`Environment`].Value)][].{Env:Tags[?Key==`Environment`]|[0].Value,InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,PrivateIp:PrivateIpAddress,PublicIp:PublicIpAddress}|sort_by(@,&Env)[]' --output table

---------------------------------------------------------------------------------------------------------
|                                           DescribeInstances                                           |
+-------------+----------------------+------------------------------+----------------+------------------+
|     Env     |     InstanceId       |            Name              |   PrivateIp    |    PublicIp      |
+-------------+----------------------+------------------------------+----------------+------------------+
|  Development|  i-XXXXX1            |  host1                       |  10.XXX.X.XXX  |  13.XXX.XXX.XXX  |
|  Development|  i-XXXXX2            |  host2                       |  10.XXX.X.XXX  |  None            |
|  Development|  i-XXXXX3            |  host3                       |  10.XXX.X.XXX  |  None            |
|  Development|  i-XXXXX4            |  host4                       |  10.XXX.X.XXX  |  None            |
|  Development|  i-XXXXX5            |  host5                       |  10.XXX.X.XXX  |  None            |

…

|  Staging    |  i-XXXXX10           |  host10                      |  10.XXX.X.XXX  |  None            |
|  Staging    |  i-XXXXX11           |  host11                      |  10.XXX.X.XXX  |  13.XXX.XXX.XXX  |
|  Staging    |  i-XXXXX12           |  host12                      |  10.XXX.X.XXX  |  None            |
+-------------+----------------------+------------------------------+----------------+------------------+

これで必要最低限の全EC2インスタンス情報が表示されるようになりました。

A. ホスト名で絞りたい

特定のホスト名で絞りこんで表示したい場合は、3. のコマンドに対して --filter で絞り込むだけです。

$ aws ec2 describe-instances --filter 'Name=tag:Name,Values=host10' 
 --query 'Reservations[].Instances[?not_null(Tags[?Key==`Environment`].Value)][].{Env:Tags[?Key==`Environment`]|[0].Value,InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,PrivateIp:PrivateIpAddress,PublicIp:PublicIpAddress}|sort_by(@,&Env)[]' --output table

---------------------------------------------------------------------------------------------------------
|                                           DescribeInstances                                           |
+-------------+----------------------+------------------------------+----------------+------------------+
|     Env     |     InstanceId       |            Name              |   PrivateIp    |    PublicIp      |
+-------------+----------------------+------------------------------+----------------+------------------+
|  Staging    |  i-XXXXX10           |  host10                      |  10.XXX.X.XXX  |  None            |
+-------------+----------------------+------------------------------+----------------+------------------+

4. のコマンドでもいいですが、このケースではnullチェックやsortは不要かと思います。

B. 環境で絞りたい

A. と同じく --filter をかけます。

$ aws ec2 describe-instances --filter 'Name=tag:Environment,Values=Staging' --query 'Reservations[].Instances[?not_null(Tags[?Key==`Environment`].Value)][].{Env:Tags[?Key==`Environment`]|[0].Value,InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,PrivateIp:PrivateIpAddress,PublicIp:PublicIpAddress}' --output table

---------------------------------------------------------------------------------------------------------
|                                           DescribeInstances                                           |
+-------------+----------------------+------------------------------+----------------+------------------+
|     Env     |     InstanceId       |            Name              |   PrivateIp    |    PublicIp      |
+-------------+----------------------+------------------------------+----------------+------------------+
|  Staging    |  i-XXXXX10           |  host10                      |  10.XXX.X.XXX  |  None            |
|  Staging    |  i-XXXXX11           |  host11                      |  10.XXX.X.XXX  |  13.XXX.XXX.XXX  |
|  Staging    |  i-XXXXX12           |  host12                      |  10.XXX.X.XXX  |  None            |
+-------------+----------------------+------------------------------+----------------+------------------+

複数環境を指定したい場合は、バラバラに出力されないようにsortもかけたほうがよいです。


以上、どなたかのご参考になれば幸いです。