AWS RDS for MySQL5.5 => 5.6 アップグレード手順 (CLI) (2017年検証)

AWSから5.5の古いバージョンアップデートするよー。って通知がきたので
手動アップグレードをすることに。

ググッてみたけども、RDSって枯れてるからか、古い情報しかないんですよね。
そこでメモがてらに手順を記載します。

## やること

* 本番稼働しているRDS MySQL 5.5.40b を MySQL 5.6.29にアップグレードする
    * (注意!!)ダウンタイムが数分発生します
* エンドポイントはそのままでアプリケーション側等の変更は行わない

## 環境

* MacOSX ElCapitan (HostOS)
    * 10.11.6


## 事前準備に必要なもの

* [AWS CLI](https://aws.amazon.com/jp/cli/)
  * 入っていない人は何も考えずに ``` pip install awscli ``` と打とう。

## 参考にしたサイト

* [ AWS Documentation DB インスタンスのデータベースエンジンバージョンのアップグレード](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Upgrading.html#USER_UpgradeDBInstance.MySQL)
    * 手順全体はコレと一緒です。
* [ AWS Documentation DB インスタンスの名前変更](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RenameInstance.html)

## 全体の流れ

全ての手順を AWS CLI で実行しています。


* アップグレードしたいRDSインスタンス(Masterインスタンス)にリードレプリカを作成する
* リードレプリカを作成したら、リードレプリカ側のMySQLをバージョンアップする
* リードレプリカのインスタンスをマスター昇格させる
    * 厳密にはリード専用ではなく、独立したインスタンスにさせる
    * この時点でマスターインスタンス側がデータが更新されるとデータ不整合が発生します。
* マスターインスタンスとマスター昇格させたリードレプリカインスタンスのエンドポイントを切り替える。
    * この切り替えの期間がダウンタイム発生時間です。

## 手順

以下ここから全体の流れの詳細。
作業はHostOS(Mac)から作業しています。

### バージョンアップしたいRDSインスタンスの確認


#### マスターインスタンス名を変数にエクスポート

```
MASTER_INSTANCE='{DBインスタンス名}'
```

変数の確認

```
cat << ETX

        MASTER_INSTANCE ${MASTER_INSTANCE}
        
ETX
```

#### マスターインスタンスの確認

```
aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE}
```

マスターインスタンスのMySQLバージョンの確認

```
aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].EngineVersion' --output text
```

レスポンス

```
5.5.40b
```

### マスターインスタンスのリードレプリカを作成

* 今回は同一AvailabilityZoneに作成しています。
* AvailabilityZoneの指定をしない場合違うAvailabilityZoneに作成されてしまう可能性がありますので、用途に応じて実行してください。

#### アップグレードインスタンス名を変数にエクスポート


```
UPGRADE_INSTANCE='{DBインスタンス名}'
```

変数の確認

```
cat << ETX

        UPGRADE_INSTANCE ${UPGRADE_INSTANCE}
        
ETX
```

#### マスターインスタンス側のAvailabilityZoneを確認

```
AZ=$(aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].AvailabilityZone' --output text)
```

変数の確認

```
cat << ETX

        AZ ${AZ}
        
ETX
```


#### リードレプリカを作成する。

実行後、マスターインスタンス側にリードレプリカの設定が走るので多少の負荷がかかります。

リードレプリカの作成に数分かかります。

```
aws rds create-db-instance-read-replica \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --source-db-instance-identifier ${MASTER_INSTANCE} \
    --availability-zone ${AZ}
```

マスターインスタンス側にリードレプリカが設定されていることの確認

```
aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].ReadReplicaDBInstanceIdentifiers' --output text
```

レスポンスが作成したリードレプリカと一致していることを確認

```
cat << ETX

        `aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].ReadReplicaDBInstanceIdentifiers' --output text` == ${UPGRADE_INSTANCE}
        
ETX
```

レスポンス

```
        {マスター側リードレプリカ設定DBインスタンス名} == {アップグレードDBインスタンス名}
```

スレーブの同期状態の確認

* マスターインスタンスに接続できるEC2インスタンスから一旦mysqlコマンドで接続します。
* Seconds_Behind_Master はスレーブ遅延の秒数です。 0であればスレーブ遅延していません。


```
mysql -h {アップグレードインスタンスのエンドポイント} -u {ユーザー名} -p --auto-rehash
```

スレーブのステータスを確認

```
> SHOW SLAVE STATUS\G
```


``` Seconds_Behind_Master: 0 ``` となっていることを確認してください。なっていない場合スレーブ遅延が発生しています。



#### リードレプリカインスタンス用のパラメーターグループの作成

マスターインスタンスのパラメーターグループファミリーがmysql5.5の為別途パラメーターグループを設定する必要があります。

パラメーターグループを作成しなくてもよい場合は ``` default.mysql5.6 ``` を使用してください。
ただしデフォルトパラメーターグループだとMySQL側の細かな設定を変更できないのでおすすめはしません。

パラメーターグループ名を変数にエクスポート


```
PARAMETER_GROUP='{任意の名前}'
```

変数の確認

```
cat << ETX

        PARAMETER_GROUP ${PARAMETER_GROUP}

ETX
```

パラメーターグループの作成

```
aws rds create-db-parameter-group \
    --db-parameter-group-name ${PARAMETER_GROUP} \
    --db-parameter-group-family 'mysql5.6' \
    --description 'mysql5.6 parameter group'
```

パラメーターグループの確認

```
aws rds describe-db-parameter-groups \
    --db-parameter-group-name ${PARAMETER_GROUP}
```


#### リードレプリカインスタンス側のMySQLバージョンアップ

* リードレプリカインスタンスのStatusが ``` available ``` になってから作業してください

リードレプリカインスタンスの状態確認

```
aws rds describe-db-instances --db-instance-identifier ${UPGRADE_INSTANCE}
```

MySQLのバージョン確認

```
cat << ETX

        `aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].EngineVersion' --output text` == `aws rds describe-db-instances --db-instance-identifier ${UPGRADE_INSTANCE} --query 'DBInstances[].EngineVersion' --output text`
        
ETX
```

レスポンス

```
        5.5.40b == 5.5.40b
```


リードレプリカのバージョンアップ

* ``` --apply-immediately ``` を指定しないと即時反映されません。
* アップグレードに数分かかります

```
aws rds modify-db-instance \
  --db-instance-identifier ${UPGRADE_INSTANCE}  \
  --apply-immediately \
  --allow-major-version-upgrade \
  --db-parameter-group-name ${PARAMETER_GROUP} \
  --option-group-name 'default:mysql-5-6' \
  --engine-version 5.6.29
```


#### リードレプリカのマスター昇格

コレを実行した時点でマスターインスタンスからのデータ同期は解除されますのでこれ以降の作業は
速やかにやりましょう

```
 aws rds promote-read-replica \
  --db-instance-identifier ${UPGRADE_INSTANCE} \
```

リードレプリカインスタンスからリードオンリーのフラグが外れていることの確認

```
aws rds describe-db-instances \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --query 'DBInstances[].StatusInfos' \
    --output text
```

上記パラメーターで ``` replicating ``` ``` read replication ``` の設定がなくなっていたらOK

#### マスターインスタンスのエンドポイントの変更

マスターインスタンス側のエンドポイントを先に剥がさないとリードレプリカインスタンスにエンドポイントを付け替えできません。


確認

```
cat << ETX

       MASTER_INSTANCE ${MASTER_INSTANCE}

ETX
```

エンドポイントの切り替え

* 実行後rebootが走ります。

```
aws rds modify-db-instance \
    --db-instance-identifier ${MASTER_INSTANCE} \
    --new-db-instance-identifier "${MASTER_INSTANCE}-cold-standby" \
    --apply-immediately
```

#### リードレプリカインスタンスのエンドポイントの変更


確認

```
cat << ETX

       UPGRADE_INSTANCE ${UPGRADE_INSTANCE}

ETX
```

* 実行後rebootが走ります。

```
aws rds modify-db-instance \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --new-db-instance-identifier "${MASTER_INSTANCE}" \
    --apply-immediately
```


## 補足 バージョンアップ失敗時のロールバック手順

何かしらの原因でバージョンアップで動作不調の場合は下記の方法にてロールバックを行います。

* 切り替え後すぐの動作不調の場合の方法になります
* 時間がしばらく経過の場合はsnapshotからの復元のほうがいいかと思います


### アップグレードしたインスタンスをコールドスタンバイに変更

```
aws rds modify-db-instance \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --new-db-instance-identifier "${UPGRADE_INSTANCE}-cold-stanby" \
    --apply-immediately
```

### 元のインスタンスのエンドポイントを変更

```
aws rds modify-db-instance \
    --db-instance-identifier "${MASTER_INSTANCE}-cold-stanby" \
    --new-db-instance-identifier "${MASTER_INSTANCE}" \
    --apply-immediately
```


## 最後に

以上でMySQL 5.5 => 5.6のアップグレード手順になります。
公式のドキュメントで記載していますが、5.6 => 5.7 も同様の手順でできるとは書いてあります。