ライフワーク(&将来の仕事)としている野球データ分析の基盤をAirflow + Docker他で作りました.
このハナシはkawasaki.rb #051 5年目突入LT大会で披露したLTの続きであり,
PyConJP 2017のトークネタ「野球を科学する技術〜Pythonを用いた統計ライブラリ作成と分析基盤構築」のメインテーマ「分析基盤構築」の主軸となるハナシでもあります.
要約すると
- データ集め→前処理→データベース化の流れはAirflowを使うといい感じに実現できる.
- Airflowは高機能だが導入と運用に一手間かかる→困った→そうだ!Docker Imageにしちゃえ!→楽になったぞ!
- そんなAirflowのDocker Imageとコードを公開したので気になる方はぜひ使ってほしい&PRとかいただけるとうれしいです.
このエントリーの対象読者
- データを集めて分析するお仕事・趣味をしている方かつ,cron的な方法で定期実行する方法にお悩みの方.
- データ集めと前処理,データベース化を今時な「データパイプライン」で実現したい方.
- レベル的にはPythonおよびDockerを実務で使っている方は割と読めると思います.
なお,野球の分析基盤ハナシですが,野球のハナシは一切出てきません.あしからず.
おしながき
- 要約すると
- このエントリーの対象読者
- おしながき
- 「俺々データ分析基盤」の全体像
- Airflow #とは
- Dockerイメージを作った&公開した
- 使い方(例)
- 実際やってみて
- 学んだこと
- 【雑感】kawasaki.rb #51 の感想
「俺々データ分析基盤」の全体像
まず,実現したい「俺々データ分析基盤」の全体像です.
「kawasaki.rb #051 5年目突入LT大会」でLTしたこちらのスライドのおさらいでもあります.
必要な箇所のみ抜粋してご紹介します.
実現したいこと(図解付き)
世の中のWebサイト(お察し)から,
- 毎日1:00(JST)にクローラー(Scrapyで実装)を回してデータを取ってくる&クレンジングして保存する
- 2:00頃から,保存したデータに対してセイバーメトリクス(野球統計学)の指標値・モデルを使って前処理(Pythonスクリプト)を行ってアップデートする
- 取得したデータはJupyter,pandasなどを使って分析・可視化
を実現するため,以下の構成でプロダクトを開発しています.
分析環境のJupyterを除き,Docker Container上で動くアプリケーションとして構築しています.
クローラー(Scrapy)や前処理(Pythonスクリプト)を毎日定時実行する仕組みがほしいと思い,
といった幾つかの候補の中から,Python製のAirflowの導入を決め(選んだ理由は後述),こちらで構築することにしました.
Airflow #とは
AirflowはAirbnbが最初に開発し,ApacheプロジェクトとなったOSSのジョブスケジューラ&データパイプラインのプラットフォームです.
Apache Airflow (incubating) Documentation — Airflow Documentation
JenkinsやRundeckだとちょっと重い…Pythonでやりたい!という層に対して人気っぽいです.
探すとブログも幾つかありました&私がはじめた当初は参考にさせてもらいました.
具体的な利用例や使い方などはこれらのブログおよび公式ドキュメントを参考にされたほうがよいかなと思います(ここでは解説しません).
特徴(長所)
必要な機能(ジョブスケジューラ・ワーカー・GUI)が揃っているかつ、全てPythonで実現している一貫性が大きな強みです.
- ジョブスケジューラ(scheduler),ジョブワーカー(worker),GUI(webserver)がきれいに分かれており,三つ全部使う・必要なモノのみ使うといった柔軟な運用が可能.
- DAG(Directed acyclic graph, 有向非巡回グラフ)をベースにタスクを記述. Pythonを書ける人ならだれでも記述可能かつ楽.
- cronが無くても単体でジョブスケジューラとして機能する. Docker使いならわかってくださると思いますが,わざわざcronを入れたりする手間を省けて◎
- GUIやユーザー管理が最初から充実している.必要なプラグインのみ選択してインストールしたら大抵のことができる.
- これらの機能・強みをPythonの長所を駆使して実現している!
私自身は,scheduler,worker,webserverそれぞれが高機能かつ,分けて使うことができる有効性に惚れたのと,たまたまAirflowを知ってた同僚の押しに負け,「俺々データ分析基盤」のデータパイプラインの基盤としてAirflowを採用しました.
なお,先ほど名前を上げたFrameworkたちですが,
- Rundeckは技術的に枯れているので利用したかったが,Pythonで作りたかったので不採用(PyCon JPの発表でもあるので)
- luigiはAirflowとくらべて軽くて素直で魅力があったが,パイプラインの記述が独特なのとcronを別に入れないといけない
という理由で採用をやめました.
短所
いたれりつくせりなAirflow(意味:気流)ですが,万能ではなく色々と厄介な面もあります.
- 高機能な分の代償なのか,依存ライブラリがメチャクチャ多い.下手をすると100を超える
- DAGの追加・設定変更の度にアプリケーションの再起動が必要
- 設定変更の度にAirflowのDBをリセット(airflow resetdb)しないとすぐ動かなくなる
- そんなresetdbをしても上手く動いてくれないときもある→結局SchemeをDropしてDBを作り直すのが手っ取り早い*1
- ちょっとでも設定を変えようとすると定義ファイル(airflow.cfg)を作り直さないとアカン
- 総じて,動作環境を作って安定稼働させるのがメチャクチャ面倒くさい!!!(半ギレ
Airflowは「気流」の如く,データパイプラインを作れる&運用ができる!…かと思いきや,
ちょっとした変更ですぐに乱気流になるTurbulenceなんや!!!
とこの数ヶ月で学びました.
Dockerイメージを作った&公開した
そんなTurbulence…じゃなくてAirflowの長所を活かしつつ欠点を補うため,
自分がハマった箇所を自動化&Docker Imageにして公開しました!
ポイントとしては,
- わずらわしい初期設定・ライブラリ管理をDockerfileに全て梱包
- Dockerの特徴「作っては壊して再作成」が楽にできる長所を駆使して環境の作り直し・リセットを楽にした
- imageを継承(FROM)することにより,自前のアプリケーションのデプロイを楽に
となります.
なお,ググると他のimageが一個だけ見つかりますが,こちらはDBがPostgres SQL縛りなのと,sedで地味に置換するのが辛かったので使うのをやめました.*2
https://hub.docker.com/r/puckel/docker-airflow/~/dockerfile/
使い方(例)
GithubのREADME.md に記載の通りですが,ちょこっとだけ抜粋&補足します.
imageを取得する
これはいつもどおりdocker pullで済みます.
$ docker pull shinyorke/airflow
単体で動かす
いずれもお試しで動かす際はこのコマンドをコピればOKです.
実際に環境を好きにカスタマイズする際は, 環境変数(–env-file)のファイルを修正(もしくは新規作成)してあげればOKです.
webserver
$ docker run -p 8080:8080 --env-file=./env_example shinyorke/airflow webserver init
scheduler
$ docker run --env-file=./env_example shinyorke/airflow scheduler init
worker
$ docker run --env-file=./env_example shinyorke/airflow worker init
Productionな構成で動かす(サンプル)
airflowの管理DBをMySQL,workerのqueueとしてcelery(バックエンドはredis)を使う本番構成サンプルを用意しました.
Dockerfile(airflow_dag_sample/DockerfileExample)
オリジナルのイメージを継承して,DAGファイルを置くだけのシンプル設計で動きます.
airflow_dag_sample/直下に好きなDAGを入れたら動きます.
Pythonのアプリを動かす際はpip installなどをいい感じに入れてあげればOK.
ちなみにPYTHONPATHを上手く指定したら$AIRFLOW_HOMEじゃなくても任意のPythonアプリが動きます.
# airflow-docker example FROM shinyorke/airflow:latest MAINTAINER Shinichi Nakagawa <spirits.is.my.rader@gmail.com> # airflow ENV AIRFLOW_USER=airflow ENV AIRFLOW_HOME=/usr/local/airflow # add to dag USER ${AIRFLOW_USER} ADD ./airflow_dag_sample ${AIRFLOW_HOME}/dags # run application EXPOSE 8080 5555 8793 WORKDIR ${AIRFLOW_HOME} ENTRYPOINT ["/entrypoint.sh"]
docker-compose-example.yml
定義ファイル(env_example_docker-compose)はそのままでも動きますが,必要に応じて変更するといいかも.
version: "3.0" services: webserver: build: context: ./ dockerfile: airflow_dag_sample/DockerfileExample container_name: airflow_webserver env_file: ./env_example_docker-compose ports: - "8080:8080" restart: always command: ["webserver", "init"] scheduler: build: context: ./ dockerfile: airflow_dag_sample/DockerfileExample container_name: airflow_scheduler env_file: ./env_example_docker-compose restart: always depends_on: - webserver command: ["scheduler", ""] worker: build: context: ./ dockerfile: airflow_dag_sample/DockerfileExample container_name: airflow_worker env_file: ./env_example_docker-compose restart: always depends_on: - webserver - redis command: ["worker", ""] redis: image: redis:3.2.9-alpine container_name: airflowl_redis command: ["redis-server", "--appendonly", "yes"] networks: default: external: name: airflow_link
起動
DBのイメージを動かした後,アプリを起動します.
$ docker-compose -f docker-compose-example-db.yml up -d $ docker-compose -f docker-compose-example.yml build $ docker-compose -f docker-compose-example.yml up -d
こんな感じでアプリが動いたら成功です.
※画面は野球データ分析基盤です(残念ながら非公開)
実際やってみて
結論から言うと,
当初の目的「データ集め→前処理→データベース化の流れ」の基盤化&運用に成功したので満足しています.
自宅PC(iMac)で毎日動かしてデータを取得しているのですが,約二週間分の野球データが整形された状態で手元にある状態ができており,
やりたい可視化・分析はできています.
その成果は…PyConJP 2017でお披露目できたらと思います(大切なので二回言った)
学んだこと
- (Airflowを使うのは大変だってのは)見てのとおりです.
- (Dockerでまとめちゃうと楽になるのは)見てのとおりですね.
- 人類が皆ハマりそうな所は自動化してOSSにしちゃおう
- すべてPythonで収まるのは気持ちいい
- とはいえ次に同じようなことをする時にAirflowを使うかどうかはちょっと考えたい.*3
【雑感】kawasaki.rb #51 の感想
今回の分析基盤ネタはPyConJP 2017…の前に,壁打ち・素振りとしてkawasaki.rbさんの5年目突入LT会で披露させてもらいました.
感想はだいたいこんな感じ
野球の人正装きた #kwskrb
— Naoki Nagazumi (@nk_ngzm) 2017年8月23日
本日のPython枠と正装 #kwskrb pic.twitter.com/IGuqpvOp5c
— ぺら (@Peranikov) 2017年8月23日
#kwskrb は Pycon の壁打ち場所
— プログラミングが苦手なフレンズ (@NagominHotMotto) 2017年8月23日
#kwskrb 「kwskpyで良いのではないか」
— YakisobaMelonpan@🍣 (@ice_arr) 2017年8月23日
Airflow使ってるのか #kwskrb
— MasaruTech (@MasaruTech) 2017年8月23日
"AirflowはTurbulence だった" #kwskrb
— chezou (@chezou) 2017年8月23日
当日の盛り上がりの様子はTogetterにまとまってます,控えめに言って最高でした.
GolangやRuby,イカの話で盛り上がる中,Pythonの環境のハナシになる→後日主催の@chezouさんまとめの大変素晴らしいエントリーが出てくるという, #kwskpy #kwskrb らしい大変素晴らしい会でした.
今年も壁打ちありがとうございました!&またお邪魔します!!