supersetをシュッと起動できるDockerfile(認証方式をGoogle API OAuth2に変更)をつくってみた、あと触ってみた所感など
ダッシュボードツールのsupersetをシュッと起動できるDockerfileを作りました。といってもsupersetのDockerfileはgithub.comに見かけるので認証方式をGoogle API OAuth2.0に変更したDockerfileを作りました。あとsupersetを触ってみての感想など導入に向けての所感をまとめたエントリです。
認証方式をOAuthに変更する方法
supersetは認証方式を変更できます。チームに最適な認証方式を選択できます。標準はDBにID/パスワードを登録する方式になっています。これをOAuthに変更する方法をまとめます。
コンテナ内の環境変数 SUPERSET_HOME
にセットしたディレクトリ配下にsuperset_config.py
を置いてsupersetの環境変数を上書きします。次のように認証方式をAUTH_OAUTH
に設定し認証プロバイダの詳細設定を記述します。
import os from flask_appbuilder.security.manager import AUTH_OAUTH basedir = os.path.abspath(os.path.dirname(__file__)) AUTH_TYPE = AUTH_OAUTH OAUTH_PROVIDERS = [ {'name':'google', 'icon':'fa-google', 'token_key':'access_token', 'remote_app': { 'consumer_key':'{GOOGLE_AUTH_CLIENT_ID}', 'consumer_secret':'{GOOGLE_AUTH_SECRET_KEY}', 'base_url':'https://www.googleapis.com/plus/v1/', 'request_token_params':{ 'scope': 'https://www.googleapis.com/auth/userinfo.email' }, 'request_token_url':None, 'access_token_url':'https://accounts.google.com/o/oauth2/token', 'authorize_url':'https://accounts.google.com/o/oauth2/auth'} } ]
認証方式をAUTH_OAUTH
に設定した状態でsupersetを起動するとログイン画面で認証するサービスにGoogle
が表示されます。
次に認証情報を作成したGoogle Developer ConsoleでリダイレクトURL
をhttp://localhost:8088/oauth-authorized/google
に設定するとGoogle Accountで認証ができます。またGoogle+ Api
からアカウント情報を取得しますのでDeveloper ConsoleでGoogle+ Api
を有効にします。
最後に認証させたいアカウントをfabmaneger
を使って作成します。
docker exec -it superset \ fabmanager create-admin --app superset \ --username 'Google+ アカウントの表示名(displayName)' \ --firstname '任意の名' \ --lastname '任意の姓' \ --email 'Google アカウントのメールアドレス' \ --password '任意のパスワード'
Google以外にもTwitterやFacebookなどの認証サービスを追加することができます。
詳しくはgithubのレポジトリに公開していますので合わせて確認できます。
supersetが参照するDBを標準のsqliteからmysqlに変更する
標準ではsupersetが参照するDBはsqliteでOS内の$DATA_DIR
にデータが格納されます。
これだとコンテナを削除するとダッシュボードの登録設定が消えてしまうのでsupersetのコンテナではない外のmysqlコンテナを起動させて参照させました。
Compose化して次のようにSQLALCHEMY_DATABASE_URI
の環境変数を変更しています。
SQLALCHEMY_DATABASE_URI = 'mysql://root@mysql:3306/app?charset=utf8mb4'
mysqlのコンテナではマルチバイト文字列も扱えるようにutf8mb4
の文字コードを有効にしています。
supersetアプリが参照するデータベースURLの末尾に?charset=utf8mb4
をつければダッシュボードの名前にマルチバイト文字列が使えるようになります。
Dockerfileの使い方
次のレポジトリのDockerfileでコンテナを起動させるとsupersetが使えるようになります。
superset-demo/superset at master · nsoushi/superset-demo · GitHub
supersetだけを起動したい場合はsuperset-init.sh
内の次の行をコメントアウトしてください。
SQLALCHEMY_DATABASE_URI = '${SUPERSET_DB_URI}'
mysqlのコンテナとセットで動かしたい場合はレポジトリのREADMEを参考にdocker-copomseでsupersetとmysqlのコンテナを起動してください。
GitHub - nsoushi/superset-demo: This repository contains demo using Superset. After begging containers, you can try Superset right now.
supersetを触ってみた感想など
最後にsupersetを触ってみた感想をまとめます。
初めてsupersetを触りましたが次のようなダッシュボードを作成することができました。
mysqlが提供するworldデータベースをデータソースにして人口やGNPの数値をグラフ化しました。
- 人口の総数(VisualizationType: BigNumber)
- 大陸ごとの人口総数(VisualizationType: Distribution - Bar Chart)
- 大陸ごとの人口総数(VisualizationType: Distribution - Pie Chart)
- 言語ごとのGNP(VisualizationType: Word Cloud)
- 大陸ごとのGNP(VisualizationType: Treemap)
worldデータベースには時系列のデータがありませんが、時系列のデータがあれば集計条件に取得範囲時間を設定してダッシュボードを定期的に更新して定点観測することもできます。
グラフの作成手順
特にヘルプなどを見なくても直感的にグラフ作成まで進めます。
グラフ作成手順は次のような流れです。
- データベースを登録する
- 登録したデータベースからテーブルを登録する
- テーブルからグラフ化するカラムを登録する
- グラフ化に必要なメトリクスを登録する
- データの総数が必要な場合は
Count(*)
、カラム値の総数が必要な場合(人口の総数)はSum(Population)
などを登録する
- データの総数が必要な場合は
- 登録したテーブルからスライスを登録する
- グラフを選択する
- メトリクスとGroup Byするカラムを組み合わせる
- 例)'Asia',‘Europe'などの大陸ごとに人口総数を出す場合は、メトリクスに
Sum(Population)
を登録してContinent
カラムをGroup Byする - 登録したグラフをダッシュボードへ登録する
柔軟にテーブルを定義できる
柔軟にグラフ化したデータテーブルを定義できます。
- DBにあるテーブルをつかう
- 複数のテーブルをJoinさせた結果をテーブルとしてつかう
SQL Lab
(SQLクエリを実行できる)で実行した結果からダイレクトにグラフ化に進む
ただ、SQL Lab
からダイレクトにグラフ化に進む方法は手元のバージョン(0.17.3)ではエラーとなりIssueとしても登録されていました。
SQL Lab
SQL Labでは作成したクエリを実行できます。
実行したクエリは履歴として残ります。後から再度実行できたり、実行結果から直接グラフを作ることもできます。
クエリを書ける人であればSQL Labでグラフ化したいデータの条件でSQLを作りメトリクスとグラフ作成に進むほうが効率が良さそうです。
機能権限とセキュリティ
Admin, Alpha, Gamma, sql_labなどのロールが用意されていてテーブルの登録権限、スライスの登録権限、SQL Labだけを使える権限などがあります。
http://airbnb.io/superset/security.html
機能権限に加えてユーザの操作ログや各種メニューへのアクセス権限などを設定することも可能です。
ここらへんはBIツールに必要そうな機能をサポートする姿勢が伺えます。
まとめ
- RedashはSQLクエリの作成を起点としてダッシュボードを整える流れに比べて、supersetは予め準備されたデータソースを選択します。次に総数や平均など、どんなメトリクスでグラフを作るかを考えダッシュボードを整えます。データソースの選択からダッシュボード登録まで全て画面UIとして提供されているのでクエリを理解していなくても簡単にグラフを作成できます。
- 必要なデータソースを予め準備するエンジニアと解析する人で役割を分ける運用ができます。解析者はエンジニアが準備してくれたデータソースをもとにメトリクスを作成して長所を活かした役割分担ができます。
- ロールとセキュリティも担保されているので情報の公開範囲に注意しながら運用できます。
- グラフの種類が豊富で定期的にグラフが更新されるダッシュボードが作れるので実行したSQL結果をエクセルに持っていきプレゼンしているような状況であれば利用の検討ができそうです。
コードを公開しています
コード全体はgitbubで確認できます。
go-grpc-prometheusでgRPCのmetricsをPrometeusとGrafanaでモニタリングしてみた
gRPC Ecosystemの1つにgo-grpc-prometheus
があります。今回は「gRPC Ecosystem
のgo-grpc-prometheus
を試してみました」エントリです。
go-grpc-prometheus
go-grpc-prometheus
はgRPCのmetricsをPrometheusでモニタリングできるログ出力をサポートするインターセプターを提供します。
取得できるmetricsはレポジトリのREADMEにまとまっています。
GitHub - grpc-ecosystem/go-grpc-prometheus: Prometheus monitoring for your gRPC Go servers.
gRPC Goはインターセプターをサポートしていますので次のようにClientとServerそれぞれに設定します。
- Serverでは次のように。https://github.com/grpc-ecosystem/go-grpc-prometheus#server-side
- Clientでは次のように。https://github.com/grpc-ecosystem/go-grpc-prometheus#client-side
PrometheusでモニタリングしたmetricsをGrafanaでもモニタリングしてみる
go-grpc-prometheus
でgRPCのmetricsが取得できるようになります。Prometheusを起動すればmetricsをモニタリングできるようになります。合わせてPrometheusでモニタリングしているmetricsをGrafanaでもモニタリングしてみます。
シンプルなEchoサービスを作る
unary RPCs
を利用してシンプルなEchoサービスを作ります。
proto
syntax = "proto3"; option go_package = "protobuf"; package proto; service EchoService { rpc EchoService (Message) returns (Message) {} } message Message { string message = 1; }
Server Side
Server sideはgRPCのClientからのリクエストに応えるServer-side of gRPC
の役割とPrometeusのためのMetrics
を出力する役割の2つが必要です。
1つのPortでHTTP/2 (gRPC)
とHTTP/1.1
のリクエストを解釈する必要があるのでsoheilhy/cmux
を使います。
ほぼ素の使い方ですがServer-sideのソースは次のようになりました。(コード抜粋。詳細はnsoushi/go-grpc-prometheus-demoにあります。)
func main() { // Create the main listener. s, err := net.Listen("tcp", fmt.Sprintf(":%s", os.Getenv("GRPC_SERVER_PORT"))) if err != nil { log.Fatal(err) } // Create a cmux. m := cmux.New(s) // Match connections in order: grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc")) httpL := m.Match(cmux.HTTP1Fast()) // gRPC server grpcS := grpc.NewServer( grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor), grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor), ) pb.RegisterEchoServiceServer(grpcS, newGrpcServer()) // prometheus metrics server grpc_prometheus.Register(grpcS) httpS := &http.Server{ Handler: promhttp.Handler(), } go grpcS.Serve(grpcL) go httpS.Serve(httpL) m.Serve() }
※ unary RPCs
のみなのでgrpc.StreamInterceptor
は必要ないですがデモのため入れています。
Client Side
Client Sideはブラウザからリクエストを受け取りgRPCのServer-sideへリクエストを送ってくれるエンドポイントとPrometeusのためのmetricsを出力するエンドポイントの2つを用意します。
Client-sideのソースは次のようになりました。(コード抜粋。詳細はnsoushi/go-grpc-prometheus-demoにあります。)
func main() { //gRPC connection var err error conn, err = grpc.Dial( fmt.Sprintf("%s:%s", os.Getenv("GRPC_SERVER_HOST"), os.Getenv("GRPC_SERVER_PORT")), grpc.WithInsecure(), grpc.WithBackoffMaxDelay(time.Second), grpc.WithUnaryInterceptor(grpc_prometheus.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpc_prometheus.StreamClientInterceptor), ) if err != nil { log.Error("Connection error: %v", err) } defer conn.Close() // handle http http.Handle("/metrics", promhttp.Handler()) http.HandleFunc("/echo", echoHandler) http.HandleFunc("/", indexHandler) // serve http http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("GRPC_CLIENT_PORT")), nil) }
Prometheusでmetricsを確認する
PrometheusはDockerで起動しました。Dockerで起動するとprometheus.ymlのtargetsにlocalhost
としてもgRPCのServer-sideとClient-sideのホストへはアクセスできないのでdocker-composeを使いコンテナ構成をまとめてホスト解決を行います。
version: "3" services: grpcserver: container_name: grpcserver build: ./server ports: - 8080:8080 environment: GRPC_SERVER_HOST: grpcserver GRPC_SERVER_PORT: 8080 grpcclient: container_name: grpcclient build: ./client ports: - 8081:8081 environment: GRPC_SERVER_HOST: grpcserver GRPC_SERVER_PORT: 8080 GRPC_CLIENT_HOST: grpcclient GRPC_CLIENT_PORT: 8081 prometheus: container_name: prometheus build: ./prometheus ports: - 9090:9090 depends_on: - grpcserver - grpcclient grafana: image: grafana/grafana ports: - "3000:3000" depends_on: - prometheus - grpcserver - grpcclient
Prometheusのコンテナを起動してhttp://localhost:9090/graph
へアクセスするとgRPCのmetricsが insert metric at cursor
のメニューに追加されているのが確認できます。
Grafanaでmetricsを確認する
Grafanaのコンテナもdocker-composeに入れましたのでhttp://localhost:3000/login
へアクセスするとGrafanaのダッシュボードを確認できます。Data Sourceにprometheusを追加してDashboardを作成します。
次のようなServer-sideのダッシュボードを作成しました。
gRPCのServer-sideのレスポンス送信数、クライアントからの受信数をGrafanaに設定しました。
※ nsoushi/go-grpc-prometheus-demoのgrafana
フォルダにServer-sideとClient-sideのダッシュボード設定をエクスポートしたJSONがあります。このJSONをインポートするとダッシュボードが簡単に作れます。詳細はレポジトリのREADMEを参照してください。
まとめ
go-grpc-prometheus
をつかってgRPCのmetricsをPrometheusとGrafanaでモニタリングしました。go-grpc-prometheus
の導入はインターセプターを入れるだけなので簡単ではありますが複数のClient-sideとServer-sideの条件での検証、負荷検証などサービスへの導入検証が必要。
コードを公開しています
コード全体はgitbubで確認できます。
Terraform 0.9がリリース。0.8.xから0.9.xのStateマイグレーション手順をまとめました。
HashiCorpからTerraform 0.9がリリースされました。「よし、最新バージョンにあげよう。」と作業をはじめましたがremote
コマンドが使えない。どうやら0.9からはremote
コマンドが廃止されたようです。このエントリではTerraform 0.9にバージョンアップをして0.8以前のterraform stateをマイグレーションする方法をまとめます。
remoteコマンドの廃止
remote
コマンドが廃止になりました。代わりにbackends
を利用してS3などのremoteにあるtfstateファイルの管理を行います。
remote stateがbackendsに置き換わる過程は次のPull Requestから確認できます。 github.com
0.8以前を利用している場合はbackendを有効にしたtfstateファイルを用意する必要があります。次からは0.8.xまでのリソース状態を保持したまま新機能のbackendを有効にしたtfstateファイルへのマイグレーション手順についてまとめていきます。
マイグレーション手順
次の環境のマイグレーション手順になります。
0.8.8
から0.9.1
へのバージョンアップする- これまではremoteに
S3
をつかっていて、これからもS3
を利用する - ロールバックできるように、これまでのtfstateファイルは保持して新しいtfstateファイルを用意する
0.8.8
と0.9.1
のterraformを使うのでtfenvを使ってterraformを切り替えながらマイグレーションを行う
1:tfファイルにterraform
セクションを追加してbackends
を設定する
次のように設定しました。
terraform { backend "s3" { bucket = "tfstate-bucket" // 自身のbucket名を設定します } }
- AWSの
access_key
,secret_key
,region
はそれぞれ環境変数のAWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
,AWS_DEFAULT_REGION
を設定しているため省略しています。 - S3の
key
は必須ですが省略しています。後述するinit
コマンドの-backend-config
オプションで開発環境や本番環境ごとにS3のkey
を分けているためterraformセクションでは省略します。
※ その他bucket
などのS3の変数はこちらにまとまっています。
2:0.8.8のterraformをつかいremote config
をしてtfstateファイルをローカルに同期する
tfenvでインストールしたバージョンリスト
terraform/dev ➤ tfenv list 0.9.1 0.8.8
0.8.8を使いremote configする
terraform/dev ➤ tfenv use 0.8.8 Terraform v0.8.8 terraform/dev ➤ terraform remote config -backend=S3 -backend-config="bucket=tfstate-bucket" -backend-config="key=dev" Initialized blank state with remote state enabled! Remote state configured and pulled.
- S3のkeyは開発環境の
dev
としています
3:0.9.1のterraformをつかいinit
をしてtfstateファイルをマイグレーションする
terraform/dev ➤ tfenv use 0.9.1 Terraform v0.9.1 terraform/dev ➤ terraform init -backend-config "key=dev" Initializing the backend... New backend configuration detected with legacy remote state! ・・・省略・・・
- 最初のaskで
remote state
から変更するか?と聞かれるのでyes
を入力します。これをすることでtfstateファイル内のremote
がbackend
に置き換わります。 - 次のaskでremoteのstateをローカルのstateにコピーする?と聞かれるのでローカルのstateを保持したければ
no
を入力、コピーするのであればyes
を入力します。すでにローカルにstateがあるのでno
と入力。
4:マイグレーションしたtfstateファイルをS3にアップロードする
マイグレーション後に0.8.8にロールバックするかもしれないので、0.8.8で運用したtfstateファイルを残したいです。そのため新しいS3のkeyをdev0.9
と決めマイグレーションしたtfstateファイルをS3にアップロードします。
terraform/dev ➤ aws s3 cp ./.terraform/terraform.tfstate s3://tfstate-bucket/dev0.9
こうすることで開発中のtfstateファイルに影響が及ぶことはなくマイグレーションのロールバックができる状態にします。
4:最後にplan
を実行して新しいtfstateファイルにリソースの差分がないか確認する
terraform/dev ➤ rm -rf ./.terraform terraform/dev ➤ tfenv use 0.9.1 Terraform v0.9.1 terraform/dev ➤ terraform init -backend-config "key=dev0.9" Initializing the backend... ・・・省略・・・ terraform/dev ➤ terraform plan --refresh=false No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, Terraform doesn't need to do anything.
- 0.9.1からは
remote config
を使わずinit
を使いtfstateファイルをローカルに同期します
まとめ
- 0.9.1へtfstateファイルのマイグレーション手順をまとめました。
- 0.8.xまでは
remote config
を利用していましたが、0.9.1からはinit
を利用します。 - backendではtfstateのリソース情報がメモリ上に管理されます。0.8.xまではリソース状態がtfstateファイルを開けば確認できましたがbackendでは確認できません。リソース状態の管理がセキュアになりました。
- backendは
STATE LOCKING
を機能が有効になります。複数人でapplyを実行した場合にstateをロックし競合を防ぎます。CIなどでapply
が同時に稼働しても安心です。 - もし0.7.xからのマイグレーションの場合はリソース状態に差分が生まれているのでリソース状態を0.8系に合わせる必要があります。
参考URL
- Terraform 0.9 | HashiCorp
- core: introduce "backends" to replace "remote state" (superset) and fix UX by mitchellh · Pull Request #11286 · hashicorp/terraform · GitHub
- Backends: Migrating From 0.8.x and Earlier - Terraform by HashiCorp
- Backends - Terraform by HashiCorp
- State: Locking - Terraform by HashiCorp