Lean Baseball

Engineering/Baseball/Python/Agile/SABR and more...

AirflowとDockerで俺々データ分析基盤をつくってみた&Imageを公開してみた #kwskrb

ライフワーク(&将来の仕事)としている野球データ分析の基盤をAirflow + Docker他で作りました.

このハナシはkawasaki.rb #051 5年目突入LT大会で披露したLTの続きであり,

PyConJP 2017のトークネタ「野球を科学する技術〜Pythonを用いた統計ライブラリ作成と分析基盤構築」のメインテーマ「分析基盤構築」の主軸となるハナシでもあります.

要約すると

  • データ集め→前処理→データベース化の流れはAirflowを使うといい感じに実現できる.
  • Airflowは高機能だが導入と運用に一手間かかる→困った→そうだ!Docker Imageにしちゃえ!→楽になったぞ!
  • そんなAirflowのDocker Imageとコードを公開したので気になる方はぜひ使ってほしい&PRとかいただけるとうれしいです.

このエントリーの対象読者

  • データを集めて分析するお仕事・趣味をしている方かつ,cron的な方法で定期実行する方法にお悩みの方.
  • データ集めと前処理,データベース化を今時な「データパイプライン」で実現したい方.
  • レベル的にはPythonおよびDockerを実務で使っている方は割と読めると思います.

なお,野球の分析基盤ハナシですが,野球のハナシは一切出てきません.あしからず.

おしながき

「俺々データ分析基盤」の全体像

まず,実現したい「俺々データ分析基盤」の全体像です.

kawasaki.rb #051 5年目突入LT大会」でLTしたこちらのスライドのおさらいでもあります.

speakerdeck.com

必要な箇所のみ抜粋してご紹介します.

実現したいこと(図解付き)

世の中のWebサイト(お察し)から,

  • 毎日1:00(JST)にクローラー(Scrapyで実装)を回してデータを取ってくる&クレンジングして保存する
  • 2:00頃から,保存したデータに対してセイバーメトリクス(野球統計学)の指標値・モデルを使って前処理(Pythonスクリプト)を行ってアップデートする
  • 取得したデータはJupyter,pandasなどを使って分析・可視化

を実現するため,以下の構成でプロダクトを開発しています.

f:id:shinyorke:20170831190033p:plain

分析環境のJupyterを除き,Docker Container上で動くアプリケーションとして構築しています.

クローラー(Scrapy)や前処理(Pythonスクリプト)を毎日定時実行する仕組みがほしいと思い,

といった幾つかの候補の中から,Python製のAirflowの導入を決め(選んだ理由は後述),こちらで構築することにしました.

Airflow #とは

AirflowはAirbnbが最初に開発し,ApacheプロジェクトとなったOSSのジョブスケジューラ&データパイプラインのプラットフォームです.

github.com

Apache Airflow (incubating) Documentation — Airflow Documentation

JenkinsやRundeckだとちょっと重い…Pythonでやりたい!という層に対して人気っぽいです.

探すとブログも幾つかありました&私がはじめた当初は参考にさせてもらいました.

具体的な利用例や使い方などはこれらのブログおよび公式ドキュメントを参考にされたほうがよいかなと思います(ここでは解説しません).

qiita.com

oss.sios.com

tech.speee.jp

特徴(長所)

必要な機能(ジョブスケジューラ・ワーカー・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(意味:気流)ですが,万能ではなく色々と厄介な面もあります.

  1. 高機能な分の代償なのか,依存ライブラリがメチャクチャ多い.下手をすると100を超える
  2. DAGの追加・設定変更の度にアプリケーションの再起動が必要
  3. 設定変更の度にAirflowのDBをリセット(airflow resetdb)しないとすぐ動かなくなる
  4. そんなresetdbをしても上手く動いてくれないときもある→結局SchemeをDropしてDBを作り直すのが手っ取り早い*1
  5. ちょっとでも設定を変えようとすると定義ファイル(airflow.cfg)を作り直さないとアカン
  6. 総じて,動作環境を作って安定稼働させるのがメチャクチャ面倒くさい!!!(半ギレ

Airflowは「気流」の如く,データパイプラインを作れる&運用ができる!…かと思いきや,

ちょっとした変更ですぐに乱気流になるTurbulenceなんや!!!

とこの数ヶ月で学びました.

Dockerイメージを作った&公開した

そんなTurbulence…じゃなくてAirflowの長所を活かしつつ欠点を補うため,

自分がハマった箇所を自動化&Docker Imageにして公開しました!

shinyorke/airflow

github.com

ポイントとしては,

  • わずらわしい初期設定・ライブラリ管理を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

こんな感じでアプリが動いたら成功です.

※画面は野球データ分析基盤です(残念ながら非公開)

f:id:shinyorke:20170831203456p:plain

f:id:shinyorke:20170831203449p:plain

実際やってみて

結論から言うと,

当初の目的「データ集め→前処理→データベース化の流れ」の基盤化&運用に成功したので満足しています.

自宅PC(iMac)で毎日動かしてデータを取得しているのですが,約二週間分の野球データが整形された状態で手元にある状態ができており,

やりたい可視化・分析はできています.

その成果は…PyConJP 2017でお披露目できたらと思います(大切なので二回言った)

pycon.jp

学んだこと

  • (Airflowを使うのは大変だってのは)見てのとおりです.
  • (Dockerでまとめちゃうと楽になるのは)見てのとおりですね.
  • 人類が皆ハマりそうな所は自動化してOSSにしちゃおう
  • すべてPythonで収まるのは気持ちいい
  • とはいえ次に同じようなことをする時にAirflowを使うかどうかはちょっと考えたい.*3

【雑感】kawasaki.rb #51 の感想

今回の分析基盤ネタはPyConJP 2017…の前に,壁打ち・素振りとしてkawasaki.rbさんの5年目突入LT会で披露させてもらいました.

kawasakirb.connpass.com

感想はだいたいこんな感じ

当日の盛り上がりの様子はTogetterにまとまってます,控えめに言って最高でした.

togetter.com

GolangやRuby,イカの話で盛り上がる中,Pythonの環境のハナシになる→後日主催の@chezouさんまとめの大変素晴らしいエントリーが出てくるという, #kwskpy #kwskrb らしい大変素晴らしい会でした.

medium.com

今年も壁打ちありがとうございました!&またお邪魔します!!

*1:コードを読むのは面倒なのでやめた.何のためのリセットなのかw

*2:とはいえ,シェルとか構成とかメチャクチャ参考になって助かりました.感謝感激.

*3:一時期はホントどうにも動かなくて辛かった