EC2 NameTag から ELB の操作をする

# 概要
本ページでは、ELB(ここではClassicLoadBalancer)のアタッチ・デタッチを EC2 の `tag:Name` で行えるようにした手法について説明する。

# ゴール
ELB名に続いてインスタンス名を複数指定することで複数台のアタッチ・デタッチを可能にする。

```bash
$ aws-register.sh ${elb-name} [${EC2 tag:Name} ..... ]
```

# 準備
* EC2 インスタンスを準備 (今回は `t3.micro` をスポットインスタンスで3台用意)
    * clom-spot-t3{01-03} を用意

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/61893/8f518476-f8b3-cc55-cad2-98be5fd4159c.png)

* ELB は Classic Load Balancer を用意する
    * `clom-classic-lb` を用意する

![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/61893/4767a4fd-a8c8-e338-9c65-edbcfcde5692.png)

## 使用する AWS CLI
今回は EC2 のインスタンスIDが必要なため、インスタンス情報を表示する `describe-instances` を使用する。
また、EC2をELBにアタッチ・デタッチする為に `register-instances-with-load-balancer`,  `deregister-instances-from-load-balancer` を使用する。

# 実装
## describe-instances
* `filter` を用いて `tag:Name` で該当のインスタンスの情報が表示できるようにする。`,` で OR 条件になるため、複数ある場合は `clom-spot-t301, clom-spot-t302` のように指定をする。
* 取得できる情報としては色々な物があるが、今回は `InstanceId` のみ必要な為、 `Reservations[].Instances[].InstanceId` を jq 等でフィルタリングすると以下のコマンドで次の情報が取得できる。

```bash
aws ec2 describe-instances --filter "Name=tag:Name,Values=${INSTANCES}" | jq -r ".Reservations[].Instances[].InstanceId"
```

```bash
i-xxxxxxxxxxxx
i-xxxxxxxxxxxx
```

それ以外に取得できる情報としては
https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html
を確認されたい。

## register-instances-with-load-balancer,  deregister-instances-from-load-balancer
* `register-instances-with-load-balancer`は CLB にインスタンスをアタッチする際に用いり、`deregister-instances-from-load-balancer` は インスタンスを CLB からデタッチする際に用いる。
* CLI の記法としてはどちらも同様に以下のような形になる。例はアタッチ時である。

```bash
aws elb register-instances-with-load-balancer \
 --load-balancer-name ${ELB名} \
 --instances ${INSTANCE_ID}
```

ここでの `INSTANCE_ID` は`i-xxxxxxxxxxxx i-xxxxxxxxxxxx` のように、空白区切りで指定する必要がある。これにより指定したインスタンスをELBにアタッチ・デタッチが可能となる。

## shell script を書く
2種のコマンドを用いり、Nameで指定したインスタンス名をCLBにアタッチするスクリプトを記載する。
(デタッチはアタッチの項目をデタッチに変更するのみで実現するため、ここでは割愛する。)

```bash
#!/bin/sh
# AWS ELB attach

ARG=("$@")
ELB=${ARG[0]}

unset -v ARG[0]

IFS=,
INSTANCES=${ARG[*]}
INSTANCE_ID=(`aws ec2 describe-instances --filter "Name=tag:Name,Values=${INSTANCES}" | jq -r ".Reservations[].Instances[].InstanceId "`)

IFS=$'\n'
# AWS register ELB
aws elb register-instances-with-load-balancer --load-balancer-name ${ELB} \
 --instances ${INSTANCE_ID}

if [ $? -eq 0 ]; then
    echo "${ELB} is attached ${INSTANCES}"
else
   echo "${ELB} is not attached ${INSTANCES}"
fi
```

先の節で出力例を示したが、`describe-instances` の結果をそのままELBの引数には持ってくることはできない。また、shell実行時の引数の形式(`clom-classic-lb clom-spot-t301 clom-spot-t302`)では、LB名が`describe-instances`に入ることや、空白区切りになっているためNameでORのフィルタを書けることが出来なくなる。

そこで引数や返り値を配列にして `IFS` に次に使用するコマンドに合わせた区切り文字に変更して利用している。
これにより、引数のフォーマットが異なる場合でも対応することが可能となる。

## 実行結果

アタッチした場合の実行結果はこのような形になる。

```bash
A). nonoca@chihaya:~$ bash aws-register.sh clom-classic-lb clom-spot-t301 clom-spot-t302
{
    "Instances": [
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx"
        },
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx"
        }
    ]
}
clom-classic-lb is attached clom-spot-t301,clom-spot-t302


B). nonoca@chihaya:~$ bash aws-register.sh clom-classic-lb clom-spot-t303
{
    "Instances": [
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx"
        },
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx"
        },
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx"
        }
    ]
}
clom-classic-lb is attached clom-spot-t303

```

Aの実行結果のマネジメントコンソールは以下のようになる
![キャプチャ5.PNG](https://qiita-image-store.s3.amazonaws.com/0/61893/a42fb555-49e6-a3b1-989f-0e6a791a6b41.png)

Bの実行結果のマネジメントコンソールは以下のようになる
![キャプチャ4.PNG](https://qiita-image-store.s3.amazonaws.com/0/61893/c56709b8-9b6e-014d-7c41-00b511137beb.png)

# まとめ
以上のことから、ShellScript でインスタンス名(tag:Name)からELBにアタッチすることが可能になった。
これを組み合わせることでインスタンス名からELBのアタッチ・デタッチ以外にも様々なアクションを取ることが出来るのではないかと思う。