[JAWS-UG CLI] RDS:#1 DBインスタンスの作成 (PostgreSQL: Public MultiAZ)


前提条件
========


RDSへの権限
-----------

RDSに対してフル権限があること。


EC2への権限
-----------

EC2への読み取り権限があること。


AWS CLI
-------

以下のバージョンで動作確認済

- AWS CLI 1.11.14

```bash:コマンド:
aws --version
```

```text:結果(例):
      aws-cli/1.11.14 Python/2.7.10 Darwin/15.6.0 botocore/1.4.71
```

バージョンが古い場合は最新版に更新しましょう。

```bash:コマンド:
sudo -H pip install -U awscli
```


AWSアカウントの属性
-------------------

AWSアカウントがEC2-Classicに対応していないこと。

```bash:コマンド:
AWS_SUPPORT_PLATFORMS=$( \
               aws ec2 describe-account-attributes \
                 --query 'AccountAttributes[?AttributeName == `supported-platforms`].AttributeValues[].AttributeValue' \
                 --output text \
      ) && echo ${AWS_SUPPORT_PLATFORMS}
```

```text:結果(例):
      VPC
```

'VPC'の他に'EC2'が表示される場合、別のアカウントを作成もしくは利用してください。


デフォルトVPCの存在
-------------------

デフォルトVPCが存在すること。


psqlコマンドの存在
------------------

```bash:コマンド:
which psql
```

```text:結果(存在する場合の例):
      /opt/local/bin/psql
```

```text:結果(存在しない場合の例):
      psql: Command not found.
```

psqlコマンドのインストール: https://qiita.com/tcsh/items/be2f64904a3194f0a96b


0. 準備
=======


0.1. リージョンの決定
---------------------

```bash:変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'
```


0.2. 変数の確認
---------------

プロファイルが想定のものになっていることを確認します。

```bash:変数の確認:
aws configure list
```

```text:結果(例):
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile       rdsFull-prjz-mbp13        env    AWS_DEFAULT_PROFILE
      access_key     ****************XXXX shared-credentials-file
      secret_key     ****************XXXX shared-credentials-file
          region        ap-northeast-1        env    AWS_DEFAULT_REGION
```


0.3. セキュリティーグループの指定
---------------------------------

```bash:変数の設定:
VPC_SG_NAME='postgresql-2017-11-20'
```

セキュリティーグループのIDを取得します。

```bash:コマンド:
VPC_SG_ID=$( \
        aws ec2 describe-security-groups \
          --filter Name=group-name,Values=${VPC_SG_NAME} \
          --query 'SecurityGroups[].GroupId' \
          --output text \
) \
        && echo ${VPC_SG_ID}
```

```text:結果(例):
      sg-xxxxxxxx
```


1. 事前作業
===========


1.1. DBエンジンの決定
---------------------

```bash:変数の設定:
RDS_ENGINE_NAME='postgres'
```


1.2. License Model
------------------

PostgreSQLのライセンスモデルは1つのみです。

デフォルト値: postgresql-license


1.3. DB Instance Class
----------------------

```bash:変数の設定:
RDS_INSTANCE_CLASS='db.t2.micro'
```


1.4. Allocated Storage
----------------------

データベース用に5GBのストレージを割り当てます。

```bash:変数の設定:
RDS_STORAGE_SIZE='5'
```


1.5. DB Instance Identifier
---------------------------

DBインスタンス名を決定します。

選択したリージョン内で、自分のアカウントに対して一意であることが必要です。

```bash:変数の設定:
RDS_INSTANCE_IDENT="postgre-handson-$(date +%Y%m%d)" \
        && echo ${RDS_INSTANCE_IDENT}
```


1.6. Master Username
--------------------

DB インスタンスにログオンするためのマスターユーザー名を英数字で入力します。

```bash:変数の設定:
RDS_USER_NAME='pgadmin'
```


1.6. Master Password
--------------------

マスターパスワードとして 8～128 個の表示可能な ASCII 文字（/、"、@ 以外）を指定します。

```bash:変数の設定(例):
RDS_USER_PASS='#dbPass123'
```


1.7 データベース名の指定
------------------------

データベースの名前を、英数字 63 文字以内で入力します。 (起動後に追加できない)

```bash:変数の設定:
RDS_DB_NAME="handson$(date +%Y%m%d)" \
        && echo ${RDS_DB_NAME}
```

注釈: 名前を指定しない場合、DB インスタンスでデフォルトのデータベースは作成されません。


1.8 ポートの指定 (省略)
-----------------------

DBインスタンスを作成するとポートを変更できないため、デフォルトと異なるポートを利用する場合は、DBインスタンス作成時に指定する必要があります。

デフォルト値: 5432 (PostgreSQLの場合)


1.9. VPC IDの取得
-----------------

```bash:コマンド:
VPC_ID=$( \
        aws ec2 describe-vpcs \
          --filters Name=isDefault,Values=true \
          --query 'Vpcs[].VpcId' \
          --output text \
  ) \
          && echo ${VPC_ID}
```

```text:結果(例):
      vpc-xxxxxxxx
```


1.10. セキュリティグループの配列への追加
----------------------------------------

```bash:変数の設定:
ARRAY_SG_ID="${VPC_SG_ID} ${ARRAY_SG_ID}" \
        && echo ${ARRAY_SG_ID}
```


2. DBインスタンスの作成
=======================


2.1. 起動時刻の確認
-------------------

```bash:変数の設定:
DATETIME_UTC=$( date -u '+%Y-%m-%dT%H:%MZ' ) \
        && echo ${DATETIME_UTC}
```

```text:結果(例):
      2016-11-13T01:23Z
```


2.2. DBインスタンスの起動
-------------------------

```bash:変数の確認:
cat << ETX

        RDS_INSTANCE_IDENT: ${RDS_INSTANCE_IDENT}
        RDS_STORAGE_SIZE:   ${RDS_STORAGE_SIZE}
        RDS_INSTANCE_CLASS: ${RDS_INSTANCE_CLASS}
        RDS_ENGINE_NAME:    ${RDS_ENGINE_NAME}
        RDS_USER_NAME:      ${RDS_USER_NAME}
        RDS_USER_PASS:      ${RDS_USER_PASS}
        RDS_DB_NAME:        ${RDS_DB_NAME}
        ARRAY_SG_ID:        ${ARRAY_SG_ID}

ETX
```

```bash:コマンド:
aws rds create-db-instance \
        --db-instance-identifier ${RDS_INSTANCE_IDENT} \
        --allocated-storage ${RDS_STORAGE_SIZE} \
        --db-instance-class ${RDS_INSTANCE_CLASS} \
        --engine ${RDS_ENGINE_NAME} \
        --master-username ${RDS_USER_NAME} \
        --master-user-password ${RDS_USER_PASS} \
        --db-name ${RDS_DB_NAME} \
        --vpc-security-group-ids ${ARRAY_SG_ID} \
        --publicly-accessible \
        --multi-az
```

```text:結果(例):
      {
        "DBInstance": {
          "PubliclyAccessible": true,
          "MasterUsername": "pgadmin",
          "MonitoringInterval": 0,
          "LicenseModel": "postgresql-license",
          "VpcSecurityGroups": [
              {
                  "Status": "active",
                  "VpcSecurityGroupId": "sg-xxxxxxxx"
              }
          ],
          "CopyTagsToSnapshot": false,
          "OptionGroupMemberships": [
              {
                  "Status": "in-sync",
                  "OptionGroupName": "default:postgres-9-5"
              }
          ],
          "PendingModifiedValues": {
              "MasterUserPassword": "****"
          },
          "Engine": "postgres",
          "MultiAZ": false,
          "DBSecurityGroups": [],
          "DBParameterGroups": [
              {
                  "DBParameterGroupName": "default.postgres9.5",
                  "ParameterApplyStatus": "in-sync"
              }
          ],
          "AutoMinorVersionUpgrade": true,
          "PreferredBackupWindow": "14:30-15:00",
          "DBSubnetGroup": {
              "Subnets": [
                  {
                      "SubnetStatus": "Active",
                      "SubnetIdentifier": "subnet-xxxxxxxx",
                      "SubnetAvailabilityZone": {
                          "Name": "ap-northeast-1a"
                      }
                  },
                  {
                      "SubnetStatus": "Active",
                      "SubnetIdentifier": "subnet-xxxxxxxx",
                      "SubnetAvailabilityZone": {
                          "Name": "ap-northeast-1c"
                      }
                  }
              ],
              "DBSubnetGroupName": "default",
              "VpcId": "vpc-xxxxxxxx",
              "DBSubnetGroupDescription": "default",
              "SubnetGroupStatus": "Complete"
          },
          "ReadReplicaDBInstanceIdentifiers": [],
          "AllocatedStorage": 5,
          "DBInstanceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
          "BackupRetentionPeriod": 1,
          "DBName": "handson20161114",
          "PreferredMaintenanceWindow": "sat:17:17-sat:17:47",
          "DBInstanceStatus": "creating",
          "EngineVersion": "9.5.4",
          "DomainMemberships": [],
          "StorageType": "standard",
          "DbiResourceId": "db-XXXXXXXXXXXXXXXXXXXXXXXXXX",
          "CACertificateIdentifier": "rds-ca-2015",
          "StorageEncrypted": false,
          "DBInstanceClass": "db.t2.micro",
          "DbInstancePort": 0,
          "DBInstanceIdentifier": "postgre-handson-20161114"
        }
      }
```


DBインスタンスの状態確認
------------------------

```bash:変数の設定:
RDS_INSTANCE_STATUS=$( \
        aws rds describe-db-instances \
          --db-instance-identifier ${RDS_INSTANCE_IDENT} \
          --query 'DBInstances[].DBInstanceStatus' \
          --output text \
) \
          && echo ${RDS_INSTANCE_STATUS}
```

```text:結果(例):
      creating
```

availableになればデータベースを利用することができます。

注釈: t2でも起動に7分くらいかかるようです。


3. 事後確認
===========


3.1. イベントの確認
-------------------

```bash:変数の設定:
RDS_EVENT_TYPE='db-instance'
RDS_EVENT_START=${DATETIME_UTC}
RDS_MAX_ITEMS='3'
```

```bash:コマンド:
aws rds describe-events \
        --start-time ${RDS_EVENT_START} \
        --source-type ${RDS_EVENT_TYPE} \
        --max-items ${RDS_MAX_ITEMS}
```

```text:結果(例):
      {
        "Events": [
          {
              "EventCategories": [
                  "creation"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:28:38.782Z",
              "Message": "DB instance created",
              "SourceIdentifier": "postgre-handson-20161114"
          },
          {
              "EventCategories": [
                  "backup"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:29:47.617Z",
              "Message": "Backing up DB instance",
              "SourceIdentifier": "postgre-handson-20161114"
          },
          {
              "EventCategories": [
                  "backup"
              ],
              "SourceType": "db-instance",
              "SourceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "Date": "2016-11-13T05:32:17.561Z",
              "Message": "Finished DB Instance backup",
              "SourceIdentifier": "postgre-handson-20161114"
          }
        ]
      }
```


3.2. DBインスタンス情報の確認
-----------------------------

```bash:コマンド:
aws rds describe-db-instances \
        --db-instance-identifier ${RDS_INSTANCE_IDENT}
```

```text:結果(例):
      {
        "DBInstances": [
          {
              "PubliclyAccessible": true,
              "MasterUsername": "pgadmin",
              "MonitoringInterval": 0,
              "LicenseModel": "postgresql-license",
              "VpcSecurityGroups": [
                  {
                      "Status": "active",
                      "VpcSecurityGroupId": "sg-xxxxxxxx"
                  }
              ],
              "InstanceCreateTime": "2016-11-13T05:28:38.651Z",
              "CopyTagsToSnapshot": false,
              "OptionGroupMemberships": [
                  {
                      "Status": "in-sync",
                      "OptionGroupName": "default:postgres-9-5"
                  }
              ],
              "PendingModifiedValues": {},
              "Engine": "postgres",
              "MultiAZ": false,
              "LatestRestorableTime": "2016-11-13T05:29:47.646Z",
              "DBSecurityGroups": [],
              "DBParameterGroups": [
                  {
                      "DBParameterGroupName": "default.postgres9.5",
                      "ParameterApplyStatus": "in-sync"
                  }
              ],
              "AutoMinorVersionUpgrade": true,
              "PreferredBackupWindow": "14:30-15:00",
              "DBSubnetGroup": {
                  "Subnets": [
                      {
                          "SubnetStatus": "Active",
                          "SubnetIdentifier": "subnet-xxxxxxxx",
                          "SubnetAvailabilityZone": {
                              "Name": "ap-northeast-1a"
                          }
                      },
                      {
                          "SubnetStatus": "Active",
                          "SubnetIdentifier": "subnet-xxxxxxxx",
                          "SubnetAvailabilityZone": {
                              "Name": "ap-northeast-1c"
                          }
                      }
                  ],
                  "DBSubnetGroupName": "default",
                  "VpcId": "vpc-xxxxxxxx",
                  "DBSubnetGroupDescription": "default",
                  "SubnetGroupStatus": "Complete"
              },
              "ReadReplicaDBInstanceIdentifiers": [],
              "AllocatedStorage": 5,
              "DBInstanceArn": "arn:aws:rds:ap-northeast-1:XXXXXXXXXXXX:db:postgre-handson-20161114",
              "BackupRetentionPeriod": 1,
              "DBName": "handson20161114",
              "PreferredMaintenanceWindow": "sat:17:17-sat:17:47",
              "Endpoint": {
                  "HostedZoneId": "Z24O6O9L7SGTNB",
                  "Port": 5432,
                  "Address": "postgre-handson-20161114.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"
              },
              "DBInstanceStatus": "available",
              "EngineVersion": "9.5.4",
              "AvailabilityZone": "ap-northeast-1a",
              "DomainMemberships": [],
              "StorageType": "standard",
              "DbiResourceId": "db-XXXXXXXXXXXXXXXXXXXXXXXXXX",
              "CACertificateIdentifier": "rds-ca-2015",
              "StorageEncrypted": false,
              "DBInstanceClass": "db.t2.micro",
              "DbInstancePort": 0,
              "DBInstanceIdentifier": "postgre-handson-20161114"
          }
        ]
      }
```


3.3. エンドポイントの確認
-------------------------

```bash:変数の設定:
RDS_INSTANCE_ENDPOINT=$( \
        aws rds describe-db-instances \
          --db-instance-identifier ${RDS_INSTANCE_IDENT} \
          --query 'DBInstances[].Endpoint.Address' \
          --output text \
) \
        && echo ${RDS_INSTANCE_ENDPOINT}
```

```text:結果(例):
      postgre-handson-ap-northeast-1.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com
```


3.4. 接続情報設定ファイルの作成
-------------------------------

```bash:変数の確認:
cat << ETX

        RDS_INSTANCE_ENDPOINT: ${RDS_INSTANCE_ENDPOINT}
        VPC_SG_PORT:           ${VPC_SG_PORT}
        RDS_DB_NAME:           ${RDS_DB_NAME}
        RDS_USER_NAME:         ${RDS_USER_NAME}
        RDS_USER_PASS:         ${RDS_USER_PASS}

ETX
```

```bash:コマンド:
echo "${RDS_INSTANCE_ENDPOINT}:${VPC_SG_PORT}:${RDS_DB_NAME}:${RDS_USER_NAME}:${RDS_USER_PASS}" >> ${HOME}/.pgpass \
        && chmod 600 ${HOME}/.pgpass \
        && cat ${HOME}/.pgpass
```


3.4. 接続
---------

```bash:コマンド:
psql \
        --host=${RDS_INSTANCE_ENDPOINT} \
        --username=${RDS_USER_NAME} \
        --dbname=${RDS_DB_NAME}
```

```text:結果:
      psql (9.5.5, server 9.5.4)
      SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
      Type "help" for help.

      handson20161114=>
```

DBコマンドのテスト実行をしてみます。

```sql:SQL:
select version();
```

```text:結果(例):
                                                       version
      ----------------------------------------------------------------------------------------------------------
        PostgreSQL 9.5.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit
       (1 row)
```

DBへの接続を切断します。

```bash:コマンド:
\q
```


3.5. 予定メンテナンスアクションの確認
-------------------------------------

```bash:コマンド:
aws rds describe-pending-maintenance-actions \
        --filter Name=db-instance-id,Values=${RDS_INSTANCE_IDENT}
```

```text:結果(例):
      {
          "PendingMaintenanceActions": []
      }
```


3.6. DBMSのログファイル確認
---------------------------

ログファイルの一覧を表示します。

```bash:コマンド:
aws rds describe-db-log-files \
        --db-instance-identifier ${RDS_INSTANCE_IDENT}
```

```text:結果(例):
      {
        "DescribeDBLogFiles": [
          {
              "LastWritten": 1479014886000,
              "LogFileName": "error/postgres.log",
              "Size": 307
          },
          {
              "LastWritten": 1479015287000,
              "LogFileName": "error/postgresql.log.2016-11-13-05",
              "Size": 1729
          }
        ]
      }
```

ログファイルをダウンロードします。

```bash:変数の設定:
RDS_LOG_NAME=<ダウンロードするLogFileName>
```

```bash:コマンド:
aws rds download-db-log-file-portion \
        --db-instance-identifier ${RDS_INSTANCE_IDENT} \
        --log-file-name ${RDS_LOG_NAME} \
        --query 'LogFileData' \
        --output text
```

```text:結果(例):
      2016-11-13 05:28:06 UTC::@:[3317]:LOG:  MultiXact member wraparound protections are now enabled
      2016-11-13 05:28:06 UTC::@:[3315]:LOG:  database system is ready to accept connections
      2016-11-13 05:28:06 UTC::@:[3321]:LOG:  autovacuum launcher started
      2016-11-13 05:28:09 UTC::@:[3318]:LOG:  checkpoint starting: immediate force wait flush-all
      2016-11-13 05:28:09 UTC::@:[3318]:LOG:  checkpoint complete: wrote 21 buffers (0.1%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.008 s, total=0.031 s; sync files=19, longest=0.008 s, average=0.000 s; distance=17 kB, estimate=17 kB
      2016-11-13 05:28:10 UTC::@:[3318]:LOG:  checkpoint starting: immediate force wait
      2016-11-13 05:28:10 UTC::@:[3318]:LOG:  checkpoint complete: wrote 0 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.000 s, total=0.084 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=15 kB
      2016-11-13 05:29:47 UTC::@:[3318]:LOG:  checkpoint starting: force wait
      2016-11-13 05:29:51 UTC::@:[3318]:LOG:  checkpoint complete: wrote 38 buffers (0.1%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=3.736 s, sync=0.058 s, total=4.092 s; sync files=33, longest=0.058 s, average=0.001 s; distance=5516 kB, estimate=5516 kB
      2016-11-13 05:34:47 UTC::@:[3318]:LOG:  checkpoint starting: time
      2016-11-13 05:34:47 UTC::@:[3318]:LOG:  checkpoint complete: wrote 1 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.003 s, total=0.017 s; sync files=1, longest=0.003 s, average=0.003 s; distance=16384 kB, estimate=16384 kB
      2016-11-13 05:39:47 UTC::@:[3318]:LOG:  checkpoint starting: time
      2016-11-13 05:39:47 UTC::@:[3318]:LOG:  checkpoint complete: wrote 1 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.002 s, total=0.016 s; sync files=1, longest=0.002 s, average=0.002 s; distance=16384 kB, estimate=16384 kB
```


完了
====