Chatwork Creator's Note

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

読者になる

Kubernetesのアプリケーションログ収集(1)

SRE部の坂本です。

みなさま、Kubernetes環境(EKS環境)におけるアプリケーションのログ収集ってどうされていますか?

Chatworkでは下記のように各ノードのforwarderとしてfluent-bit、aggregatorとしてfluentdというfluent兄弟を両方使っており、やや珍しい構成のように思えるので、そのことについて記載したいと思います。

概要図

この構成にしたのは、2020年*1ではありますが、それほど古い考えではないように思えるのと、ふと構成を振り返ったときに、内部にも全体をまとめたドキュメントがなかったので、外部発信しつつまとめたいと思います。

Chatworkのアプリケーションログの量

具体的な数値を乗せることはできませんが、アクセス数やログの量は多いです。

アプリケーションのログの量は、アクセス量に比例(というわけでもないけど、基本的には)するわけですが、Chatworkのアクセス量は、2024年5月において、ピーク時で?M req/min(1桁台のメガ(M))あります。これは秒間に直すと、??K req/sec(2桁台のキロ(K))ぐらいです。ChatworkのアプリケーションはCloudFront -> ALB -> Pod(nginx + php-fpm)で、このリクエスト数はALBなので、すべてがアプリケーションのためのリクエストではないにしても、とにかくそれぐらい流れています。

nginxでアクセスログが出てきますが、これが特に多いです。

Athenaで集計してみると(database名、table名は実際のものではないです)、

SELECT count(*) FROM "database"."chatwork-web-nginx-accesslog"
where dt = '20240519'
;

-> 2億レコード弱あります。1日で。これはnginxだけのログです。 なので、2億 / 86400 = 2314.81481 ということで、1秒で2300レコードぐらい吐き出されています。

これは1日の平均です。ピーク時はもっと出ています。

Chatworkのアクセスパターンは、Chatworkのユーザ層が国内のToB向けということもあり、平日日中に多く、夜間はだいぶおとなしいです。 平日日中と夜間の差はだいたい35倍ぐらいです。

アクセスが増えればPodもオートスケーリングしますが、PodのCPU使用率でのスケールなので、正比例に増えるわけでもなく、1Podあたりのリクエスト数がピーク時には増えます。

fpmのほうは

SELECT count(*) FROM "database"."chatwork-web-php-fpm-log"
where dt = '20240519'
;

-> 1000万レコード以上あります。nginxに比べると少ないものです。

10000000 / 86400 = 115.740740741 ということで、1秒で100レコード以上吐き出されています。 こちらも1日の平均です。

さらに1ノードに1Podではなく、1ノードにこれぐらいログを出すPodが複数います。 下記は本番のあるノードのPodの一部ですが、kddi-webというのはKDDI Chatworkのことで、諸事情により、通常のChatworkとは別Podで動いていますが、中身は同じで、こちらもまずまずの量のログが出ています。

$ kubectl get po -n chatwork-web -o wide | grep ip-10-1-111-11.ap-northeast-1.compute.internal
chatwork-web-php-7c9b75b8dc-aa111                     2/2     Running     0              75m     10.1.123.58    ip-10-1-111-11.ap-northeast-1.compute.internal    <none>           1/1
chatwork-web-php-7c9b75b8dc-a11abc                    2/2     Running     0              73m     10.1.124.4     ip-10-1-111-11.ap-northeast-1.compute.internal    <none>           1/1
kddi-web-php-68db945c97-b3fa1                         2/2     Running     0              73m     10.1.129.247   ip-10-1-111-11.ap-northeast-1.compute.internal    <none>           1/1

このノードにはアプリケーションのPodのほかに、Daemonsetも複数動いており、それらのすべてのログを収集し、可能な限り欠損しないようにaggregatorに送信できるパフォーマンスがforwarderには求められます。

kubelet側での設定で重要なこと

やや脱線しますが、EKSのノードのkubeletにおいて、コンテナのログのローテションまわりは変えていますか?

kubernetes.io

コンテナのログのローテーションに関連する項目は下記の2つです

  • containerLogMaxSize
    • ローテーションされるサイズ。デフォルト: 10Mi
  • containerLogMaxFiles
    • ローテーションの世代。デフォルト: 5
  • containerLogMaxWorkers(1.30から)
    • ローテーションの同時実行数。デフォルト: 1

Chatworkではノードのuser_dataにおいて、jqでpatchを当てて、設定を変えています。 やや涙ぐましいシェル芸感があり、実際にはこの2つの項目以外にもpatchを当てているところがあり、もう少しワンライナーが長いです。

ファイルをわけているのは、これらを試すときに別ファイルのほうがデバッグしやすかった、というのがあります。

# kubelet
cat /etc/kubernetes/kubelet/kubelet-config.json | jq ". |= .+ {\"containerLogMaxSize\": \"${WORKER_LOG_MAX_SIZE}Mi\",\"containerLogMaxFiles\": ${WORKER_LOG_MAX_FILE}}" > /tmp/kubelet-config.json
mv /tmp/kubelet-config.json /etc/kubernetes/kubelet/kubelet-config.json

このようにして、ChatworkではcontainerLogMaxSizeを本番では500Mi, containerLogMaxFilesを2としています。 なんで512Miにしなかったんだろう...と過去の自分に聞いてみましたが、わかりませんでした。とにかく、それぐらい大きくしています。ローテーション時の負荷を考えるともう少し小さくてもよい気もします。

上記に記載したログの量なので、デフォルトの10Miではすぐにローテションされてしまいます。

まとめ

Chatworkのログがかなり膨大であることを記載しました。

(2)では、現構成の前に使っていたものや、この構成にした理由(だいたい書きましたが)について記載します。

*1:ChatworkのモノリスアプリケーションがEKSに移行したとき https://creators-note.chatwork.com/entry/2020/11/04/141050