AmazonLinux2にAnsibleでtd-agent v4を入れる方法

# はじめに
新しく立てた`linux2`のインスタンスに`ansible`で`td-agent`の最新版を入れたのでその手順を記します。

# 目次
1. [対応バージョンの確認](#Chapter1)
1. [使用してるプラグインの確認](#Chapter2)
1. [playbookの作成](#Chapter3)
1. [playbookの実行](#Chapter4)
1. [動作確認](#Chapter5)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 1. 対応バージョンの確認

まず古い`linuxAMI`のEC2で使っていた既存の`td-agent`のバージョンを確認しました。
`td-agent v2`でした。中身は`fluentd v0.12`です。

```sh
$ td-agent --version
td-agent 0.12.40 # ここで表示されるのはtd-agent内部で使用されてるfluentdのバージョン
```

`td-agent`は`fluend`と呼ばれるクロスプラットフォームのオープンソースデータ収集ソフトを簡易に利用できるようにした安定版パッケージなので、中身は`fluentd`みたいです。
[td-agent と fluentd の違い](https://qiita.com/billthelizard/items/4c31428eeb114fb2c362)

tg-agentの公式サイトで現在の推奨バージョンを確認します。
[td-agent v2 vs v3 vs v4](https://docs.fluentd.org/quickstart/td-agent-v2-vs-v3-vs-v4)

v2はとても古いため`AmazonLinux2`は未対応。
> td-agent v2
This is for v0.12 and old distribution users. We don't recommend this version for new deployments.

v3は古い安定版で、内部で`Ruby2.4`が使用。
> td-agent v3
Old stable.
Ruby 2.4
Fluentd v1
Windows Support
Remove fluentd-ui from the package

v4は最新の安定版で、内部で`Ruby2.7`が使用。

> td-agent v4
New stable. Major feature updates to td-agent v4 are as follows:
Ruby 2.7
Fluentd v1
Arm64 Support
See also Changes from Treasure Agent 3.

ログ収集はユーザーの行動分析やサイトのモニタリングなどに使う非常に重要な処理なので、とりあえず最新の安定版を入れておこうと`td-agent v4`を使うことに決めました。

<a id="#Chapter2"></a>
# 2. 使用してるプラグインの確認

`td-agent`は、ログのフィルタリングができたり、ログのインプット、アウトプット先などを連携するプラグインに応じて変更するなど、柔軟にカスタマイズができるみたいです。

既存の`td-agent.conf`を読んで、[fluent-plugin-forest](https://github.com/tagomoris/fluent-plugin-forest)と[fluent-plugin-bigquery](https://github.com/fluent-plugins-nursery/fluent-plugin-bigquery)のプラグインが使われていることを確認しました。
これらも一旦今回のインスコ対象に含めることにしました。

<a id="#Chapter3"></a>
# 3. playbookの作成

今回は5台のサーバに入れる必要があったので、`ansbile`の`playbook`を作成しました。
手順書って理解するのに時間かかったり抜け漏れが怖かったりするし、再現性も担保されないから、こういう時に`playbook`がすぐ作れると便利だなと思いました。
ただ、`ansible`の書き方ってweb上にある記事を色々見た印象だと人によってもかなり違うし、`version`の違いで記法も変わるし、環境ごとに独自のやり方を取ってたりするので、他人の`playbook`をそのまま流用するのはほぼ不可能で、部分的に拝借してくっつけて利用するのが良いなという印象です。
（`AnsibleRole`化されてる場合は環境ごとの再現性も担保されてるはずなので使用しても問題ないはず）

## 参考までに自分が書いた`playbook`を掲載

```yml
- hosts: all
  vars_files:
    - vars/{{ inventory_hostname }}.yml
  any_errors_fatal: true
  gather_facts: no
  user: my_user
  become: true
  tasks:
    - name: test
      debug:
        msg: "接続先ホスト名： {{ inventory_hostname }}"

    - name: Create my_user_keys directory for td-agent
      file: path="/home/my_user/my_user_keys" state=directory owner=my_user group=my_user mode=0775

    - name: Put my_user_key.json
      template: src=my_user_key.j2 dest=/home/my_user/my_user_keys/my_user_key.json backup=true owner=my_user group=my_user mode=0644

    - name: Install td-agent v4
      shell:
        cmd: /bin/bash -lc "curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent4.sh | sh"
      become: yes

    - name: Put action_schema.json
      template: src=td-agent/action_schema.json.j2 dest=/etc/td-agent/action_schema.json backup=true owner=my_user group=my_user mode=0644

    - name: Put td-agent.conf
      template: src=td-agent/td-agent.conf.j2 dest=/etc/td-agent/td-agent.conf backup=true owner=my_user group=my_user mode=0644

    - name: Install td-agent-gem plugin fluent-plugin-bigquery
      shell:
        cmd: /bin/bash -lc "td-agent-gem install fluent-plugin-bigquery"
      become: yes

    - name: Install td-agent-gem plugin fluent-plugin-forest
      shell:
        cmd: /bin/bash -lc "td-agent-gem install fluent-plugin-forest"
      become: yes

    - name: Setting root user
      lineinfile:
        dest: /usr/lib/systemd/system/td-agent.service
        backrefs: yes
        regexp: ^User=
        line: User=root
        state: present

    - name: Setting root group
      lineinfile:
        dest: /usr/lib/systemd/system/td-agent.service
        backrefs: yes
        regexp: ^Group=
        line: Group=root
        state: present

    - name: Enabled and Running td-agent
      systemd:
        name: td-agent
        daemon_reload: yes
        state: restarted
        enabled: yes
```

## `playbook`の解説

- `td-agent`のインスコ前に、`Bigquery`との接続のために使う`ApiKey`を配置してます。
- `AmazonLinux2`用の`td-agent v4`インストールコマンドは[公式](https://docs.fluentd.org/installation/install-by-rpm#amazon-linux)にあります。
- `td-agent`のインスコ後は、ログのスキーマ定義用のjsonファイルと設定ファイルを配置してます。
- その後、`td-agent-gem`コマンドを使ってプラグインをインスコしてます。
- `td-agent`の実行ユーザーを`td-agent`でなく`root`に変更したくて、起動時に読み込んでる`systemd`のファイルを`lineinfile`モジュールを使って書き換えてます。
- 書き換え処理が終わったら`daemon_reload`で設定を読み込んだあと、リスタートさせてます。

## ハマりポイント

- conf内で使ってるプラグイン(`td-agent-gem`)が入っていないと、こういうエラーがでます。プラグイン依存をやめてconfを書き換えれる場合はそのほうがいいですが、ダメならプラグインを入れましょう。

`fluent/log.rb:369:error: config error file="/etc/td-agent/td-agent.conf" error_class=Fluent::ConfigError error="Unknown output plugin 'forest'. Run 'gem search -rd fluent-plugin' to find plugins"`

今回入れたプラグイン

```sh
$ td-agent-gem list
fluent-plugin-bigquery (2.2.0)
fluent-plugin-forest (0.3.3)
```

- バージョン確認の省略コマンドはない

`$ td-agent -v`でバージョン確認しようとするとなぜかバージョンが表示されず`stdout`にログが垂れ流されてきて謎だったんですが、単にコマンドが`--version`しかないだけでした。

この時、`fluent/log.rb:369:error: unexpected error error_class=Errno::EADDRINUSE error="Address already in use - bind(2) for 0.0.0.0:24224"`
というエラーが出て24224ポートが既に使用中なのだと勘違いし、よくあるエラーか？と[この記事](https://chiarab.hatenablog.com/entry/2018/11/05/000803)を見ながらプロセスを消して立ち上げ直したりなどしてましたが徒労でした。

- 実行ユーザーを`root`に変更

最初にお試し導入したときに実行ログを眺めてると、このようなエラーに出会いました。

`fluent/log.rb:369:error: unexpected error on reading data host="127.0.0.1" port=54444 error_class=Fluent::Plugin::Buffer::BufferOverflowError error="can't create buffer file for /var/log/td-agent/buffer/action_rack/buffer.*.log. Stop creating buffer files: error = Permission denied @ rb_sysopen - /var/log/td-agent/buffer/action_rack/buffer.b5b62c41c60856775a9a0b08a26f55fac.log"`

`/var/log`の所有者は`root`ユーザーなので、`Permission denied`で`Buffer`ファイルの生成に失敗してるようです。

[td-agent で /var/log/messages の情報を読み込めない](https://www.oresamalabo.net/entry/2019/03/09/120747)の記事を参考にしつつ、`td-agent`の実行ユーザーがデフォルトだと`td-agent`になっているのを`root`に修正することにしました。

```sh
# 起動時に読み込んでるファイルを確認するためにstatusを開く
$ sudo systemctl status td-agent.service

● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
   Loaded: loaded (/usr/lib/systemd/system/td-agent.service; enabled; vendor preset: disabled) # ここが起動時設定ファイル
   Active: active (running) since 金 2020-12-11 19:19:55 JST; 11h ago
     Docs: https://docs.treasuredata.com/articles/td-agent
  Process: 5133 ExecStop=/bin/kill -TERM ${MAINPID} (code=exited, status=0/SUCCESS)
  Process: 5142 ExecStart=/opt/td-agent/bin/fluentd --log $TD_AGENT_LOG_FILE --daemon /var/run/td-agent/td-agent.pid $TD_AGENT_OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 5151 (fluentd)
   CGroup: /system.slice/td-agent.service
           ├─5151 /opt/td-agent/bin/ruby /opt/td-agent/bin/fluentd --log /var/log/td-agent/td-agent....
           └─5154 /opt/td-agent/bin/ruby -Eascii-8bit:ascii-8bit /opt/td-agent/bin/fluentd --log /va...
```

上記の`systemd`の設定ファイル内に`User=td-agent`、`Group=td-agent`と記載されてるので、そこを`ansible`の`lineinfile`を使って正規表現検索をかけて、`root`に書き換えます。
そして、設定ファイルを再度読み込ませるために`deamon_reload`して`restart`すれば`root`で実行されるので解決です。
（ちなみに`ansible`の`service`モジュールでは`deamon_reload`はできず、`systemd`モジュールが完全に上位互換に見えたので、サービスの自動起動設定などの際は`systemd`モジュールを使うのがオススメです。）

<a id="#Chapter4"></a>
# 4. playbookの実行
`td-agent v4`（`fluentd v1.11.2`）が無事インストールされました。

```sh
$ td-agent --version
td-agent 1.11.2
```

<a id="#Chapter5"></a>
# 5. 動作確認

## ログの確認

```sh
$ tail -f /var/log/td-agent/td-agent.log
```

## Bigqueryでの計測データ確認

```SQL
SELECT FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', TIMESTAMP_SECONDS(time), 'Asia/Tokyo') AS date, message FROM `my_project.my_dataset.action_rack_20201211` ORDER By date DESC limit 100
```

両方に問題なければおkです。
おしまい

（余談：td-agentがエラーを吐いたときにアラートを出す仕組みがあるとよさそうです。ログ欠損怖い。）

<a id="#reference"></a>
# 参考文献
- [td-agent と fluentd の違い](https://qiita.com/billthelizard/items/4c31428eeb114fb2c362)
- [td-agent v2 vs v3 vs v4](https://docs.fluentd.org/quickstart/td-agent-v2-vs-v3-vs-v4)
- [fluentd公式：AmazonLinux2用インストールコマンド](https://docs.fluentd.org/installation/install-by-rpm#amazon-linux)
- [【トラブル対応】td-agent(fluentd) 再起動時の "Address already in use" エラー](https://chiarab.hatenablog.com/entry/2018/11/05/000803)
- [td-agent で /var/log/messages の情報を読み込めない](https://www.oresamalabo.net/entry/2019/03/09/120747)