プロダクションReadyなRedashを5分で立ち上げるためのCfn template

テックタッチアドベントカレンダーも無事8日目になりました。残り2/3ですね。

昨日は@analogrecordによる「goのhot-reload」でした。
テックタッチの開発環境は彼がrealizeを導入してくれたおかげで、docker-compose一発で快適な環境が立ち上がり、生産性が大幅アップしました。

本日はタイトルの通り、社内でのデータ民主化に欠かせないRedashを、本番運用まで見据えて立ち上げる方法の紹介です。

# What is Redash?

[https://redash.io/](https://redash.io/)

Redashは多様な[データソース](https://redash.io/integrations/)に統合的にクエリを発行し、結果を可視化するためのOSSです。2019年現在においては、開発やユーザーサポートも活発に続けている印象です。Python製。

Metabaseなどいくつか類似のOSSがありますが、対応しているデータソースの数が豊富な点、UIがシンプルで使いやすい点が気に入っています。

# 動機

[Redashのフォーラム](https://discuss.redash.io/t/redash-on-aws-ecs/1124/3)でもスレッドがありますが、ECSでRedashを動かす方法が確立されていなさそうだったので、運用実績のあるCfnテンプレートを少し手直しして公開することにしました。

対応バージョンは現時点で最新のver.8です。

ちなみに、Redash applicationやDBを1つのサーバーに詰め込んで運用するのが問題なければ、[このレポジトリ](https://github.com/getredash/setup/tree/master)が手っ取り早いと思います。

なお、本体とは別に、Slackにクエリの結果を展開してくれる[便利なBot](https://github.com/yamitzky/redashbot)もあるので、そちらも合わせて立ち上がるような設定にしてあります。

<img width="536" alt="Slack | notify-redash | rentio 2019-12-08 21-43-23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5201/fb48d535-8237-0245-fc8b-a4fac77fa129.png">


（SlackにredashのクエリやダッシュボードのURLをPostするリマインダーを設定しておくと、Slackチャンネルへのポストが手間なく実現できます。）

# 成果物と手順

このレポジトリにCloudformation templateと手順があります。

[https://github.com/ikazoy/redash-on-ecs](https://github.com/ikazoy/redash-on-ecs)

READMEも丁寧めに書いたので見てください。

以上。

だと面白くないので、少しだけ構成などを解説します。

# Architecture

**共通インフラ部分、アプリケーション部分**

AWS公式の[コンテナ型マイクロサービスのリファレンスアーキテクチャ](https://github.com/aws-samples/ecs-refarch-cloudformation)をforkしました

+

**データストア部分**

下記の画像以外に、Redashに必要なRDS + ElastiCacheを自前で定義しています。

![https://github.com/aws-samples/ecs-refarch-cloudformation/raw/master/images/architecture-overview.png](https://github.com/aws-samples/ecs-refarch-cloudformation/raw/master/images/architecture-overview.png)

アーキテクチャのポイント

- ECSにしたのは、[ecs-cli](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI.html)を使って、Redash officialの[docker-compose.yml](https://github.com/getredash/setup/blob/master/data/docker-compose.yml)を利用したかったから
- 手間をかけずに＆堅牢に運用したいので、RDSやElastiCacheを使うことを選択
- RDSのバックアップを利用して、有事に備える
- Auto scaling groupやECSのService設定があるので、EC2インスタンスやコンテナが落ちても自動復旧してくれる（はず）
- ECSの設定を変更すれば冗長性を確保できる

# その他Tipsなど

## ecs-cli

上述の通り、Redashレポジトリのdocker-compose.ymlをなるべく流用する形でecs上にServiceを立ち上げようと思いました。

ECSにdocker-compose.yml形式でTaskDefinitionを作成する際は、[ecs-cli](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_CLI.html)を使っています。

本家Redashのdocker-compose.ymlを流用しつつ、mem_reservation, mem_limit, logging(CloudWatchへの出力）、Redashに必要な環境変数の定義を調整しました。

```yaml
version: "2"
x-redash-service: &redash-service
  image: redash/redash:8.0.0.b32245
services:
  server:
    <<: *redash-service
    command: "server"
    mem_reservation: 314572800
    mem_limit: 3221223822
    ports:
      - "0:5000"
    environment:
      REDASH_WEB_WORKERS: 4
    env_file: .env
    logging:
      driver: awslogs
      options:
        awslogs-region: $AWS_REGION
        awslogs-group: $AWS_LOG_GROUP
        awslogs-stream-prefix: redash-server
```

## ecs-paramsオプション + SSMの活用

また、ECSのTaskDefinitionに対してconfidentialな環境変数を設定する際は、ecs-cliでecs-paramsオプションを指定することで、SSMに格納したパラメーターを参照できるようにしました。

RedisのエンドポイントをSSMに格納しつつ、ecsのタスク定義からアクセスする実際の設定はこんな感じ↓

services/redash-app.yaml

```yaml
Resources:
  RedisCacheCluster:
    Type: AWS::ElastiCache::CacheCluster
    Properties:
      Engine: redis
      EngineVersion: 5.0.3
    # 以下略
  RedisEndpoint:
      Type: "AWS::SSM::Parameter"
      Properties:
        Name: !Sub /${EnvironmentName}/RedashRedisEndpoint
        Type: "String"
        Value: !Sub "redis://${RedisCacheCluster.RedisEndpoint.Address}:${RedisCacheCluster.RedisEndpoint.Port}/0"
```

ecs-params-redash-app.yml

```yaml
    version: 1
    task_definition:
      task_execution_role: ecsTaskExecutionRoleWithSsmRead-YOUR_STACK_NAME
      services:
        server:
          secrets:
            - value_from: /redash-production/RedashRedisEndpoint
              name: REDASH_REDIS_URL
```

これでデータベースへの接続情報など、機密情報を安全に管理できますね。

参考 [ECSでごっつ簡単に機密情報を環境変数に展開できるようになりました！ | Developers.IO](https://dev.classmethod.jp/cloud/aws/ecs-secrets/)

## メール配信にSESを使う

ここはCfn templateにはしていないのですが、Redashからのメール配信にはAWS SESを使っています。

## あえてFargateは使わなかった

- ECS on EC2とECS on Fargateを比較したときの稼働時間あたりの金銭的コスト
- デバッグのしやすさ

を考慮してEC2で運用する選択をしました。

## デバッグは少し面倒

上記リポジトリのREADMEにもありますが、構築作業中はEC2インスタンスに接続して、起動に失敗したdockerコンテナのログを見て原因を探り、設定を変更するという作業が必要でした。

その際、on Fargateだとインスタンスという概念がないので、on EC2のほうが作業をしやすいです。

また、EC2インスタンスをPrivateなSubnetで起動していると踏み台サーバーが必要になるので、一時的にPublicなSubnetで起動した上でsshするとデバッグしやすかったです。

## バージョンアップの方法

Redashはこれまでおよそ半年に1回程度の頻度で新しいバージョンがリリースされています。

[公式のバージョンアップガイド](https://redash.io/help/open-source/admin-guide/how-to-upgrade)にある通り、バージョンアップの作業時はデータベースのバックアップを取っておくのが安全です。

今回ご紹介したCfn templateを使えば、RDSを含んだStackがまるっと一式立ち上がりますので、実際のバージョンアップ時には以下のような方法で気軽に新バージョンを試しつつ、アップデートすることができます。

ドメイン名はCfn stackのパラメーターとして変更可能になっています。

1. 稼働中の旧バージョンのCfn stackと並行して、別ドメインで新バージョンのCfn stackを立ち上げる
2. 旧バージョンのPostgresをdumpし、新バージョンにrestoreする
3. （必要であれば）`docker-compose run --rm server manage db upgrade`を実行
4. 新バージョンの動作確認。問題なければ旧バージョンと新バージョンのドメインを切り替える。

以上、参考になれば幸いです。

明日は@smith-30 による「Nature Remo mini を使って快適生活」です。
私はsRemo（初代）とGoogle homeを使って、もっぱらテレビを点けたり消したりしています。