Aurora ClusterのReplica作成をスクリプト化する

[Relux Advent Calendar](https://qiita.com/advent-calendar/2017/relux) 22日目の記事です。

ReluxではRDBMSとしてRDS Auroraを使用しています。
サイトへのアクセス増が見込まれる時など、Read Replicaの追加やサイズ変更を行なうのですが、Webのコンソールでは、ブラウザでログイン・ポチポチと操作・利用可能になるまで待つといったことが面倒です。
そこで、必要なパラメータを指定してReplicaを生成し、利用できるまで待つスクリプトを作りました。

## スクリプトの中で使用するコマンド
**jq**
コマンドラインやシェルスクリプトでjsonを扱う際の必須コマンドです。mac os であればbrewでインストールできます。たいていのLinuxディストリビューションでは、OS標準のパッケージリポジトリに用意されていると思います。

**AWS CLI**
コマンドラインでawsの操作をする際の必須コマンド群です。pipなどでインストールします。

## AWS CLIでAurora ClusterのReplicaを作成する際の注意

AWS CLIには `create-db-instance-read-replica` という非常にそれっぽいrdsのサブコマンドがあるのですが、これではAurora ClusterのReplicaは作成できません。
<a href="http://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance-read-replica.html" target="_blank">マニュアル</a>にこのような注意書きがあります。

> Amazon Aurora does not support this action. You must call the create-db-instance action to create a DB instance for an Aurora DB cluster.

AuroraのReplicaを作成する際には、インスタンスを作成するためのコマンドである `create-db-instance` を使用します。
例えば、 db-cluster-name というクラスタに new-replica-instance という名前のRead Replicaを r4.xlarge で作成する際には、下記のようなコマンドを発行します。

```
aws rds create-db-instance \
    --engine aurora \
    --db-cluster-identifier 'db-cluster-name' \
    --db-instance-identifier 'new-replica-instance' \
    --db-instance-class 'db.r4.xlarge' \
    --availability-zone 'ap-northeast-1a'
```

## 作成したスクリプト

```bash
#!/bin/bash

while getopts c:n:p:s:z: OPT
do
    case $OPT in
        c)  clusterIdentifier=$OPTARG
            ;;
        n)  newReplicaIdentifier=$OPTARG
            ;;
        p)  parameterGroupName=$OPTARG
            ;;
        s)  newReplicaInstanceClass=$OPTARG
            ;;
        z)  replicaAvailabilityZone=$OPTARG
            ;;
    esac
done

function main() {
    createNewReadReplica

    waitForReadyToUseNewReplica

    showNewReplicaEndpoint
}

function createNewReadReplica() {
    aws rds create-db-instance \
        --engine aurora \
        --db-cluster-identifier $clusterIdentifier \
        --db-instance-identifier $newReplicaIdentifier \
        --db-instance-class $newReplicaInstanceClass \
        --availability-zone $replicaAvailabilityZone \
        --db-parameter-group-name $parameterGroupName \
        --promotion-tier 0 \
        --no-publicly-accessible
}

function waitForReadyToUseNewReplica() {
    echo -n 'waiting for ready to use new replica instance'
    while :
    do
        echo -n '.'
        local instanceStatus=`aws rds describe-db-instances --filters "Name=db-instance-id,Values="${newReplicaIdentifier} | jq -r '.DBInstances[0].DBInstanceStatus'`
        if test $instanceStatus = 'available'; then
            break
        elif test $instanceStatus = ''; then
            echo 'Error: could not create new replica instance!' >&2
            exit 1
        fi
        sleep 10
    done

    echo 'New instance '$newReplicaIdentifier' has been available!'
}

function showNewReplicaEndpoint() {
    aws rds describe-db-instances --filters "Name=db-instance-id,Values="${newReplicaIdentifier} | jq -r '.DBInstances[0].Endpoint.Address'
}

main
```

### 解説・使用方法

クラスタ名・作成するインスタンス名・インスタンスタイプ・AZ・パラメータグループ名を引数で指定し、スクリプトを実行します。
まず、ReadReplicaを作成するコマンドが発行され、statusがavailableになるまで待つ処理が入り、availableになると新しいReplicaのエンドポイントを出力して終了します。

実行例

```
$ bash create-relux-db-replica.bash -c cluster-name -n new-replica-instance-name -p parameter-group-name -s db.r3.4xlarge -z ap-northeast-1c

waiting for ready to use new replica instance............................New instance new-replica-instance-name has been available!
new-replica-instance-name.*******.ap-northeast-1.rds.amazonaws.com
```

availableになるまで待つので、 利用可能になったインスタンスを使うための処理を && で続けて書くことができます。

## これをAnsible化したい

現在、いろいろなオペレーションのAnsible化を進めています。
これもAnsibleで書きたいのですが、AWS CLIでの `--db-cluster-identifier` に当たるオプションがなかったり、AuroraのReplicaでは必要のないディスクサイズの指定やユーザ名の指定が必須だったりと、なんだかうまくいかず試行錯誤しているところです。

うまくできたら、Ansibleでの実装方法も記事にしようと思います。