Fluent Bitをミニマムな構成でKubernetes環境にデプロイする

# TL;DR

Fluent Bitをミニマムな構成でKubernetes環境にデプロイしてみました。
この記事ではデプロイ方法について解説します。

この記事で取り扱うデプロイ設定やマニフェストファイルは以下のリポジトリにあります。
Github: https://github.com/cacapouh/fluentbit-minimum-example

# デプロイ周りの構成

簡単なPythonアプリをKubernetes環境にデプロイして、
PythonアプリのコンテナログをFluent Bitで取り扱うようにします。

# サンプルアプリ

サンプルアプリとして、1秒に1回`Count ${カウント値}`を標準出力するものをデプロイします。
以下はPythonスクリプトとDockerfileです。

```python:main.py
import time

if __name__ == '__main__':
    count = 0
    while True:
        count += 1
        print("Count {}".format(count))
        time.sleep(1)
```

```Dockerfile
FROM python:3.9.18-slim

RUN mkdir /work
WORKDIR /work

COPY main.py /work
ENTRYPOINT python -u main.py
```

## サンプルアプリのビルド

```shell
docker build -t simple-app .
minikube image load simple-app:latest # Minikube環境の場合
```

## マニフェスト

以下はサンプルアプリのマニフェストです。

```yaml:deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-app-deployment
  labels:
    app: simple-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: simple-app
  template:
    metadata:
      labels:
        app: simple-app
    spec:
      containers:
        - name: simple-app
          image: "simple-app:latest"
          imagePullPolicy: IfNotPresent
```

以下はマニフェスト適用結果です。

```
$ kubectl apply -f deployment.yml
deployment.apps/simple-app-deployment created

$ kubectl get pods
NAME                                    READY   STATUS    RESTARTS   AGE
simple-app-deployment-dd44b5ff4-2zhps   1/1     Running   0          5s
simple-app-deployment-dd44b5ff4-58bg4   1/1     Running   0          5s

$ kubectl logs simple-app-deployment-dd44b5ff4-2zhps 
Count 1
Count 2
Count 3
Count 4
Count 5
Count 6
Count 7
Count 8
Count 9
Count 10
Count 11
Count 12
Count 13
Count 14
```

# Fluent Bitのマニフェストファイルの雛形を用意

Fluent Bitをデプロイするためのマニフェストファイル等をHelmで生成します。
Helmについては以下の記事でも説明していますので、もし宜しければご一読お願いします。

https://qiita.com/tobita_yoshiki/items/b6c37681d43c6ac8a85a

https://qiita.com/tobita_yoshiki/items/ba0513a84c2c8e86f8dd

まず、Helm Chartを以下のコマンドで初期化します。

```shell:helm createコマンド
$ helm create fluent-bit
Creating fluent-bit

$ tree fluent-bit
fluent-bit
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
```

さまざまなファイルが生成されますが、不要なため、
`templates`ディレクトリ配下のファイルと`value.yaml`を削除します。

```shell
$ rm -rf fluent-bit/templates/* fluent-bit/values.yaml
```

次に、以下のコマンドで`tempmlate`ディレクトリ配下にFluent Bitのマニフェストファイルを配置します。[^1][^2]

```shell:helm templateコマンド
$ helm template fluent-bit fluent/fluent-bit | yq -s '.kind'
$ ls fluent-bit/templates
ClusterRole.yml		ClusterRoleBinding.yml	ConfigMap.yml		DaemonSet.yml		Pod.yml			Service.yml		ServiceAccount.yml
```

[^1]: `helm pull --untar fluent/fluent-bit`でもマニフェストファイルを配置することはできますが、不要なファイルもダウンロードされるため、今回は`helm template`コマンドを使用しました。
[^2]: YAMLを操作する[yqコマンド](https://mikefarah.gitbook.io/yq/)を使用しています

# Fluent Bitのマニフェストファイルを編集する

Fluent BitのマニフェストファイルをHelm経由で入手しますと、
ログ出力先がElastic Searchになっていたり、特有の設定が諸々あります。

今回はミニマムな構成でFluent Bitを動かしたいため、
以下のように雛形として生成した`ConfigMap.yaml`のみを編集します。

`data.fluent-bit.conf`のところで、
ログのINPUTをコンテナの標準出力に指定し、
OUTPUTをFluent Bitコンテナの標準出力にしています。

```yaml:ConfigMap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit
  namespace: default
  labels:
    helm.sh/chart: fluent-bit-0.42.0
    app.kubernetes.io/name: fluent-bit
    app.kubernetes.io/instance: fluent-bit
    app.kubernetes.io/version: "2.2.1"
    app.kubernetes.io/managed-by: Helm
data:
  fluent-bit.conf: |
    [SERVICE]
        HTTP_Server On
        HTTP_Listen 0.0.0.0
        HTTP_Port 2020
        Health_Check On

    [INPUT]
        Name tail
        Path /var/log/containers/*.log
        multiline.parser docker, cri
        Tag kube.*
        Mem_Buf_Limit 5MB
        Skip_Long_Lines On
    
    [OUTPUT]
        Name stdout
        Match *
```

# Fluent Bitのデプロイ

以下のコマンドでFluent Bitをデプロイします。

```
$ helm install fluent-bid-example ./fluent-bit
NAME: fluent-bid-example
LAST DEPLOYED: Tue Jan  9 21:29:38 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
```

以下、デプロイしたFluent BitのPodのログを確認しています。
`"log"=>"Count 249"`, `"log"=>"Count 250"`, ...とPythonの標準出力によって生成された文字列が確認できます。

```
$ kubectl get pods
NAME                                    READY   STATUS    RESTARTS   AGE
fluent-bit-dzqrr                        1/1     Running   0          30s
simple-app-deployment-dd44b5ff4-2zhps   1/1     Running   0          2m13s
simple-app-deployment-dd44b5ff4-58bg4   1/1     Running   0          2m13s

$ kubectl logs fluent-bit-dzqrr | tail      
[0] kube.var.log.containers.simple-app-deployment-dd44b5ff4-2zhps_default_simple-app-8964f46eb8eba5cedbc75be3b8e32c9dbdf182a3f87fd808f82e8e7d19113d30.log: [[1704803524.484566339, {}], {"log"=>"Count 249
", "stream"=>"stdout", "time"=>"2024-01-09T12:32:04.484566339Z"}]
[0] kube.var.log.containers.simple-app-deployment-dd44b5ff4-58bg4_default_simple-app-975041d1a419c97d7d8357b1523fd0cb5c1e2af870bae1a9d43d364a6a15a4fe.log: [[1704803525.484707964, {}], {"log"=>"Count 250
", "stream"=>"stdout", "time"=>"2024-01-09T12:32:05.484707964Z"}]
[0] kube.var.log.containers.simple-app-deployment-dd44b5ff4-2zhps_default_simple-app-8964f46eb8eba5cedbc75be3b8e32c9dbdf182a3f87fd808f82e8e7d19113d30.log: [[1704803525.487212964, {}], {"log"=>"Count 250
", "stream"=>"stdout", "time"=>"2024-01-09T12:32:05.487212964Z"}]
[0] kube.var.log.containers.simple-app-deployment-dd44b5ff4-58bg4_default_simple-app-975041d1a419c97d7d8357b1523fd0cb5c1e2af870bae1a9d43d364a6a15a4fe.log: [[1704803526.488146298, {}], {"log"=>"Count 251
", "stream"=>"stdout", "time"=>"2024-01-09T12:32:06.488146298Z"}]
[0] kube.var.log.containers.simple-app-deployment-dd44b5ff4-2zhps_default_simple-app-8964f46eb8eba5cedbc75be3b8e32c9dbdf182a3f87fd808f82e8e7d19113d30.log: [[1704803526.488614048, {}], {"log"=>"Count 251
", "stream"=>"stdout", "time"=>"2024-01-09T12:32:06.488614048Z"}]
```

# おわりに

Fluent BitでPythonのPodのログを確認することができました :thumbsup: