centos7
digdag

Digdag serverを入れた際の躓きポイント(CentOS7対応)

数ヶ月前、Digdag serverを導入した。
これまではタスクの依存関係だけ解決できればいいよね、というスタンスでDigdagを使っていた。
が、タスクのモニタリングやRetry、並列処理をスムーズにやりたい等が重なりDigdag serverを使うことになった。

ついでにCentosが6だったので7にアップグレードしている。

自分が躓いた点について書いてみた。

DigdagをDaemon化するためのSystemd設定

/usr/lib/systemd/system/digdag.service
[Unit]
Description=digdag

[Service]
Type=simple
PIDFile=/run/digdag.pid
ExecStart=/bin/bash -l -c 'EMBULK_ROOT=/apps/ipros-embulk/current ~/bin/digdag server --max-task-threads 2 --config /home/app/.config/digdag/config -O /apps/ipros-embulk/shared/log -A /apps/ipros-embulk/shared/log'
User=app
Group=app
WorkingDirectory=/apps/ipros-embulk/current/
Restart=always
RestartSec=5
KillMode=process
TimeoutStopSec=1200
SyslogIdentifier=digdag

[Install]
WantedBy=multi-user.target

Systemd備考

  • --max-task-threadsはEmbulkが大量に動いても困るので2に制限
  • KillModeのデフォルトはcontrol-groupだが、これだと再起動した際に問答無用でDigdagとタスクを殺してしまう。
    • Digdagはprocessをstopする際にタスクの終了を待つようになっている。
  • SyslogIdentifierはjournald経由でSyslogに転送する際のident。
  • Digdag自体のアップグレードをカジュアルにやりたいためroot権限では動作させず、ユーザー権限で動かしている。

@frsyuki 先生のご教授

--params-file(-P)オプションをやめて環境変数を丸ごとinclude

Digdagはserver modeでもClient modeでも--params-file yamlとするとyamlの中をDigdag.envに展開してくれる。
以下が参考になる。

例えば実行方法は以下のような感じ。

  • Client mode
digdag run --project workflow -P env.yml test.dig
  • Server mode
digdag server -o workflow/.digdag -P env.yml

ただ、この場合毎回workflowをdeployする度にDigdagをrestartしなければならずバッチが常時起動しているようなワークロードでは致命的。
実行中のタスクがあれば再起動がタスク待ちになってしまうので、そう簡単に再起動は出来ない。
そこで全てのworkflowに以下のような記述をしている。

env.dig
HOGE: test
base.dig
_export:
  !include : shared/env.dig
task.dig
!include : shared/base.dig
+task1:
  sh>: echo ${HOGE}

このように環境変数自体をincludeにしてしまえばdigdag push時に読み込まれるため再起動が不要。
ただし、~/.config/digdag/configを編集した場合は再起動が必要。
勿論env.digを環境(Stage)毎に変えてDeployすることを前提としている。

includeには以下の注意点がある。

  • 親ディレクトリにあるdigはinclude出来ない。
    • symlinkにしても親ディレクトリに実態があれば不可
    • hardlinkにすれば当然いけた。
  • 拡張子が.digでないとinclude出来ない。

database.type = postgresql について

~/.config/digdag/configに以下のように接続情報を書いておくと、Digdag serverを複数台で分散して動かせる。
要はHAできる。

database.type: postgresql
database.user: application
database.password: xxxxxxxxx
database.host: digdag01
database.port: 5432
database.database: embulk
database.maximumPoolSize: 32

サーバー間で設定を合わせる必要がある。
またローカルに一時ファイルを置くようなタスクの依存関係を取っている場合は当然不整合が起きる。
弊社はこのケースが多かったので、一時ファイル置き場にはNFSを噛まして対応した。
Digdagのconfigを書き換えた際には当然restartが必要。(digdag pushでは変更が反映されないので注意)

以下のようなワークフローの場合、task1がサーバーAでtask2がサーバーBで動くといった感じになる。

+task1:
  sh>: echo ${HOGE}

+task2:
  sh>: echo ${HOGE}

Postgresqlのコネクション数について

RDSのt2.microでpostgresqlを作成したがそれでも負荷的には全く問題ない。
が、接続数がDefaultでavailable CPU cores * 32とかなり多めなので抑えるためにdatabase.maximumPoolSizeを32にした。

@frsyuki 先生曰く、コネクション数はかなり少なくしても問題はないとのこと。

自分のケースでは主にEmbulkをシングルサーバで実行するのが目的なので--max-task-threadsで同時実行数を制限している。
分散実行は現状別の仕組みで実行しているが、これはDigdagに寄せていきたい。

Ruby operatorを使う際に嵌った点

まず、ディレクトリ階層が以下のようになっている場合。(というか自分のケース)

root/
  workflow/
    task1.dig
    task2.dig
    shared/
      base.dig
    lib/
      environment.rb
  Gemfile
  script.rb

serverにpushする場合は

$ digdag push myproject --project workflow

とする。
これを実行すればディレクトリ配下のdigがまとめてpushされてDigdagのワークスペースに配置される
このDigdagのワークスペースというのが少し曲者だった。
bundle execなどでRubyのscriptを実行しても、このワークスペースがcurrent directoryになってしまいfailしてしまう。
Gemfileがdigdag pushの対象外なため。

なので、以下のようにcdするか、Bundler.setupをscript内で動かす必要がある。(自分は後者)

+task2:
  sh>: |
    cd /apps/root
    bundle exec script.rb