CloudFormationでElasticache for redis(クラスターモード有効)を構築してみた

# 概要
ElastiCacheのエンジンは `Memcache` or `Redis`の２つがあります。 
Redisを選択する場合はクラスタモードを有効にするか無効にするかも選択する必要があります。
*※クラスターモードの有効/無効に関するメリット・デメリットは[こちら](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/red-ug/Replication.Redis-RedisCluster.html)*

CloudFormationにてElastiCacheを構築する際にMemcache/Redis（クラスターモード有効）/Redis(クラスター無効)の3パターンそれぞれで利用できる設定箇所が異なる点や専用用語もあり非常に混乱しやすい印象を受けました。

本記事ではRedisでクラスターモードを有効にしたElastiCache構築のCloudFormationコードを紹介すると共に、詰まった点や解決方法がわからず断念した点をご紹介します。

# サンプルコード
サンプルコードは以下の条件に従って記載しています。

- ElastiCache(Redis クラスターモード有効)を構築する部分のみ抜粋
    - SubnetやSecurityGroupも別途定義が必要
- クラスターの構成は以下の通り
    - 利用するノードタイプは `cache.m6g.large`
    - 利用するredisのバージョンは6系
    - ノードグループは4つであり、１つのノードグループに付き3台構成
        - Primaryが1台、Replicaが２台
    - 耐障害性を考慮して各NodeGruoupにてAZを分散する

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'ElastiCache for Redis(Cluster mode on)'
Parameters:
  ElastiCacheMaintenanceWindow:
    Type: String
    Default: Mon:18:00-Mon:19:00 # JST TUE 3:00-4:00
    Description: Maintenance window for ElastiCache

Resources:
  ElastiCacheRedisClusterEnalbe:
    Type: AWS::ElastiCache::ReplicationGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    UpdatePolicy:
      UseOnlineResharding: true
    Properties:
      AtRestEncryptionEnabled: false
      AutomaticFailoverEnabled: true
      MultiAZEnabled: true
      CacheNodeType: cache.m6g.large
      CacheParameterGroupName: default.redis6.x.cluster.on
      Engine: redis
      EngineVersion: 6.x
      NumNodeGroups: 4
      ReplicasPerNodeGroup: 2
      NodeGroupConfiguration:
        - PrimaryAvailabilityZone: ap-northeast-1a
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
          NodeGroupId: "0001"
        - PrimaryAvailabilityZone: ap-northeast-1c
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
          NodeGroupId: "0002"
        - PrimaryAvailabilityZone: ap-northeast-1a
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
          NodeGroupId: "0003"
        - PrimaryAvailabilityZone: ap-northeast-1c
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
          NodeGroupId: "0004"
      Port: 6379
      ReplicationGroupDescription: 'ElastiCache Redis Cluster (Enable Cluster mode)'
      ReplicationGroupId: elasticache-redis
      PreferredMaintenanceWindow: !Ref ElastiCacheMaintenanceWindow
```

# 詰まった点
構築する際に詰まった点として大きく２点あります。
それぞれご紹介します。

## 3AZに分散できない
今回利用するノードタイプはメモリ量も多く費用とスペックのバランスが良い `cache.m6g.large` を利用しました。
AWSのセミナー等でもオススメされるノードタイプだと思います。
ですが、m6g系のノードタイプは東京リージョンのAZである `ap-northeast-1d` に対応しておらず、 `ap-northeast-1a` と `ap-northeast-1ｃ` のみで分散する事になりました。

## NodeGroupId指定
今回の構成では耐障害性を考慮して４つあるノードグループを以下の通りに設計しました。

- 各ノードグループのPrimaryノードはAZを分散させる
    - 2つのノードグループはPrimaryを `ap-northeast-1a`
    - 2つのノードグループはPrimaryを `ap-northeast-1c`
- 各ノードグループ内のReplicaもAZを分散させる
    - 各ノードグループのReplicaは `ap-northeast-1a` に１つ、 `ap-northeast-1c` に１つとする

これらの要件を明示的に指定するためには `NodeGroupConfiguration` を利用する必要がありました。
その際にマニュアルでは `NodeGroupId` は必須の記載が無いのですが、明示的に指定しないとエラーになりました。

# 断念した点
ElastiCacheを構築する際に dev/stg/prd 環境にてノードグループの台数を変数にて調整したいと考えてCloudFormationのコードを作成に取り組みました。
初期の想定では `NumNodeGroups` にて指定する値を変数化して環境毎に数値指定する事で各環境のElastiCacheクラスターのノードグループ数を指定できると思っていました。
しかしながら、先の耐障害性を考慮して各ノードグループの構成を明示的に決めるために `NodeGroupConfiguration` を利用したところ、`NumNodeGroups`にて指定した数に応じた `NodeGroupConfiguration` の設定が必要になったので変数だけで各環境の台数を定義するのが難しくなりました。

[条件関数](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html)使う等で記載する方法を検討しましたが、コードの複雑さが増してメンテナンス性が下がる事を懸念して断念しました。

現在はdev/stg/prd環境のクラスターをそれぞれ別のリソースとして定義しています。

#最後に
ElastiCacheは構成のパターンも多く、公式マニュアルだけではCloudFormationのyaml作成が難しい印象を受けました。
ノードグループの制限等もあり戸惑う部分も多かったのですが、構築できて安心しています。

今回断念した部分も解決策を調査しています。
もしご存知の方が居ましたら是非とも情報交換させてください。