ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

SupersetをECS(Docker)で導入してみる

おはこんばんちはユニファのインフラのすずきです。

今肩こりが悪化しすぎて右腕が痛くなって接骨院通っています。 右腕の痛みは治ったのですが肩のほうが痛くないのが異常だと言われ緩めるために引き続き通い続けています。 みなさんも普段の姿勢とか肩を動かす運動とかして慢性的な肩こりにならないようにしていただけたらと思います。

あとiPhoneX買いましたanimojiキモいですね!

さて本題、弊社DBの情報をグラフなどで可視化したり、一覧で取得したりなどするためにRedashを利用しています。 特定のサービスでしか利用していなかったので、先日他のサービスでも利用できるように共通の環境に移設しました(ついでにDocker化)。
ただ、Redash自体は他の候補を検討せず導入したものであり、実現したいことも増えてきたのでこれを期にRedash以外を検討してみようということになりました。
そこで、最近良く目にするようになってきたSupersetがどんなものかお試しで利用してみようとなりました。 丁度RedashがDockerで動いてるのでSupersetもDockerで動かしてみようとおもったので、その内容をブログにしてみました。

コンテナイメージの作成

Superset を読んでみるとDocker image (community contributed)とDocker Imageが存在していたのでこれ幸いと利用します。
これを利用したDockerfileを作成し、ECRにPushしてECSで利用していきます。

用意したファイルとその内容は以下になります。

$ ls -r *
Dockerfile

superset:
superset_config.py

$
$ cat Dockerfile
FROM amancevice/superset

ADD superset /etc/superset
$
$ cat superset/superset_config.py
import os

MAPBOX_API_KEY = os.getenv('MAPBOX_API_KEY', '')
CACHE_CONFIG = {
    'CACHE_TYPE': 'redis',
    'CACHE_DEFAULT_TIMEOUT': 300,
    'CACHE_KEY_PREFIX': 'superset_',
    'CACHE_REDIS_HOST': os.getenv('CACHE_REDIS_HOST', ''),
    'CACHE_REDIS_PORT': 6379,
    'CACHE_REDIS_DB': os.getenv('CACHE_REDIS_DB', 0),
    'CACHE_REDIS_URL':  os.getenv('CACHE_REDIS_URL', '')}
SQLALCHEMY_DATABASE_URI = \
    os.getenv('SQLALCHEMY_DATABASE_URI', '')
SQLALCHEMY_TRACK_MODIFICATIONS = True
SECRET_KEY = 'thisISaSECRET_1234'

Dockerfileは公開されているイメージに、環境に合わせた設定ファイルを追加するというものになっています。

Supersetは環境変数 PYTHONPATHsuperset_config.py が存在していると読み込み、Supersetの設定として利用します。 このイメージでは /etc/superset/PYTHONPATH になっているのでそちらに作成した設定ファイルを突っ込んでやる形になっています。
詳細を知りたい方はこのイメージのDockerfileなど見ていただけるといいのかなと思います。

追加した設定ファイルは利用しているDockerイメージのDockerfileと同じリポジトリ内にある、Postgresqlの 設定ファイルを参考にしています。 変更しそうな値は環境変数にしてECS側から利用できるようにしています。

ここまでできたらECRのリポジトリ作成時に出てきたコマンドに従ってECRにPushします。

ECSのタスクの設定

設定内容が多いのでJSONを貼ってしまいます。 必要そうなのはこのあたりかと思います。

  • image : pushしたecrのイメージを指定
  • environment : superset_config.py で設定している値を指定
  • user : supersetユーザを指定
  • portMappings : 8088:8088 tcpを指定
{
    "networkMode": "bridge",
    "taskRoleArn": null,
    "containerDefinitions": [
        {
            "volumesFrom": [],
            "memory": 512,
            "extraHosts": null,
            "linuxParameters": null,
            "dnsServers": [],
            "disableNetworking": null,
            "dnsSearchDomains": [],
            "portMappings": [
                {
                    "hostPort": 8088,
                    "containerPort": 8088,
                    "protocol": "tcp"
                }
            ],
            "hostname": null,
            "essential": true,
            "entryPoint": [
                "superset"
            ],
            "mountPoints": [],
            "name": "superset",
            "ulimits": null,
            "dockerSecurityOptions": [],
            "environment": [
                {
                    "name": "CACHE_REDIS_URL",
                    "value": "redis://10.0.0.1:6379/0"
                },
                {
                    "name": "CACHE_REDIS_DB",
                    "value": "0"
                },
                {
                    "name": "SQLALCHEMY_DATABASE_URI",
                    "value": "postgresql+psycopg2://superset:superset@example.ap-northeast-1.rds.amazonaws.com:5432/superset"
                },
                {
                    "name": "CACHE_REDIS_HOST",
                    "value": "10.0.0.1"
                },
                {
                    "name": "MAPBOX_API_KEY",
                    "value": "xxxxxxxxxxxxxxxxxxxx"
                }
            ],
            "links": [],
            "workingDirectory": null,
            "readonlyRootFilesystem": false,
            "image": "YYYYYYYYYYYY.dkr.ecr.ap-northeast-1.amazonaws.com/superset:latest",
            "command": [
                "runserver"
            ],
            "user": "superset",
            "dockerLabels": null,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "superset",
                    "awslogs-region": "ap-northeast-1"
                }
            },
            "cpu": 0,
            "privileged": false,
            "memoryReservation": null
        }
    ],
    "volumes": [],
    "family": "superset",
    "placementConstraints": []
}

Supersetの起動

先程作成したタスクを実行します。

タスクが動いてるサーバに接続します。 サーバIP:8088 するとこんな画面になってSupersetが起動できたのが確認できるかと思います。 f:id:mominosin:20171116154158p:plain

しかしここで適当なアカウント入力しても、ありそうなアカウント入力してみても反応はありません。 それもそのはずDBが存在しないのです。

Supersetを初期セットアップするsuperset-initコマンドを実行する必要があります。
それ用のECSタスクを作ろうかとも思ったのですがキー入力が必要になるので断念しました。
なのでタスクの動いているEC2インスタンスにSSHログインしてコマンドを実行します。

'->$ docker exec -it [supersetが起動しているコンテナID]  superset-init
Username [admin]: admin
User first name [admin]: admin
User last name [user]: user
Email [admin@fab.org]: admin@example.com
Password:
Repeat for confirmation:
Loaded your LOCAL configuration at [/etc/superset/superset_config.py]
/usr/local/lib/python3.5/dist-packages/flask_cache/jinja2ext.py:33: ExtDeprecationWarning: Importing flask.ext.cache is deprecated, use flask_cache instead.
  from flask.ext.cache import make_template_fragment_key
Recognized Database Authentications.
Admin User admin created.
Loaded your LOCAL configuration at [/etc/superset/superset_config.py]
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 4e6a06bad7a8, Init
INFO  [alembic.runtime.migration] Running upgrade 4e6a06bad7a8 -> 5a7bad26f2a7, empty message
~~~~~~~~~~~~~~~~~~~~~~ どるぅぅぅっと流れます~~~~~~~~~~~~~~~~~~~~~~~~~~~

ここではadminユーザの作成をしています。 作成が終わった後再度ブラウザからSupersetを開いてsuperset-initで設定した UsernameとPasswordを入力してログインしてください。 f:id:mominosin:20171116160941p:plain するとログインできたかなと思います。

以上でSupersetをECSに導入してみるでした。 結構端折ったり適当な質問してたりすると思いますがご了承ください。

ツッコミ等あればコメントいただけたらと思います。

今回はこれにて!