digdagで定期バックアップをやってみた

# はじめに

あるソフトウェアのバックアップ取得をcronで実施していたが、失敗したことに気づかないまま放置されていたことがあったので、処理の失敗時にアラートを飛ばすように改善しようと思った。
そのため、cronをやめ、ワークフローエンジンであるdigdagの機能を使ってアラート通知してみた。

# digdagの導入

## 環境情報

* Ubuntu 18.04.3
* OpenJDK 1.8.0
* digdag 0.10.1

## 作業ログ

公式ドキュメント[^1]を参考に、インストールする。

### JDK8のインストール

前提条件[^2]であるJDK8をインストールする。

```
$ sudo apt update

... snip ...

76 packages can be upgraded. Run 'apt list --upgradable' to see them.
$ apt-cache policy openjdk-8-jdk
openjdk-8-jdk:
  Installed: (none)
  Candidate: 8u292-b10-0ubuntu1~18.04
  Version table:
     8u292-b10-0ubuntu1~18.04 500
        500 http://jp-west-1a.clouds.archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages
        500 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages
     8u162-b12-1 500
        500 http://jp-west-1a.clouds.archive.ubuntu.com/ubuntu bionic/universe amd64 Packages
$ sudo apt install -y openjdk-8-jdk

... snip ...

$ java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-8u292-b10-0ubuntu1~18.04-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)
```

### digdagのインストール

バイナリをダウンロードして、実行権限付与して、パスの通ったディレクトリに置くだけ。

```
$ export DIGDAG_VERSION=0.10.1
$ curl -O https://github.com/treasure-data/digdag/releases/download/v${DIGDAG_VERSION}/digdag-${DIGDAG_VERSION}.jar
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   623  100   623    0     0   1876      0 --:--:-- --:--:-- --:--:--  1870
100 81.2M  100 81.2M    0     0  16.2M      0  0:00:04  0:00:04 --:--:-- 17.7M
$ chmod +x digdag
$ sudo mv digdag /usr/local/bin/
$ digdag --version
0.10.1
```

### ワークフローのサンプルを試す

```
~$ digdag init mydag
2021-07-26 07:30:39 +0000: Digdag v0.10.1
  Creating mydag/mydag.dig
  Creating mydag/.gitignore
Done. Type `cd mydag` and then `digdag run mydag.dig` to run the workflow. Enjoy!
~$ cd mydag/
~/mydag$ digdag run mydag.dig
2021-07-26 07:30:56 +0000: Digdag v0.10.1
2021-07-26 07:30:58 +0000 [WARN] (main): Using a new session time 2021-07-26T00:00:00+00:00.
2021-07-26 07:30:58 +0000 [INFO] (main): Using session /home/ubuntu/mydag/.digdag/status/20210726T000000+0000.
2021-07-26 07:30:58 +0000 [INFO] (main): Starting a new session project id=1 workflow name=mydag session_time=2021-07-26T00:00:00+00:00
2021-07-26 07:31:00 +0000 [INFO] (0016@[0:default]+mydag+setup): echo>: start 2021-07-26T00:00:00+00:00
start 2021-07-26T00:00:00+00:00
2021-07-26 07:31:01 +0000 [INFO] (0016@[0:default]+mydag+disp_current_date): echo>: 2021-07-26 00:00:00 +00:00
2021-07-26 00:00:00 +00:00
2021-07-26 07:31:02 +0000 [INFO] (0016@[0:default]+mydag+repeat): for_each>: {order=[first, second, third], animal=[dog, cat]}
2021-07-26 07:31:03 +0000 [INFO] (0016@[0:default]+mydag+repeat^sub+for-0=order=0=first&1=animal=0=dog): echo>: first dog
first dog
2021-07-26 07:31:03 +0000 [INFO] (0019@[0:default]+mydag+repeat^sub+for-0=order=1=second&1=animal=1=cat): echo>: second cat
second cat
2021-07-26 07:31:03 +0000 [INFO] (0018@[0:default]+mydag+repeat^sub+for-0=order=1=second&1=animal=0=dog): echo>: second dog
second dog
2021-07-26 07:31:03 +0000 [INFO] (0017@[0:default]+mydag+repeat^sub+for-0=order=0=first&1=animal=1=cat): echo>: first cat
first cat
2021-07-26 07:31:03 +0000 [INFO] (0020@[0:default]+mydag+repeat^sub+for-0=order=2=third&1=animal=0=dog): echo>: third dog
third dog
2021-07-26 07:31:03 +0000 [INFO] (0021@[0:default]+mydag+repeat^sub+for-0=order=2=third&1=animal=1=cat): echo>: third cat
third cat
2021-07-26 07:31:05 +0000 [INFO] (0021@[0:default]+mydag+teardown): echo>: finish 2021-07-26T00:00:00+00:00
finish 2021-07-26T00:00:00+00:00
Success. Task state is saved at /home/ubuntu/mydag/.digdag/status/20210726T000000+0000 directory.
  * Use --session <daily | hourly | "yyyy-MM-dd[ HH:mm:ss]"> to not reuse the last session time.
  * Use --rerun, --start +NAME, or --goal +NAME argument to rerun skipped tasks.
```

動いたようである。

# 定期バックアップを実行するワークフローの設定

## ワークフローの作成

まずは`digdag init`コマンドでワークフローのプロジェクトを作成

```
$ digdag init backup-dag
2021-07-28 08:38:25 +0000: Digdag v0.10.1
  Creating backup-dag/backup-dag.dig
  Creating backup-dag/.gitignore
Done. Type `cd backup-dag` and then `digdag run backup-dag.dig` to run the workflow. Enjoy!
```

以下のようなdigファイルを作成

```
timezone: Asia/Tokyo

_export:
  redmine_backup_script: ./bin/backup_redmine.sh
  mail:
    from: "xxxxx@yyyyy.com"
    host: "smtp.yyyyy.com"
    port: 25

schedule:
  daily>: 04:00:00

+setup:
  echo>: start ${session_time}

+backup_redmine:
  sh>: ${redmine_backup_script}

+teardown:
  echo>: finish ${session_time}

_error:
  mail>:
    data: "Redmineのバックアップ取得に失敗しました。"
  subject: "【エラー通知】バックアップ取得失敗"
  to: [zzzzz@yyyyy.com]
```

* `schedule`を定義し、ワークフローを実行するスケジュールを指定
* `_error`を定義することで、タスク失敗時にアラート通知などの処理を実行できる

プロジェクトのディレクトリ配下のファイル

```
.
├── backup-dag.dig
└── bin
    └── backup_redmine.sh
```

## セッションについての注意事項

ワークフローを1回実行した後、2回目を実行すると各タスクがスキップされてしまった。

```
2021-07-29 00:31:48 +0000 [WARN] (0016@[0:default]+backup-dag+setup): Skipped
2021-07-29 00:31:49 +0000 [WARN] (0016@[0:default]+backup-dag+backup_redmine): Skipped
```

ググったところ、以下記事に説明があった。

https://qiita.com/toyama0919/items/2b1a7729d9a9b7be4900

> --sessionには引数として、
>
> - `hourly`
> - `daily`
> - `last`
> - `"yyyy-MM-dd"` 
> - `"yyyy-MM-dd HH:mm:SS"`
>
> が指定可能。
> この--sessionのデフォルト値はlast(最後に実行されたセッションを適用)になるため、2回め以降の実行は永久にスキップされてしまう。

全てのタスクを実行したい場合は`-a`を指定すればいい。

## スケジューラーの起動

[Running scheduler](https://docs.digdag.io/scheduling_workflow.html#running-scheduler)を参考に、実施。

```
$ digdag scheduler
2021-07-29 02:17:10 +0000: Digdag v0.10.1
2021-07-29 02:17:12 +0000 [INFO] (main): secret encryption engine: disabled
2021-07-29 02:17:13 +0000 [INFO] (main): Added new revision 1
2021-07-29 02:17:13 +0000 [INFO] (main): XNIO version 3.3.8.Final
2021-07-29 02:17:13 +0000 [INFO] (main): XNIO NIO Implementation Version 3.3.8.Final
2021-07-29 02:17:13 +0000 [INFO] (main): Starting server on 127.0.0.1:65432
2021-07-29 02:17:13 +0000 [INFO] (main): Bound on 127.0.0.1:65432 (api)
```

バックグラウンドで動いてくれることを期待したが、違うらしい。
なので、セッションを作成し、そこでスケジューラーを起動する。

```
$ screen -S digdag-scheduler
```

```
$ digdag scheduler
2021-07-29 03:13:17 +0000: Digdag v0.10.1
2021-07-29 03:13:19 +0000 [INFO] (main): secret encryption engine: disabled
2021-07-29 03:13:20 +0000 [INFO] (main): Added new revision 1
2021-07-29 03:13:20 +0000 [INFO] (main): XNIO version 3.3.8.Final
2021-07-29 03:13:20 +0000 [INFO] (main): XNIO NIO Implementation Version 3.3.8.Final
2021-07-29 03:13:20 +0000 [INFO] (main): Starting server on 127.0.0.1:65432
2021-07-29 03:13:20 +0000 [INFO] (main): Bound on 127.0.0.1:65432 (api)
```

これで、サーバーからログアウトしてもスケジューラーが動いてくれる。
ただし、サーバーが再起動した場合は、再度セッションを作成しスケジューラーを起動する必要がある。
なので、スケジューラーをsystemdでデーモン化してみることにした。

### schedulerのデーモン化

以下記事を参考に実施してみる。
https://qiita.com/vukujin/items/68d0957d7ac3c1dec977

`digdaag-scheduler`ユーザーを作成

```
$ sudo useradd digdag-scheduler
```

`/etc/digdag-scheduler`を作成し、プロジェクトディレクトリを配置

```
$ sudo cp -r ~/backup-dag/ /etc/digdag-scheduler
$ sudo chown -R digdag-scheduler:digdag-scheduler /etc/digdag-scheduler/backup-dag/
```

ワークフロー配下で実行するコマンドも`/usr/local/bin`に移動

```
$ sudo mv /etc/digdag-scheduler/backup-dag/bin/backup_redmine.sh /usr/local/bin/
```

ファイルの移動に合わせて、digファイルを編集

```
timezone: Asia/Tokyo

_export:
  redmine_backup_script: /usr/local/bin/backup_redmine.sh
  mail:
    from: "xxxxx@yyyyy.com"
    host: "smtp.yyyyy.com"
    port: 25

schedule:
  daily>: 04:00:00

+setup:
  echo>: start ${session_time}

+backup_redmine:
  sh>: ${redmine_backup_script}

+teardown:
  echo>: finish ${session_time}

_error:
  mail>:
    data: "Redmineのバックアップ取得に失敗しました。"
  subject: "【エラー通知】バックアップ取得失敗"
  to: [zzzzz@yyyyy.com]
```

unit定義の作成

```
$ sudo vim /etc/systemd/system/digdaag-scheduler.service
$ sudo chmod +x /etc/systemd/system/digdaag-scheduler.service
$ ll /etc/systemd/system/digdaag-scheduler.service
-rwxr-xr-x 1 root root 358 Jul 30 02:14 /etc/systemd/system/digdaag-scheduler.service*
$ sudo systemctl enable digdag-scheduler.service 
Created symlink /etc/systemd/system/multi-user.target.wants/digdag-scheduler.service → /etc/systemd/system/digdag-scheduler.service.
$ sudo systemctl start digdag-scheduler.service
```

`/etc/systemd/system/digdaag-scheduler.service`は以下の通り

```
[Unit]
Description=digdag-scheduler

[Service]
Type=simple
User=digdag-scheduler
Restart=always
RestartSec=5
TimeoutStartSec=30s
KillMode=process

ExecStart=/bin/bash /usr/local/bin/digdag sched --project /etc/digdag-scheduler/backup-dag --log /var/log/digdag-scheduler.log

[Install]
WantedBy=multi-user.target
```

スケジュールを変更し、ワークフローを実行させてみる。

```
$ systemctl status digdag-scheduler.service 
● digdag-scheduler.service - digdag-scheduler
   Loaded: loaded (/etc/systemd/system/digdag-scheduler.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2021-07-30 05:13:57 UTC; 38s ago
 Main PID: 7747 (java)
    Tasks: 25 (limit: 4704)
   CGroup: /system.slice/digdag-scheduler.service
           └─7747 java -Dio.digdag.cli.launcher=selfrun -XX:+AggressiveOpts -XX:TieredStopAtLevel=1 -Xverify:none -Djdk.attach.allowAttachSelf=true -jar /usr

... snip ...

Jul 30 05:14:31 ansible-01 bash[7747]: finish 2021-07-30T00:00:00+09:00
```

ワークフローが実行されることを確認できた！

本記事は以上となります。

[^1]: http://docs.digdag.io/getting_started.html#
[^2]: http://docs.digdag.io/getting_started.html#got-error