Redash検証環境をCentOS 7.6のDocker上に構築する(2019/09/16時点)

# 概要
Redashがどのようなソフトウェアか評価するためにAWS等の設定済みのインスタンスを起動する方法もあるが、お金がかかる場合もある。
UbuntuであればDocker環境を自動構築する[Setup Script](https://github.com/getredash/redash/tree/master/setup)が公開されているが、CentOSでは公式なものはない。

Node.js/Dockerなどには詳しくないが、業務上とにかくRedashを評価する必要があったので、試行錯誤して自宅にあるCentOS 7.6上のDocker上でRedashを動作させた。
CentOSに慣れていたのでCentOSを試したが、UbuntuでよいのであればSetup Scriptのほうがよいかもしれない。

CentOS/Redashに関してはいろいろな記事があったがすでに古くなっていていた。
とにかくこの手の記事はあっという間に古くなって役に立たなくなるので注意が必要。

困ったときはRedashのサイトを見るのが一番よい。
https://redash.io/help/open-source/dev-guide/docker

# 注意事項
なぜかSafari 12.1.2 (14607.3.9)でRedashにアクセスしようとすると画面が表示されなかった。
エラー画面になるわけではなく、ヘッダーくらいしか表示されない。

Node.jsのエラーログ

```
[HPM] Error occurred while trying to proxy request /login?next=/ from 192.168.1.200 to http://localhost:5000/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[HPM] Error occurred while trying to proxy request /api/session from 192.168.1.200 to http://localhost:5000/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[HPM] Error occurred while trying to proxy request /api/session from 192.168.1.200 to http://localhost:5000/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[HPM] Error occurred while trying to proxy request /login?next=/ from 192.168.1.200 to http://localhost:5000/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
[HPM] Error occurred while trying to proxy request /api/session from 192.168.1.200 to http://localhost:5000/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
```
Safariでだめな環境でもChrome 77.0.3865.75では正しくアクセスできることを確認している。
Safariでだめな事に気づかずインストール手順を疑って半日時間を無駄にしたことが悔やまれる。
8.0.0-beta (dev)固有の問題かもしれないが未調査。

# 前提
- あくまでもRedashを評価・検証するための方法
- それほど記事の有効寿命は長くないと思うが、コマンドをコピペすれば誰でも構築できるようにした(スクリプトにしてもよかったが、テストが面倒なのでやめた)
- この方法でインストールされるRedashのバージョンは8.0.0-beta (dev)
- 検証目的なのでコンテナのデータは永続化しない
- メール送信設定はしていないのでアラート機能は動作しない
- CentOSはVMWare Fusion上に構築(本質とはあまり関係ない)
- DockerをインストールするCentOS自体もいつでも破棄できるようになっていることが前提
- CentOS7はメモリを8GB確保している(4GB未満だとインストールに失敗する可能性あり)
- SELinuxは無効
- インストールされたパッケージのバージョン(あっというまに古くなるので参考程度にしかならない)
    - Redash 8.0.0-beta (dev)
    - CentOS 7.6
    - Docker 19.03.2
    - docker-compose 1.24.1
    - Node.js 10.16.3


# 前提条件確認
```bash
# 実施日時
$ date
2019年  9月 16日 月曜日 15:01:13 JST

# CentOSのバージョン
$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

# 最新のパッケージになっている状態での実施
$ sudo yum upgrade
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ty1.mirror.newmediaexpress.com
 * extras: ty1.mirror.newmediaexpress.com
 * updates: ty1.mirror.newmediaexpress.com
No packages marked for update

# アーキテクチャ確認
$ uname -a
Linux server200 3.10.0-957.27.2.el7.x86_64 #1 SMP Mon Jul 29 17:46:05 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

# SELinuxは無効
$ sestatus
SELinux status:                 disabled

# firewalldは有効
$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since 月 2019-09-16 11:17:18 JST; 2min 22s ago
     Docs: man:firewalld(1)
 Main PID: 708 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─708 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

# メモリは4GB以上ある
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           7.6G        168M        7.3G         11M        207M        7.2G
Swap:          2.0G          0B        2.0G

```

# Dockerのインストール
```bash
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ chmod +x get-docker.sh
$ ./get-docker.sh
$ sudo usermod -aG docker $USER

# （ここで一度ログアウト)

$ sudo systemctl enable docker
$ sudo systemctl start docker
$ docker version
Client: Docker Engine - Community
 Version:           19.03.2
 API version:       1.40
 Go version:        go1.12.8
 Git commit:        6a30dfc
 Built:             Thu Aug 29 05:28:55 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.2
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.8
  Git commit:       6a30dfc
  Built:            Thu Aug 29 05:27:34 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.6
  GitCommit:        894b81a4b802e4eb2a91d1ce216b8817763c29fb
 runc:
  Version:          1.0.0-rc8
  GitCommit:        425e105d5a03fabd737a126ad93d62a9eeede87f
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
```

# docker-composeのインストール
docker-composeは「複数のコンテナを使う Docker アプリケーションを、定義・実行するツール」。
RedashはPostgresやRedisなど様々なコンテナで構成されるため、このツールを利用している。

```bash
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.24.1, build 4667896b
```

# Node.jsのインストール
訳がわからないとも思うのだが、Dockerで提供されるのはAPIやDBなどのバックエンドの部分だけでWebGUIフロントエンドの部分はDockerの外で構築しなければならない。
このフロントエンドの部分はCentOSで提供するのでNode.jsをCentOSにインストールする必要がある。

```bash
$ sudo -s
# curl -sL https://rpm.nodesource.com/setup_10.x | bash -
# exit
$ sudo yum install -y nodejs
$ node --version
v10.16.3
```

# Gitのインストール
RedashのソースコードはGitHubから持ってくるので必要になる。

```bash
$ sudo yum install -y git
```

# Redashソースコードの取得
```bash
$ git clone https://github.com/getredash/redash.git
```

# Redashコンテナのセットアップ
```bash
# 以降のコマンドはredashディレクトリ配下で実行する必要がある
$ cd redash/

# docker-composeを実行してコンテナイメージを取得したり各種セットアップを行う(10分以上時間がかかる場合もあり)
$ docker-compose up -d

# Redash内部で使用するデータベースの作成
$ docker-compose run --rm server create_db

# Redashの内部機能テストで使用するデータベースの作成
$ docker-compose run --rm postgres psql -h postgres -U postgres -c "create database tests"

# 完了すると4つコンテナが立ち上がっているはず
$ docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES
ecaa61a9d5ca        redash_worker         "/app/bin/docker-ent…"   37 seconds ago      Up 36 seconds       5000/tcp                                         redash_worker_1
2a38df0782f0        redash_server         "/app/bin/docker-ent…"   37 seconds ago      Up 36 seconds       0.0.0.0:5000->5000/tcp, 0.0.0.0:5678->5678/tcp   redash_server_1
33203a65d11f        postgres:9.5-alpine   "docker-entrypoint.s…"   38 seconds ago      Up 37 seconds       0.0.0.0:15432->5432/tcp                          redash_postgres_1
3b191d489ede        redis:3-alpine        "docker-entrypoint.s…"   38 seconds ago      Up 37 seconds       6379/tcp                                         redash_redis_1          
```

`docker-compose up -d`はいろいろな通信を行うせいか時々失敗することがある。
一過性の問題で失敗したときは再実行すれば大丈夫。
また、`docker-compose up -d`は大量の警告を出すが、処理が止まらない限りは問題ないと割っている。

5000/tcpでRedashのWeb APIを公開している。次に構築するCentOS上のフロントWebサーバーはこのWeb APIを実行する。

# npmパッケージのインストールと構築
Node.jsに詳しくないのでよく分からないが、使用するパッケージをインストールして各種構築をする必要がある。

```bash
$ npm install
$ npm run build
```
`npm install`でセキュリティの警告がでたが、評価・検証目的なので無視。

```
added 2072 packages from 1095 contributors and audited 97146 packages in 44.854s
found 1771 vulnerabilities (16 moderate, 1754 high, 1 critical)
  run `npm audit fix` to fix them, or `npm audit` for details
```

# Redashの自動テスト
行っておいたほうが無難と思われる。
この自動テストに失敗するのであれば、なんらかの問題が発生していることになる。

```bash
$ docker-compose run --rm server tests
```

実行結果

```bash
Starting redash_postgres_1 ... done
Starting redash_redis_1    ... done
================================================================================================ test session starts ================================================================================================
platform linux2 -- Python 2.7.16, pytest-3.2.3, py-1.8.0, pluggy-0.4.0
rootdir: /app, inifile: pytest.ini
plugins: cov-2.5.1, celery-4.3.0
collected 645 items

tests/test_authentication.py ...................................
tests/test_cli.py ..............................
tests/test_configuration.py .........
tests/test_handlers.py ............................
tests/test_models.py ..................................................
tests/test_permissions.py ........
tests/test_utils.py .........
tests/extensions/test_extensions.py ......
tests/handlers/test_alerts.py ................
tests/handlers/test_authentication.py .............
tests/handlers/test_dashboards.py .................
tests/handlers/test_data_sources.py .................
tests/handlers/test_destinations.py .........
tests/handlers/test_embed.py ..........
tests/handlers/test_favorites.py ....
tests/handlers/test_groups.py ..........
tests/handlers/test_paginate.py ...
tests/handlers/test_permissions.py ................
tests/handlers/test_queries.py .................................
tests/handlers/test_query_results.py .............................
tests/handlers/test_query_snippets.py .....
tests/handlers/test_settings.py ...
tests/handlers/test_users.py ..............................................
tests/handlers/test_visualizations.py .......
tests/handlers/test_widgets.py ....
tests/models/test_alerts.py .....
tests/models/test_api_keys.py ..
tests/models/test_changes.py .....
tests/models/test_dashboards.py .
tests/models/test_data_sources.py .............
tests/models/test_parameterized_query.py ..................................
tests/models/test_permissions.py ......
tests/models/test_queries.py ..........................
tests/models/test_query_results.py ........
tests/models/test_users.py ...........
tests/query_runner/test_athena.py ....
tests/query_runner/test_drill.py .......
tests/query_runner/test_google_spreadsheets.py ...............
tests/query_runner/test_http.py ...........
tests/query_runner/test_jql.py .....
tests/query_runner/test_mongodb.py ........
tests/query_runner/test_prometheus.py ..
tests/query_runner/test_query_results.py .......................
tests/query_runner/test_script.py ....
tests/query_runner/test_utils.py ......
tests/serializers/test_query_results.py .....
tests/tasks/test_alerts.py ...
tests/tasks/test_empty_schedule.py .
tests/tasks/test_failure_report.py .........
tests/tasks/test_queries.py .......
tests/tasks/test_refresh_queries.py .....
tests/tasks/test_refresh_schemas.py ..

========================================================================================= 645 passed in 1220.21 seconds ==========================================================================================
```

# フロントのWebサーバーの起動
CentOS上でwebpack-dev-serverというものを起動する必要がある。

```bash
$ nohup npm run start &>/tmp/node.out &
```
もっとマシな起動方法があるかもしれない。
ログは/tmp/node.outに出力される。

CentOS上では　`http://localhost:8080` でRedashにアクセスできるようになる。
GNOMEが入っているのであればCentOS上で動作検証できるようになる。



もしGNOMEが入っていないのであれば、ホストOSからアクセスするためにSSHポートフォワーディングを行うかリバースプロキシを立てることを検討する。

SSHポートフォワーディングの例
例えば以下のコマンドをホストOSで実行したあとでホストOS上で `http://localhost:9999` をブラウザで開く。

```bash:ホストOS上からのSSH例
# 9999はホストOSでのLISTENポート
# 192.168.1.200は接続先ホスト(CentOS)
# localhost:8080は接続先ホスト(CentOS)から見たときの転送先(つまりCentOS上のループバックアドレスの8080/tcp)
$ ssh -L 9999:localhost:8080 192.168.1.200
```

# CentOSの外からアクセスできるようにする
上記の手順で立ち上げてもWebサーバー自体はCentOS上のlocalhostでしかLISTENしていないので、ホストOSからアクセスできない。
webpack-dev-serverのLISTENアドレスを変える方法がよくわからなかったので、nginxをインストールしてリーバスプロキシ経由でRedashにアクセスできるようにする。

## nginxのインストールおよびfirewalldの設定

```bash
$ sudo yum install -y epel-release
$ sudo yum install -y nginx
$ sudo vi /etc/nginx/nginx.conf
$ sudo systemctl enable nginx
$ sudo firewall-cmd --add-service=http --permanent
$ sudo firewall-cmd --reload
$ sudo systemctl start nginx
```

```conf:/etc/nginx/nginx.confの修正部分(serverブロック内を修正)
        proxy_buffers 8 32K;
        proxy_buffer_size 32k;
        proxy_busy_buffers_size 64k;
        location / {
            proxy_pass http://localhost:8080;
        }
```
proxy_buffersを増やさないとnginx側でエラーになるので設定が必要。

# 完成
ここまで来るとCentOSのVMのIPアドレスからRedashにアクセスできる。

CentOSのVMのIPアドレスが192.168.1.200だとすると
ホストOSから`http://192.168.1.200` でアクセスできる

<img width="898" alt="スクリーンショット 2019-09-16 19.10.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497821/ac0e2dfc-6592-5761-0dfe-0b4a8bc90031.png">

# 補足情報

```bash

# Redashの停止
$ docker-compose stop

# Redashの起動
$ docker-compose start
```

各種コマンドはredashディレクトリに入る必要がある。
docker-composeでdownを実行するとコンテナが削除されるので注意。


# 総評
各種環境をAWS等で行っているのであれば、そもそもこのようなことをする必要すらないだろうから、
今回の調査はあまり効率的ではなかったかもしれない。