redashをECS Fargateに乗せて安定化を図りPythonで分析する環境を整えた話


# はじめに

以前、[社内のRedashをEC2からECSに移行してv5からv8にした話](https://qiita.com/t_odash/items/8d28afd2ffd1e5929b99)という記事を投稿しました。redashの古いバージョンを最新まで上げつつ、EC2からECS Fargateに載せ替えたという内容です。

当時の記事ではバージョンアップ方法や環境移行方法に焦点を当てていた為、今回はECS Fargateでredashを利用する方法、メリットについてまとめたいと思います。また、当社ではこの環境でPythonを用いており、記事の後半ではPython利用時の方法、ライブラリの扱いについても記載します。

# 1. 当社の環境

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/1a3e6668-bf70-1b8d-83d6-286343e07c90.png)

上図は当社のredash環境を簡単に表した図です。redashはFargateでホスティングしており、redash_serivceの中でredash_worker、redash_serverコンテナが稼働しています。redashのダッシュボードやクエリ等のメタデータを管理するPostgreSQLはRDS、キューイングを管理するRedisはElastiCacheと、それぞれマネージドサービスに逃しています。図では割愛していますが、別で設定したALBのターゲットグループにコンテナを指定して利用しています。

## 1.1 この環境のメリット
移行前はredash本体、Redis、PostgreSQLを全て同一のEC2インスタンスでホスティングしていました。加えてredashで参照する分析用DBのホスティングや同DBへのマスキング処理も同じインスタンスで行っていました。お察しの通り、たびたびリソースが逼迫してredashが機能しなくなっていました。

Fargate環境にしてからはそういった事は起きていません。redash_serviceを登録する際の必要タスク数を1としており、仮にコンテナが落ちても必要なタスク数に応じて起動し直してくれます。その際メタデータやキューイングデータはそれぞれマネージドサービスに逃しているので運用上問題はありません。いつredashが落ちるか分からない、落ちたら手動でどうにかしなければならない、といった悩みの種を駆逐できる恩恵は非常に大きなものだと言えます。

# 2. 環境の詳細
## 2.1 利用サービスの一覧

- Secrets Manager
- ALB
- RDS
- ElastiCache
- ECS

ECSで用いるredashコンテナは公式のイメージを利用し、バージョンは[現行](https://github.com/getredash/redash/releases/tag/v8.0.0)(2021年6月現在)の最新(redash/redash:8.0.0.b32245)です。

## 2.2 設定や注意点

### 2.2.1 Secrets Manager
RDSやElastCacheの認証情報をSecrets Managerに保存しておき、ECSのタスク定義時に呼び出すことが可能です。変数入力欄に認証情報を直接記述しないで済みます。詳細は[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/specifying-sensitive-data-secrets.html#secrets-create-taskdefinition)をご覧下さい。

### 2.2.2 ALB
利用する場合は事前に設定する必要がありますが、Route53を用いて任意のレコード名とredashを紐付けできたり、あれば何かと便利です。基本的には環境に応じて作成すれば問題ありませんが、手順4のルーティング設定ではターゲットの種類をIPで設定しましょう。ヘルスチェックは`/ping`で通ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/68035778-ff09-d292-b010-f3ef70b6dfde.png)

当然ですが、VPC・サブネット・セキュリティグループ等の周辺も事前に設計、設定しておく必要があります。

### 2.2.3 RDS
redashのメタデータを保存するDBとしてPostgreSQLインスタンスを作成する必要があります。環境にも依存するかとは思いますが、そこまで大きなインスタンスタイプにする必要はなさそうな印象です。スモールスタートして、リソースが足りなさそうであれば少しずつインスタンスタイプを変更していく運用で良いかと思います。IDやPWはECSタスク定義時に利用するので、控えておくかSecrets Managerに保存しましょう。


参考までに、当社のredashは以下の様な利用状況ですが、PostgreSQLインスタンスはdb.t3.mediumタイプで安定稼働しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/34b6e406-3f5e-f432-6dfb-81a8a3479531.png)

### 2.2.4 ElastiCache
Redisでクラスターを作成します。スモールスタートする場合は、まずは1台構成からでも良いかもしれません。デフォルトだと大きめのノードタイプが選択されているので注意が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/3074f588-0270-02a9-9a64-3b3b4eea014f.png)

### 2.2.5 ECS

#### クラスター作成
利用するクラスターを作成します。Fargateを利用する場合はネットワーキングのみで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/8f317f2a-1ab0-d115-6d77-4c5f2024a394.png)

#### タスク定義
当社ではECSでredashを利用する場合のタスク定義を2種類用意しています。初回構築時のみ利用する、Redis及びPostgreSQLの利用準備を行う`create_db`タスクとredash本体を稼働させる`redash`タスクです。

##### create_dbタスク
create_dbタスクは[redashのCLI](https://github.com/getredash/redash/blob/master/bin/docker-entrypoint#L38)で`/app/manage.py database create_tables`コマンドを発行するタスクです。コマンドの内容は[ここ](https://github.com/getredash/redash/blob/d8d7c78992e44a4b6d7fdd4c39ccc1c35cd8c7a9/redash/cli/database.py#L45)に記載されており、[この辺り](https://github.com/getredash/redash/tree/1c3f724f3ef97559a5d5f443093bb9516dd6fc8b/redash/models)に記述されているテーブルを作成するものと思われます。このコマンドはredashのdocker-composeなどでも呼び出されているものです。

タスク定義の詳細は次の通りです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/35fc3832-a29d-9250-dd19-b83ed13a982f.png)

タスクメモリを0.5GiBに設定したところコンテナが落ちてしまったので3GiBとしています。
コンテナ定義は次の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/2a867d2c-ef87-38b7-90f6-81e7a75cbdfe.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/3c8c0775-355a-2256-9e68-2e22754a92f4.png)

環境の欄に`create_db`を記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/7779858a-c1fd-bd6a-17ac-0581097d8832.png)

環境変数の欄に`REDASH_DATABASE_URL`(PostgreSQLの認証情報)、`REDASH_REDIS_URL`(Redisの認証情報)を記入します。記法は以下の通りですが、Secrets Managerを利用する場合はそちらの値を記入します。記入を終えたら完成です。

 - `postgresql://user:password@hostname:port/redash`
 - `redis://hostname:port/0`

タスク定義が完成したら、クラスターの`新しいタスクの実行`から実行しましょう。このタスクは初回構築時にのみ必要となるので、サービスとして実行する必要はありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/823b28a3-3eb4-5d09-d9fb-7014ca2599ba.png)

##### redashタスク
こちらはECSクラスターのサービスとして起動することになる、redash本体のタスクです。当社ではserverとworkerの2つのコンテナを立ち上げています。定義は次の通りです。


 - serverコンテナ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/e8dd92ef-f4c3-5168-781e-bcc3f2eeb32f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/b3750134-2a45-95d0-22f5-d6006507dec7.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/5ba9a40f-bcb3-b1f7-8d37-bd84bf081e4f.png)


コマンド欄にserverと記入。各種変数は環境に合わせて読み替えてください。

 - workerコンテナ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/0a44512c-0ca6-0b08-70dd-276125afcc8f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/e21b9d05-9941-2c66-c3fc-0f2d95856601.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/cfb5bd26-b471-3fdc-f98d-84fb6638a893.png)

コマンド欄にscheduler,workerと記入。各種変数は環境に合わせて読み替えてください。

こちらのタスクはサービスとして登録したいので、サービスの作成を押下して設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/dccfe1d2-7c7f-387b-545c-e984ad9f255a.png)

サービスの設定時、パブリックIP割り当ての項目があります。ALB経由の設定を行う場合は必要はありませんが、redashが起動しているのか確認する等のデバッグ用であれば割り当てても良いかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/b64c0413-8c8e-b362-af2a-04b2b3e31afd.png)

# 3. redash on ECS環境でPythonを使う
redashでPythonを利用する為にはredash本体での設定とECSタスク定義での設定がそれぞれ必要です。ライブラリの導入も同じ手順で行います。

## 注意点
2021年6月現在、redash v8で利用できるのは既にサポートが終了したPython2系です。v9になるとPython3が利用できるようなので正式リリースが非常に楽しみです。

## 3.1 ECS側の設定
実施する設定は、redashでデータソースとしてPython自体を利用可能にするものと、Pythonで利用するライブラリをコンテナにインポートするものの2種類があります。

### 3.1.1 Pythonデータソースを利用可能にする
タスク定義にて、server、workerそれぞれのコンテナの環境変数欄に`REDASH_ADDITIONAL_QUERY_RUNNERS`を追加し、`redash.query_runner.python`を記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/43135907-4047-2886-7634-c65757876c3c.png)

作成後はリビジョンを新しいものにしてタスクを再起動すればredashでPythonが利用可能になります。

### 3.1.2 Pythonライブラリを導入する
分析を行う中で利用したいライブラリが出てくる場合もあるかと思いますが、その場合もタスク定義にて導入することになります。

タスク定義のworkerコンテナのコマンド欄にて、worker、schedulerに続いてインストールコマンドを記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/674c6a6b-de8c-eb02-7bca-0b5a6445d7c6.png)

記法は`bash -c 'pip install [ライブラリ名]==[バージョン]  --user'`です。複数導入する場合はカンマを挟んで続けて記入します。上記はstatsmodelsのv0.9.0とscipyのv0.14を導入する例です。作成後はリビジョンを新しいものにしてタスクを再起動すれば記述したライブラリがコンテナにインストールされます。

# 3.2 redash側の設定

データソース設定からPythonを作成し、利用予定のライブラリを`Modules to import prior to running the script`に記入します。`AdditionalModulesPaths`の欄には、インポート先である`/home/redash/.local/lib/python2.7/site-packages`を記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/8192dd86-3d37-2203-0ec1-9f97d2425a2d.png)


# まとめ

redash on ECS Fargate環境を構築する方法についてまとめました。この環境であればそこまでリソースに対して気を配る必要がなくなるため、運用上の負荷が軽減されます。後半ではpythonを利用する方法についてまとめました。redash上でPythonを利用できるようになると分析の幅が広がっていく為、非常に有用だと思います。反面、段々と増えていくダッシュボードやクエリの管理が煩雑になってしまう点については新たな課題となってしまいました。これに関しては良い解決策を発見次第、記事にまとめたいと考えています。