Ansible Tower / AWX + Borg Backup でバックアップサーバを作る

## はじめに

私の身の回りではサーバのバックアップに [Bacula](https://www.bacula.jp/) という OSS を使ってきました。古くからの SE の方でしたら Arcserve Backup 似と言えば伝わるでしょうか？マネージャ、エージェント、ストレージサーバ、クライアント等のいくつかのコンポーネントで構成された、テープデバイスも扱える高機能なバックアップソフトウェアです。

時は流れて、もう身の回りでテープデバイスを見る事がなくなりました。バックアップツールも様々な物が登場する中で、ある時 [Borg Backup](https://borgbackup.readthedocs.io/en/stable/) を見つけました ([Qiita記事](https://qiita.com/syogun/items/1f75812e822fccfb7612))。コマンドラインベースながらも以下のような機能を実装した優れものです。

* 差分バックアップ
* バックアップアーカイブの暗号化(パスワード付)
* SSH 経由でリモートサーバ上にバックアップアーカイブ作成

これと Ansible Tower (or AWX) を組み合わせたら、Bacula 要らないんじゃね？と思っていろいろやってみました。

## Ansible Tower / AWX + Borg Backup を用いた定期バックアップにおける考察

既存の Borg Backup 用 Ansible role は、主に cron ジョブを登録して各ホストが個別にバックアップを実行するものばかりでした。これでは、複数(場合によっては多数)のホストが同時にバックアップを実施する可能性があり、以下の問題があります。

* ネットワーク経由のバックアップで通信帯域を占有する。
    * バックアップの専用回線がない場合、他のサービスの通信に影響を及ぼす可能性がある。
* 通信帯域やバックアップ先のディスク性能等の制約により、各ホストのバックアップ実行時間が長くなる。
    * DB のスナップショット等を考えると、１ホスト上のバックアップジョブは可能な限り短時間で実施すべき。
* バックアップサーバ側の準備が整う前にクライアント側のバックアップが実施される。

こうした問題を回避するため、通常のバックアップソフトウェアでは複数ホストからのネットワーク経由バックアップジョブやリストアジョブはシリアライズする（＝同時実行しない）ようになっています。これを Ansible Tower / AWX で行うためには、バックアップジョブをホスト単位に小分けし、ジョブを同時実行しないように設定する事で実現できます。バックアップサーバ側の準備等も考慮すると、ワークフローも使用したほうが良いでしょう。

## 前提条件

1. バックアップアーカイブを保持する Linux ホスト(=ストレージサーバ)があること
2. バックアップ元の Linux ホスト(=バックアップ元クライアント)があること
3. 1, 2 にアクセス可能な Ansible Tower 又は AWX 環境が利用できること
4. 3 から 1, 2 にアクセスする際の OS アカウントはパスワードなしで sudo できること
5. 3 と連携可能なソースコードリポジトリ(GitHub, GitLab等)が利用できること

## 事前準備

1. https://github.com/yosshy/awx-project-borgbackup にある Git アーカイブを上記のソースコードリポジトリにコピーします。
2. 1 のリポジトリをプロジェクトとして登録します。
3. バックアップサーバ、バックアップクライアントを含むインベントリを新規作成します。
   インベントリには２つのグループ(servers, clients)を作成します。
     * servers グループにはバックアップサーバホスト(1台で結構です)を登録します。
     * clients グループにはバックアップクライアントホスト群を登録します。
       （現時点の 1 で clients グループ自体は利用されていません）
4. 3 のホスト群へのアクセス用認証情報を登録します。
5. 2～4 を使用するバックアップサーバ用テンプレートを新規作成します。![server.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/f0884ff3-a7a9-42e2-ba4a-55a753397266.png)
   * 名前： (バックアップサーバのジョブテンプレートである事が判る適切な名前)
   * ジョブタイプ：実行
   * インベントリー：3 で作成したインベントリ名
   * プロジェクト：2 で作成したプロジェクト名
   * PLAYBOOK：server.yml
   * 認証情報：4 で作成した認証情報名
   * 制限：servers
   * オプション：権限昇格の有効化
   * 追加変数：YAML にて以下の要領で記載

        ```yaml
        ---
        borgbackup_install_from_repo: True
        borgbackup_install_from_binary: False
        ```

6. 2～4 を使用するテンプレートを【ホスト毎に】新規作成します。 ![client1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/515a6323-5ba5-48f2-b500-deeb16f08467.png)
   * 名前： (ホスト名が判る適切な名前)
   * ジョブタイプ：実行
   * インベントリー：3 で作成したインベントリ名
   * プロジェクト：2 で作成したプロジェクト名
   * PLAYBOOK：client.yml
   * 認証情報：4 で作成した認証情報名
   * 制限：（ホスト名）
   * オプション：権限昇格の有効化
   * 追加変数：YAML にて以下の要領で記載

        ```yaml
        ---
        borgbackup_prune_enabled: False
        borgbackup_install_from_repo: True
        borgbackup_install_from_binary: False
        borgbackup_client_backup_server: (バックアップサーバのIPアドレス)
        borgbackup_client_jobs:
          - name: system
            directories:
              - /etc
              - /home
              - /var
            excludes:
              - 're:^/var/lib/apt'
              - 're:^/var/[^/]+\/cache/'
        borgbackup_prune_jobs:
          - name: system
            prune_options: "--keep-daily=7 --keep-weekly=4"
        ```

7. 以下の要領で 5～6 を使用するワークフローを作成します。
   こんな感じです。![workflow.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/f0bd2b52-605e-875d-f7aa-16ca7f8816ea.png)
   * 最初 5 のテンプレートのみ実行
   * 上記ジョブ成功時に 6 の各ジョブを実行

## テスト

1. 7 で作ったワークフローを実行します。![run.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/de191c90-fbbb-283d-7375-90e5466c0d91.png)
   エラーが無ければ複数回実行しましょう。
2. クライアントホストにログインしてバックアップを確認します。
   バックアップスクリプトは /etc/borg/<バックアップジョブ名>.sh にあります。![shell.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/059fe3a5-9903-a342-d843-929b0c1a9340.png)

## テスト後の設定変更

1. 複数のバックアップが確認できた後、各クライアントジョブテンプレートの borgbackup_prune_enabled を True に変更します。これにより prune が実行され、毎日最終のバックアップのみに集約されるとともに、古いバックアップが自動削除されるようになります。
2. 7 のワークフローにスケジュールを設定します。![schedule.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58075/7ba2be32-2b5c-276b-36fa-197746e8e854.png)