Fluent Bit で Pub/Sub にログ転送する

コンテナが出力するログを Fluent Bit で Pub/Sub に転送する方法を紹介します。
（業務で使用予定だったのですが、ひとまず不要になったため Qiita で供養。）

# 概観
Fluent Bit は NGINX から受け取ったアクセスログを Pub/Sub に転送します。
Pub/Sub への転送には、後述する Plugin を利用します。
![fluent-bit-pubsub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/97efae73-dd2b-56c7-9c78-9f7b53212c43.png)



# 準備
### サービスアカウントキー取得

```
# サービスアカウント作成
$ gcloud iam service-accounts create fluent-bit-publisher

# ロールを紐付け
$ gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member=serviceAccount:fluent-bit-publisher@<PROJECT_ID>.iam.gserviceaccount.com \
  --role=roles/pubsub.publisher

# サービスアカウントキーを取得
$ gcloud iam service-accounts keys create jwt.json \
  --iam-account fluent-bit-publisher@<PROJECT_ID>.iam.gserviceaccount.com
```

### Pub/Sub 作成

```
# トピック作成
$ gcloud pubsub topics create fluent-bit-topic

# サブスクリプション(pull型)を作成 
$ gcloud pubsub subscriptions create --topic fluent-bit-topic fluent-bit-subscription
```

### ローカル環境用意

必要なファイルは下記の通りです。

```
.
├── docker-compose.yml
├── fluent-bit.conf
├── jwt.json
└── pubsub.so
```

・docker-compose.yml
NGINX の[ロギングドライバ](https://docs.docker.jp/engine/admin/logging/fluentd.html)を `fluentd` に設定します。
Fluent Bit は [Plugin を有効にするオプション](https://docs.fluentbit.io/manual/development/golang-output-plugins#run-fluent-bit-with-the-new-plugin)を付加して実行します。


```docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:latest
    ports:
      - "8888:80" 
    depends_on:
      - fluent-bit
    command: [nginx-debug, '-g', 'daemon off;']
    logging:
      driver: fluentd
      options:
        fluentd-address: "localhost:24224"
        fluentd-async-connect: "false"
  fluent-bit:
    image: fluent/fluent-bit
    volumes:
        - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
        - ./pubsub.so:/pubsub.so
        - ./jwt.json:/jwt.json
    ports:
      - "24224:24224"
    # overwrite default command
    command: /fluent-bit/bin/fluent-bit -c /fluent-bit/etc/fluent-bit.conf -e /pubsub.so 

```

・fluent-bit.conf
入力や出力先を定義する[設定ファイル](https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/configuration-file)です。
Fluent Bit の出力先には、標準出力と Pub/Sub を設定します。

```fluent-bit.conf
[SERVICE]
    Log_Level       info

[INPUT]
    Name    forward
    Listen  0.0.0.0
    Port    24224

[OUTPUT]
    Name stdout
    Match *

[OUTPUT]
    Name pubsub
    Match *
    Project <PROJECT_ID> # 自身のIDに置き換え
    Topic fluent-bit-topic
    Jwtpath /jwt.json

```

・pubsub.so
Pub/Sub に転送するための Plugin です。
下記リポジトリから `/bin/linux_amd64/pubsub.so` をダウンロードするか、clone してビルドしてください。

https://github.com/sasamuku/fluent-bit-pubsub

※ [こちら](https://github.com/gjbae1212/fluent-bit-pubsub)から取得したバイナリだと次のようなエラーが発生したため fork して修正しています。
`panic: interface conversion: interface {} is uint64, not output.FLBTime`


・jwt.json
前述の手順でダウンロードしたサービスアカウントキーになります。

# 試してみる

コンテナを立ち上げます。

```
$ docker-compose up -d
Creating fluent-bit-pubsub-test_fluent-bit_1 ... done
Creating fluent-bit-pubsub-test_nginx_1      ... done
```

ログの出力を待機させます。

```
$ docker-compose logs -f
```

NGINX にアクセスログを出力させます。

```
$ curl http://localhost:8888/
```

下記のようなログが出力されます。標準出力には問題なく出力されることが確認できました。

```
$ docker-compose logs -f
...
nginx_1       | 172.29.0.1 - - [07/Dec/2021:09:09:33 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.64.1" "-"
fluent-bit_1  | [0] 0d26bb84569f: [1638868173.000000000, {"container_id"=>"0d26bb84569fd06bd74efe4afd9cc9f4ff927987101f4f1aab8aa0ff85c86247", "container_name"=>"/fluent-bit-pubsub-test_nginx_1", "source"=>"stdout", "log"=>"172.29.0.1 - - [07/Dec/2021:09:09:33 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.64.1" "-""}]
```

続いて、Pub/Sub にも出力されていることを確認します。
GCP コンソールより、`Pub/Sub` -> `サブスクリプション` -> `fluent-bit-subscription` -> `メッセージ` -> `PULL` を押していくと、下図のようにメッセージを受信していることを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619762/532effed-7c19-ab4d-ec04-32c140c17c01.png)

# 参考
- https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit
- https://www.nullpo.io/2021/05/21/logging-docker-compose-fluent-bit/
- https://onigra.github.io/blog/2020/05/02/try-fluent-bit-on-docker/