GKEでアプリケーションのログを取るためにfluentdをStatefulSetで動かしたので、その忘備録です。
今回はBigQueryにログを加工して流す目的で使用しました。BigQueryへの挿入方法としては、streaming insert
ではなくload
を使用しています。
ちなみに、StackDriverやPub/Subを利用する方法も検討しましたが、費用が割と高いので、一旦断念しました。
StatefulSetでfluentdを動かす利点
BigQueryに限らず、fluentdで何かしらのデータストアにログを送信する際は、ファイルバッファを用いて定期的に送信するのが一般的かと思います。
しかし、k8sで普通にdeploymentを使ってfluentdのPodを配置する場合、何かしら不慮の事故でPodが再起動してしまうと、バッファしていたデータが失われてしまいます。Podが1台の構成であれば単純に永続ボリュームをマウントすれば良いですが、複数のPodで負荷分散・冗長化が必要なことの方が多いでしょう。
StatefulSetならPodが再起動した場合でも、再起動前にマウントされていた永続ボリュームを再度マウントできます。つまり、再起動前のバッファファイルを引き継ぐことができるます。
StatefulSetの定義
以下がStatefulSetのサンプルです。
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: app-name
spec:
serviceName: app-name
replicas: 2
selector:
matchLabels:
app: app-name
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: app-name
spec:
securityContext:
fsGroup: 1000
containers:
- name: app-name
image: gcr.io/:project_id/:image_name
ports:
- containerPort: 24224
volumeMounts:
- name: app-name-pvc
mountPath: /fluentd/log
volumeClaimTemplates:
- metadata:
name: app-name-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
StatefulSetはデフォルトでローリングアップデートが出来ないので、updateStrategy
を設定します。
updateStrategy:
type: RollingUpdate
バッファファイルの書き込みを許可するために、securityContext
を設定しています(もっといい方法があるかも?)。
securityContext:
fsGroup: 1000
10GBストレージのvolumeClaimTemplates
を定義して、/fluentd/log
のパスにマウントしています。
volumeMounts:
- name: app-name-pvc
mountPath: /fluentd/log
volumeClaimTemplates:
- metadata:
name: app-name-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
fluentd側でバッファを書き込むディレクトリは、/fluentd/log
に設定する必要があります。
<buffer>
path fluentd/log/bigquery.*.buffer
flush_at_shutdown true
</buffer>
終わりに
StatefulSetでfluentdを立てるような事例がweb上にあまりなかったので、簡単にまとめてみました。GKEでログ基盤を構築する場合は、StackdriverやPub/Subを利用した方がスマートな構成にできると思います。ただ、私の扱っているシステムはリクエスト数が膨大なため、想像以上に費用が嵩むため断念し、fluentdによる構成で構築しました。kubernetesでサービスを組む場合、状態を持たせる箇所は出来るだけ少なくしたいので、スマートかつ費用を抑えた方法がないか、今後も模索したいです。