Tanzu Kubernete Grid上にTanzu PackageでFluent Bitをインストール＆動作確認をする

Tanzu Kubernete Grid(TKG)のクラスタにTanzu Packageを利用してFluent Bitをインストールしてログが転送できることを確認をする。
最初にrsyslog環境を構築し、その後にTanzu CLIでFluent Bitを構築する。\
そのため、rsyslogの構築以外はTKGの利用が前提となる。なお、ここではTKGm1.6.0で確認している。

## rsyslog環境(Pod,Service)の構築
動作確認用にrsyslogサーバをコンテナで立てる。[オフィシャルの手順](https://www.rsyslog.com/doc/master/installation/rsyslog_docker.html)だと`rsyslog/syslog_appliance_alpine`イメージを使うことになっているが、こちらは実験的な扱いで5年前に更新が止まっているので、イメージを自作した方がよい。
ここでは[Run Rsyslog server in Kubernetes](https://itnext.io/run-rsyslog-server-in-kubernetes-bb51a7a6e227)というサイトにあったDockerfileをベースにログの出力先だけ変更してイメージを作成した。
```dockerfile
MY_REGISTRY="core.harbor.hogeeee.info"
MY_REPOSITORY="${MY_REGISTRY}/myapp"
cat << 'EOF' > Dockerfile
FROM ubuntu
RUN apt update && apt install rsyslog -y
RUN echo '$ModLoad imudp \n\
$UDPServerRun 514 \n\
$ModLoad imtcp \n\
$InputTCPServerRun 514 \n\
$template RemoteStore, "/var/log/remote.log" \n\
:source, !isequal, "localhost" -?RemoteStore \n\
:source, isequal, "last" ~ ' > /etc/rsyslog.conf
ENTRYPOINT ["rsyslogd", "-n"]
EOF
docker build -t ${MY_REPOSITORY}/rsyslog .
```
イメージをリポジトリにPushする
```sh
docker push ${MY_REPOSITORY}/rsyslog
```

Namespaceを作成し、PushしたイメージをPull出来るようにSecretやServiceAccountを設定する。
```sh
kubectl create ns rsyslog
kubectl create secret docker-registry harbor-cred --docker-password 'xxxxxx' --docker-username imurata --docker-server $MY_REGISTRY -n rsyslog
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-cred"}]}' -n rsyslog
```


作成したイメージを使ってPodとServiceを作成する。今回、LoadBalancerが使える環境で試しているため、Serviceのtypeは`LoadBalancer`にしているが、環境に応じて適宜変更して問題ない。
```yaml 
cat << EOF > rsyslog.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: rsyslog
  name: rsyslog
spec:
  containers:
  - name: rsyslog
    image: $MY_REPOSITORY/rsyslog:latest
    ports:
    - containerPort: 514
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: rsyslog
  name: rsyslog
spec:
  ports:
  - port: 514
    targetPort: 514
    protocol: TCP
  selector:
    run: rsyslog
  type: LoadBalancer
EOF
kubectl apply -f ./rsyslog.yaml -n rsyslog
```

動作確認のためにsyslogにログを飛ばす。こちらも先程の[Run Rsyslog server in Kubernetes](https://itnext.io/run-rsyslog-server-in-kubernetes-bb51a7a6e227)にあった動作確認方法を流用する。`tcp://`の部分で作成したServiceのExternalIPを引っこ抜いているが、NodePort等で作成した人は自環境のIPなどに別途置きかえる必要がある。
```sh
$ docker run --log-driver syslog --log-opt syslog-address=tcp://$(kubectl get svc -o jsonpath={.status.loadBalancer.ingress[0].ip} rsyslog -n rsyslog):514 alpine echo hello world
hello world
```
'24/9/2追記：
`--log-driver syslog`でエラーになる場合は`--log-driver journald`に変更すると上手く行くかもしれない。

なお正常に接続できない場合はhello worldが返らないので、その際はリーチャビリティやPod、Serviceの状態を確認する。
ちなみに[Finch](https://github.com/runfinch/finch)だとsyslog転送はサポートしていないようで、正常に接続できなくてもhello worldが返るので注意（自分が少しはまった）。
正常に転送できた場合、以下のようにログが取得できる。
```sh
$ kubectl exec -it rsyslog -n rsyslog -- cat /var/log/remote.log
2023-01-09T16:10:31+00:00 192.168.2.1 2e8a45b6a298[1364]: hello world
```

## Fluent Bitのインストール＆動作確認
TKG1.6の[Fluent Bitのページ](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.6/vmware-tanzu-kubernetes-grid-16/GUID-packages-logging-fluentbit.html)を見ながら試していく。

利用可能なFluent Bitのバージョンを確認する。
```sh
tanzu package available list fluent-bit.tanzu.vmware.com -A
```
今回は1.8.15+vmware.1-tkg.1が最新版だったため、こちらを利用して構築する。
次に設定ファイル`fluent-bit-default-values.yaml`を抽出する。
```sh
FB_VERSION="1.8.15+vmware.1-tkg.1"
tanzu package available get fluent-bit.tanzu.vmware.com/$FB_VERSION --generate-default-values-file
```
次に設定ファイルを変更するのだが、オフィシャルドキュメントの記載が不親切すぎるので、あまりドキュメントは当てにせずに書いていく。
修正後の`fluent-bit-default-values.yaml`は以下のようになった。
```yaml
---
fluent_bit:
  config:
    service: |
      [SERVICE]
        Daemon              Off
        Flush                1
        Log_Level            info
        Parsers_File         parsers.conf
        Health_Check         On
    inputs: |
      [INPUT]
        Name                 tail
        Path                 /var/log/containers/*.log
        DB                   /var/log/flb_kube.db
        parser               cri
        Tag                  kube.*
        Mem_Buf_Limit        5MB
        Skip_Long_Lines      On
    parsers: |
      [PARSER]
        # http://rubular.com/r/tjUt3Awgg4
        Name                 cri
        Format               regex
        Regex                ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$
        Time_Key             time
        Time_Format          %Y-%m-%dT%H:%M:%S.%L%z
    filters: |
      [FILTER]
        Name                 kubernetes
        Match                kube.*
        Kube_URL             https://kubernetes.default.svc.cluster.local:443
        Kube_CA_File         /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        Kube_Token_File      /var/run/secrets/kubernetes.io/serviceaccount/token
        Kube_Tag_Prefix      kube.var.log.containers.
        Merge_Log            On
        Merge_Log_Key        log_processed
        Keep_Log             Off
        K8S-Logging.Parser   On
        K8S-Logging.Exclude  On
    outputs: |
      [OUTPUT]
        Name                 syslog
        Match                *
        Host                 10.220.24.43
        Port                 514
        Mode                 tcp
        Syslog_Format        rfc5424
        Syslog_Hostname_key  tkg_cluster
        Syslog_Appname_key   pod_name
        Syslog_Procid_key    container_name
        Syslog_Message_key   message
        syslog_msgid_key     msgid
        Syslog_SD_key        k8s
        Syslog_SD_key        labels
        Syslog_SD_key        annotations
namespace: tanzu-system-logging
```
詳細は割愛するが、Fluent BitではInput, Parser, Filter, Outputで入出力の流れを定義するので、その設定を[Fluent Bitのマニュアル](https://docs.fluentbit.io/manual/pipeline/pipeline-monitoring)等を見ながら設定していく。TKGのマニュアルを見ても書けないのであまり参考にしなくてよい。\
よく分からない人はコピペして、`[OUTPUT]`の`Host`は自環境のsyslogのIPやホスト名に変更すれば動くはず。
なお、TKGでTanzu Packageを利用する際の全般的な注意点として、設定ファイルの先頭に`---`がないとエラーになることがあるので注意すること（今回も追記している）。
また、`[SERVICE]`に`HTTP_Server On`を追記しないとreadiness probeに引っかかって動かなかったとの報告を頂いた。
同様の現象になった場合は、その設定を追記して試すことをオススメする。

修正後の`fluent-bit-default-values.yaml`を使ってFluent Bitパッケージのインストールを行う。
```sh
NAMESPACE="my-packages"
tanzu package install fluent-bit \
--package-name fluent-bit.tanzu.vmware.com \
--version $FB_VERSION \
--values-file fluent-bit-default-values.yaml \
--namespace $NAMESPACE --create-namespace
```
上手くいくと、インストール中に以下のようなメッセージがsyslogで確認出来る。
```sh
$ kubectl exec -it rsyslog -- tail -f /var/log/remote.log
：（省略）
2023-01-09T10:05:01.465345Z - - {"level":"warn","ts":"2023-01-09T10:05:01.465Z","caller":"etcdserver/util.go:166","msg":"apply request took too long","took":"183.897905ms","expected-duration":"100ms","prefix":"read-only range ","request":"key:\"/registry/pods/vmware-system-tmc/agentupdater-workload-27887645-g4ppg\" ","response":"range_response_count:1 size:2671"}
```
Fluent Bitがetcdのログを拾ってsyslogに転送している。これによりFluent Bitとsyslog間の転送の疎通もこれで確認できた。