dockerで稼働するredashのトラブルと対策

#概要
redashは複数のコンテナによって構成されている。
ざっくり役割は以下の通り。

## redash_worker_1
データの結果取得に時間がかかる場合が多いので、
実際のクエリーを実行する処理はこのコンテナが行う。
celeryというPythonのjob queue処理を行うためのフレームワークが使われている。

以下の2種類存在している
### adhoc workers
アドホックに実行したクエリーを処理する

### scheduled queries workers
スケジュールされた通りにクエリーを実行する

切り替えはcelery worker起動時に-Qオプションで制御される。
1つのworkerで両方の機能を担うことも、 別々のworkerに分けることも可能。

## redash_nginx_1
webサーバ リバースプロキシとして稼働

## redash_server_1
Pythonで実装されたWeb console画面。
基本的にこの画面を利用して ユーザはクエリーの発行やデータの可視化を行う。
Application Serverとしてgunicornが使われている。

## redash_redis_1
celeryではクエリーを貯めておく場所としてredisを利用することができる。
このredis内にserverからjobがqueueに登録され、 workerが引き出して実行を行う。

## redash_postgres_1
ユーザ情報や作成したQuery/Dashboardの情報が格納される。

#トラブルシューティング
## コンテナのリソース状況を確認したい
redashというか、dockerでの管理の話しになるが、
ctopというコマンドを使うと、管理しやすい

https://qiita.com/S-T/items/d5a43076a51f5814ee32
![image-20180322014156917.png](https://qiita-image-store.s3.amazonaws.com/0/75761/39f463ba-6777-7281-396f-b7d4267765d6.png)

## クエリが返って来ない
test connectionはOKでもクエリーを発行すると戻って来ない時がある。
コンテナの一つ一つ見ていくと、workerで処理が来ていないことがわかった。

スケジュールに登録されているクエリが多すぎるのでは？という仮説に至った。
考えてみればスケジュールされていなければいけない必要性もない。
QUEUESごとにworkerプロセスを分けて見ることにした。
をオフにすることにした。

https://github.com/getredash/redash/blob/master/setup/ubuntu/files/supervisord.conf

> appears only in the queue list of "redash_celery_scheduled"

### before

```
  worker:
    image: redash/redash:latest
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "queries,scheduled_queries,celery"
      WORKERS_COUNT: 1
    restart: always
```


### after
workerコンテナを3分割した

```
  worker-queries:
    image: redash/redash:latest
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "queries"
      WORKERS_COUNT: 1
    restart: always
  worker-scheduled_queries:
    image: redash/redash:latest
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "scheduled_queries"
      WORKERS_COUNT: 1
    restart: always
  worker-celery:
    image: redash/redash:latest
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "celery"
      WORKERS_COUNT: 1
    restart: always
```

コンテナを分けた後、ctopで再度リソースを確認したところ
worker-celeryが極端にCPUを使い始めた
![スクリーンショット 2018-03-29 14.34.25.png](https://qiita-image-store.s3.amazonaws.com/0/75761/3d03aece-9aad-4b57-f524-781ca9386ee6.png)

celeryというPythonのjob queue処理で何かか詰まっていたようだ。
しばらくしたら解消した。


# redashのversionUP
以下の流れで実施する
0. Postgressのデータをバックアップする
1. コンテナを止め、削除
2. docker-composeファイルを修正する
3. DBのスキーマ変更処理をする
4. redash起動


## Postgressのデータをバックアップする

```
docker ps
docker exec -it redash_postgres_1 /bin/bash
pg_dump -U postgres postgres | gzip > /tmp/redash_backup.gz
exit
docker cp redash_postgres_1:/tmp/redash_backup.gz .
```

## コンテナを止め、削除

```
docker stop redash_worker-scheduled_queries_1 redash_worker-celery_1 redash_worker-queries_1 redash_server_1
docker rm redash_worker-scheduled_queries_1 redash_worker-celery_1 redash_worker-queries_1 redash_server_1
```

## docker-composeファイルを修正する

```
    #image: redash/redash:latest
    image: redash/redash:4.0.0-rc.1
```


## DBのスキーマ変更処理をする

https://gitter.im/getredash/redash/archives/2017/03/26
で@arikfr氏が提案してくれているコマンドを実施したが、
エラーが出るわけでもなく、何が起こったのかわからない。
しかし、ブラウザで画面を確認すると500errorになっている。

``` 失敗事例
# docker-compose run --rm server manage db upgrade
Starting redash_redis_1
[2018-03-29 05:52:16,551][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/Grammar.txt
[2018-03-29 05:52:16,586][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
[2018-03-29 05:52:17,848][PID:1][INFO][alembic.runtime.migration] Context impl PostgresqlImpl.
[2018-03-29 05:52:17,848][PID:1][INFO][alembic.runtime.migration] Will assume transactional DDL.
#
```

よくよく考えたら、
composeを起動する時のymlファイルを指定してなかった。。

``` 成功
# docker-compose -f docker-compose.production.yml run --rm server manage db upgrade
[2018-03-29 06:05:30,551][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/Grammar.txt
[2018-03-29 06:05:30,585][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
[2018-03-29 06:05:32,423][PID:1][INFO][alembic.runtime.migration] Context impl PostgresqlImpl.
[2018-03-29 06:05:32,424][PID:1][INFO][alembic.runtime.migration] Will assume transactional DDL.
[2018-03-29 06:05:32,433][PID:1][INFO][alembic.runtime.migration] Running upgrade d1eae8b9893e -> 7671dca4e604, empty message
[2018-03-29 06:05:32,439][PID:1][INFO][alembic.runtime.migration] Running upgrade 7671dca4e604 -> 5ec5c84ba61e, Add Query.search_vector field for full text search.
[2018-03-29 06:05:32,565][PID:1][INFO][alembic.runtime.migration] Running upgrade 5ec5c84ba61e -> 6b5be7e0a0ef, Re-index Query.search_vector with existing queries.
[2018-03-29 06:05:32,661][PID:1][INFO][alembic.runtime.migration] Running upgrade 6b5be7e0a0ef -> 969126bd800f, Update widget's position data based on dashboard layout.
Updating dashboards position data:
  Updating dashboard: 1
    Building widgets map:
    Widget: 1
    Widget: 2
    Iterating over layout:
      Row: 0 - [1, 2]
      Column: 0 - 1
      Column: 1 - 2
  Updating dashboard: 2
    Building widgets map:
    Widget: 3
    Iterating over layout:
      Row: 0 - [3]
      Column: 0 - 3
  Updating dashboard: 4
    Building widgets map:
    Widget: 18
    Iterating over layout:
      Row: 0 - [18]
      Column: 0 - 18
  Updating dashboard: 5
    Building widgets map:
    Widget: 21
    Widget: 22
    Widget: 31
    Widget: 32
    Widget: 41
    Widget: 42
    Widget: 82
    Widget: 93
    Iterating over layout:
      Row: 0 - [93]
      Column: 0 - 93
      Row: 1 - [21]
      Column: 0 - 21
      Row: 2 - [22]
      Column: 0 - 22
      Row: 3 - [31]
      Column: 0 - 31
      Row: 4 - [32]
      Column: 0 - 32
      Row: 5 - [41]
      Column: 0 - 41
      Row: 6 - [42]
      Column: 0 - 42
      Row: 7 - [82]
      Column: 0 - 82
  Updating dashboard: 9
    Building widgets map:
    Widget: 53
    Widget: 94
    Iterating over layout:
      Row: 0 - [94]
      Column: 0 - 94
      Row: 1 - [53]
      Column: 0 - 53
  Updating dashboard: 7
    Building widgets map:
    Widget: 38
    Widget: 40
    Widget: 95
    Iterating over layout:
      Row: 0 - [95]
      Column: 0 - 95
      Row: 1 - [38]
      Column: 0 - 38
      Row: 2 - [40]
      Column: 0 - 40
  Updating dashboard: 11
    Building widgets map:
    Widget: 71
    Widget: 67
    Widget: 70
    Iterating over layout:
      Row: 0 - [67]
      Column: 0 - 67
      Row: 1 - [70]
      Column: 0 - 70
      Row: 2 - [71]
      Column: 0 - 71
  Updating dashboard: 3
    Building widgets map:
    Widget: 5
    Widget: 11
    Widget: 13
    Widget: 14
    Widget: 15
    Widget: 16
    Widget: 17
    Widget: 28
    Widget: 51
    Widget: 77
    Widget: 78
    Widget: 80
    Iterating over layout:
      Row: 0 - [14, 15]
      Column: 0 - 14
      Column: 1 - 15
      Row: 1 - [17, 16]
      Column: 0 - 17
      Column: 1 - 16
      Row: 2 - [11, 13]
      Column: 0 - 11
      Column: 1 - 13
      Row: 3 - [28]
      Column: 0 - 28
      Row: 4 - [5]
      Column: 0 - 5
      Row: 5 - [77, 78]
      Column: 0 - 77
      Column: 1 - 78
      Row: 6 - [51, 80]
      Column: 0 - 51
      Column: 1 - 80
  Updating dashboard: 13
    Building widgets map:
    Widget: 83
    Iterating over layout:
      Row: 0 - [83]
      Column: 0 - 83
  Updating dashboard: 14
    Building widgets map:
    Iterating over layout:
  Updating dashboard: 12
    Building widgets map:
    Iterating over layout:
      Row: 0 - [
      Column: 0 - [
      Row: 1 - ]
      Column: 0 - ]
  Updating dashboard: 16
    Building widgets map:
    Widget: 102
    Widget: 103
    Widget: 104
    Widget: 105
    Iterating over layout:
      Row: 0 - [102, 103]
      Column: 0 - 102
      Column: 1 - 103
      Row: 1 - [104, 105]
      Column: 0 - 104
      Column: 1 - 105
  Updating dashboard: 6
    Building widgets map:
    Widget: 25
    Widget: 26
    Widget: 29
    Widget: 30
    Widget: 33
    Widget: 34
    Widget: 43
    Widget: 45
    Widget: 46
    Widget: 47
    Widget: 48
    Widget: 91
    Iterating over layout:
      Row: 0 - [91, 48]
      Column: 0 - 91
      Column: 1 - 48
      Row: 1 - [47, 45]
      Column: 0 - 47
      Column: 1 - 45
      Row: 2 - [46]
      Column: 0 - 46
      Row: 3 - [43]
      Column: 0 - 43
      Row: 4 - [25]
      Column: 0 - 25
      Row: 5 - [26]
      Column: 0 - 26
      Row: 6 - [29]
      Column: 0 - 29
      Row: 7 - [30]
      Column: 0 - 30
      Row: 8 - [33]
      Column: 0 - 33
      Row: 9 - [34]
      Column: 0 - 34
  Updating dashboard: 10
    Building widgets map:
    Widget: 57
    Widget: 59
    Widget: 61
    Widget: 63
    Widget: 65
    Widget: 62
    Widget: 92
    Iterating over layout:
      Row: 0 - [92]
      Column: 0 - 92
      Row: 1 - [62]
      Column: 0 - 62
      Row: 2 - [57]
      Column: 0 - 57
      Row: 3 - [63]
      Column: 0 - 63
      Row: 4 - [59]
      Column: 0 - 59
      Row: 5 - [65]
      Column: 0 - 65
      Row: 6 - [61]
      Column: 0 - 61
  Updating dashboard: 17
    Building widgets map:
    Widget: 108
    Widget: 107
    Widget: 109
    Widget: 110
    Widget: 111
    Iterating over layout:
      Row: 0 - [108]
      Column: 0 - 108
      Row: 1 - [109]
      Column: 0 - 109
      Row: 2 - [107]
      Column: 0 - 107
      Row: 3 - [110, 111]
      Column: 0 - 110
      Column: 1 - 111
  Updating dashboard: 15
    Building widgets map:
    Widget: 98
    Widget: 99
    Widget: 100
    Widget: 101
    Iterating over layout:
      Row: 0 - [99, 100]
      Column: 0 - 99
      Column: 1 - 100
      Row: 1 - [98, 101]
      Column: 0 - 98
      Column: 1 - 101
  Updating dashboard: 18
    Building widgets map:
    Widget: 112
    Widget: 113
    Widget: 114
    Iterating over layout:
      Row: 0 - [112, 113]
      Column: 0 - 112
      Column: 1 - 113
      Row: 1 - [114]
      Column: 0 - 114
  Updating dashboard: 8
    Building widgets map:
    Widget: 68
    Widget: 85
    Widget: 86
    Widget: 87
    Widget: 88
    Widget: 89
    Widget: 115
    Widget: 116
    Iterating over layout:
      Row: 0 - [68, 116]
      Column: 0 - 68
      Column: 1 - 116
      Row: 1 - [115]
      Column: 0 - 115
      Row: 2 - [85]
      Column: 0 - 85
      Row: 3 - [86, 89]
      Column: 0 - 86
      Column: 1 - 89
      Row: 4 - [87]
      Column: 0 - 87
      Row: 5 - [88]
      Column: 0 - 88
  Updating dashboard: 20
    Building widgets map:
    Iterating over layout:
  Updating dashboard: 21
    Building widgets map:
    Widget: 122
    Iterating over layout:
      Row: 0 - [122]
      Column: 0 - 122
  Updating dashboard: 19
    Building widgets map:
    Widget: 120
    Widget: 121
    Widget: 124
    Widget: 118
    Iterating over layout:
      Row: 0 - [118]
      Column: 0 - 118
      Row: 1 - [124]
      Column: 0 - 124
      Row: 2 - [120]
      Column: 0 - 120
      Row: 3 - [121]
      Column: 0 - 121
```
作業前と、作業後でスキーマを見比べて見たが、
今回新しく追加されたカラムが結構あったので、本処理は必須。

![スクリーンショット 2018-03-29 15.24.27.png](https://qiita-image-store.s3.amazonaws.com/0/75761/cee1c415-3dd0-0dd7-4397-07509abaf9d6.png)
無事アップデートが完了した。

# 参考情報
http://tech.curama.jp/entry/2018/03/02/120000