aws上に作成したansibleサーバーでテストサイトを構築する(7) RDSの構成-2

# はじめに
[前回](https://qiita.com/yoshino_dd/items/8d559b60d5b9f316d8bb)は、RDSインスタンス作成のために必要となるサブネットグループなどのリソースを作成しました。
今回はRDSインスタンス本体の作成に入ります。

- aws上に作成したansibleサーバーでテストサイトを構築する
  1. [Ansibleサーバー構築](https://qiita.com/yoshino_dd/items/1e0969fd6dab1b51e1e0)
  1. [AWSネットワーク構成](https://qiita.com/yoshino_dd/items/d9be528837803ebb4bd3)
  1. [EC2インスタンスの作成](https://qiita.com/yoshino_dd/items/4368e468c6aa5353bf3c)
  1. [サーバー共通の設定](https://qiita.com/yoshino_dd/items/3fa56fc09e9162d6ad4a)
  1. [Webサーバーの構成](https://qiita.com/yoshino_dd/items/1292d6b3beeae26433f7)
  1. [RDSの構成-1](https://qiita.com/yoshino_dd/items/8d559b60d5b9f316d8bb)
  1. [RDSの構成-2](https://qiita.com/yoshino_dd/items/1da42dc2d1446ec20526)
  1. [WordPressの設定](https://qiita.com/yoshino_dd/items/d41694d468c5c64d78a0)
  1. 参考にしたサイトなど

# インスタンス情報の定義
まずは、作成したいRDSインスタンスの情報を`group_vars`で定義します。
前回作成した変数rdsに追加する形でまとめていきます。

DB名と、DBユーザー、パスワードは、WordPressに接続情報を設定するために使用するので、そちらで定義してインスタンス情報からはそれを参照するようにします。

```yaml:group_vars/all.yml(部分)
wordpress:
  root: /var/lib
  alias: wordpress
  user: '{{ php_fpm.user }}'
  group: '{{ php_fpm.group }}'
  dbname: wordpress
  dbuser: wordpress
  dbpass: fzlp8tzjkqcadUl=wqnmgrdnLehlcrh7

rds:
  subnet_group:
  - name: database
    description: 'private subnet group for database'
    subnets:
    - database1
    - database2
    instance:
    - name: '{{ wordpress.dbname }}'
      db_engine: MariaDB
      engine_version: 10.1.23
      multi_zone: no
      publicly_accessible: no
      zone: a
      size: 5
      instance_type: db.t2.micro
      storage_type: gp2
      subnet_group: database
      security_group:
        - SG_database
      username: '{{ wordpress.dbuser }}'
      password: '{{ wordpress.dbpass }}'
      tags:
        - key: Role
          value: wordpress
```

# RDSインスタンスの存在確認
冪当性確保のため、インスタンス作成の前に作成しようとしているインスタンスが存在しないことを確認します。
これには`aws`コマンドをshellモジュールで実行することにします。

rdsモジュールにもインスタンスの情報を取得する`facts`コマンドがあるのですが、1つずつインスタンス名を指定するループにしなければならないのと、インスタンスが存在しないとFailedになってしまい扱いが面倒なので、インスタンス名を指定しなくても存在するインスタンス名の一覧を取得できる`aws`コマンドを使用することにしました。

```yaml:roles/aws_rds/tasks/main.yml(追加)
- name: check rds instance
  shell: aws rds describe-db-instances \
    --query 'DBInstances[].DBInstanceIdentifier'
  environment:
    AWS_DEFAULT_REGION: "{{ vpc.region }}"
  failed_when: no
  changed_when: no
  register: rds_instance_chk

- debug: var=rds_instance_chk
```

出力はJSON形式なので、タスク内で扱いやすいように変換しておきます。

```yaml:roles/aws_rds/tasks/main.yml(追加)
- name: make rds instances list
  set_fact:
    rds_list: "{{ rds_instance_chk.stdout | from_json }}"

- debug: var=rds_list
```

# RDSインスタンス作成
メインであるRDSインスタンス作成のタスクは以下のようになります。
`group_vars`で定義した`rds.instance`を`with_items`でループし、該当するインスタンスの名前が上のタスクで作成したrds_listに含まれていない場合にインスタンスの作成を実行します。

ここでも`aws`コマンドを使用していますが、これはrdsモジュールでインスタンスを作成すると、storage-typeを指定できず、マグネティックになってしまうためです。
なお、後続で`rds`モジュールを使用した設定変更を行う構成とするので、ここではインスタンス作成に最低限必要なオプション(およびrdsモジュールで設定できないオプション)を指定しています。

```yaml:roles/aws_rds/tasks/main.yml(追加)
- name: RDS instance 作成
  shell: >-
    aws rds create-db-instance \
      --db-name {{ item.name }} \
      --db-instance-identifier {{ item.name }} \
      --db-instance-class {{ item.instance_type }} \
      --allocated-storage {{ item.size }} \
      --engine {{ item.db_engine }} \
      --master-username {{ item.username }} \
      --master-user-password {{ item.password }} \
      --availability-zone {{ vpc.region }}{{ item.zone }} \
      --db-subnet-group-name {{ item.subnet_group }} \
      --engine-version {{ item.engine_version }} \
      --storage-type {{ item.storage_type }} \
      --copy-tags-to-snapshot \
      {% if item.publicly_accessible == True %}
        --publicly_accessible \
      {% else %}
        --no-publicly-accessible \
      {% endif %}
      --tags \
      {% set tag_list = [] %}
      {%- for i in range(item.tags|length) -%}
      {%-   set _ = tag_list.append("Key="+item.tags[i]['key']+",Value="+item.tags[i]['value']) -%}
      {%- endfor -%}
      {{ tag_list | join( ' ' ) }}
  environment:
    AWS_DEFAULT_REGION: "{{ vpc.region }}"
  when: item.name not in rds_list
  with_items: "{{ rds.instance }}"
  register: create_rds_instance
```

# インスタンス作成完了まで待機
この後は`rds`モジュールによる設定変更を行いますが、インスタンスの作成に時間がかかる(ここでの構成で試した限りでは大体5分強)ため、操作ができるようになるまで待機する必要があるのでそのためのタスクを追加します。

インスタンス作成前の存在チェックと同様に`aws`コマンドを使用して、作成したインスタンスの`status`が`available`になるまで、`until`で待機しています。
ここでは10秒ごとに確認して10分待っています。

```yaml:roles/aws_rds/tasks/main.yml(追加)
- name: check rds instance
  shell: >-
    aws rds describe-db-instances \
      --db-instance-identifier {{ item.name }} \
      --query 'DBInstances[].DBInstanceStatus'
  environment:
    AWS_DEFAULT_REGION: "{{ vpc.region }}"
  register: rds_instance_chk
  changed_when: no
  until: rds_instance_chk.stdout.find("available") != -1
  retries: 60
  delay: 10
  with_items: "{{ rds.instance }}"

- debug: var=rds_instance_chk
```

# インスタンス構成の変更
インスタンスが使用可能になったら`rds`モジュールでの構成変更を行います。

```yaml:roles/aws_rds/tasks/main.yml(追加)
- name: rds instance modified
  rds:
    command: modify
    region: "{{ vpc.region }}"
    instance_name: "{{ item.name }}"
    apply_immediately: yes
    backup_retention: "{{ item.backup_retention | default(omit) }}"
    backup_window: "{{ item.backup_window | default(omit) }}"
    instance_type: "{{ item.instance_type | default(omit) }}"
    maint_window: "{{ item.maint_window | default(omit) }}"
    multi_zone: "{{ item.multi_zone | default('no') }}"
    publicly_accessible: "{{ item.publicly_accessible | default('no') }}"
    parameter_group: "{{ item.parameter_group | default(omit) }}"
    vpc_security_groups: >-
      {%- set sg_list = [] -%}
      {%- for i in range(item.security_group | length) -%}
      {%-   set _ = sg_list.append(sg_dict[item.security_group[i]]) -%}
      {%- endfor -%}
      {{ sg_list | join( ',' ) }}
    size: "{{ item.size }}"
    wait: yes
  with_items: "{{ rds.instance }}"
```

# 次回
前回、今回で、RDSインスタンス作成が完了しました。
次回は、作成したRDSインスタンスへの接続など、WordPressの設定を行っていきます。

- [aws上に作成したansibleサーバーでテストサイトを構築する(8) WordPressの設定](https://qiita.com/yoshino_dd/items/d41694d468c5c64d78a0)

---
---