YasuBlog

中年インフラエンジニアの備忘録です。

Kubernetes の標準出力と標準エラー出力

Kubernetes では、コンテナの標準出力/標準エラー出力ログを kubectl logs コマンドで取得できます。実際にどのファイルに標準出力/標準エラー出力ログが出力されて、ローテートはどういう設定になっているのか整理しました。

1. ログの保存場所

まずは標準出力/標準エラー出力ログの保存場所です。

コンテナが標準出力/標準エラー出力に出力したログは Node に保存されます。実体のファイルとシンボリックリンクの構成は以下です。

f:id:dunkshoot:20220215230154p:plain

整理すると以下になります。

# ログ 説明
/var/lib/docker/containers/< Container ID >/< Container ID >-json.log ・コンテナの stdout/stderr に出力されたログが保存される実体のファイル
・起動中の Pod のログのみ保存
・終了した Pod のログは消える
・コンテナが再起動した場合、再起動前のコンテナのログは消えない
・保存されるのは 2 世代分のコンテナ(起動中のコンテナと再起動前のコンテナのログのみ保存)
/var/log/pods/< Namespace >_< Pod Name >_< Pod UID >/< Container Name >/< Index >.log ・①のファイルへのシンボリックリンク
・0.log が現在起動中のコンテナのログのリンク
・1.log が一つ前に起動していたコンテナのログのリンク
kubectl logs コマンドは API Server 経由で /var/log/pods にアクセスしている
/var/log/containers/< Pod Name >_< Namespace >_< Container Name >-< Container ID >.log ・②のファイルへのシンボリックリンク

実際のログです。

  1. @Node $ ls -lh /var/log/pods/kube-system_coredns-76f4967988-pkkx9_1ab7cf50-3781-4576-8a4d-d918e321ee64/coredns/*
  2. lrwxrwxrwx 1 root root 165 215 14:07 /var/log/pods/kube-system_coredns-76f4967988-pkkx9_1ab7cf50-3781-4576-8a4d-d918e321ee64/coredns/0.log -> /var/lib/docker/containers/52d7283862b0b64d6bdfc7dc4dce964bb3ca284ec3048325dbb7e5d61a1a00e3/52d7283862b0b64d6bdfc7dc4dce964bb3ca284ec3048325dbb7e5d61a1a00e3-json.log
  3. lrwxrwxrwx 1 root root 165 215 15:17 /var/log/pods/kube-system_coredns-76f4967988-pkkx9_1ab7cf50-3781-4576-8a4d-d918e321ee64/coredns/1.log -> /var/lib/docker/containers/a402cbab8d63b90c3d76f87579fe73bca77a2bffae2d5e0b3bd1617a1dbc037b/a402cbab8d63b90c3d76f87579fe73bca77a2bffae2d5e0b3bd1617a1dbc037b-json.log
  4. @Node $ ls -lh /var/log/containers/coredns-76f4967988-pkkx9_kube-system_coredns-*
  5. lrwxrwxrwx 1 root root 101 215 14:07 /var/log/containers/coredns-76f4967988-pkkx9_kube-system_coredns-52d7283862b0b64d6bdfc7dc4dce964bb3ca284ec3048325dbb7e5d61a1a00e3.log -> /var/log/pods/kube-system_coredns-76f4967988-pkkx9_1ab7cf50-3781-4576-8a4d-d918e321ee64/coredns/0.log
  6. lrwxrwxrwx 1 root root 101 215 15:17 /var/log/containers/coredns-76f4967988-pkkx9_kube-system_coredns-a402cbab8d63b90c3d76f87579fe73bca77a2bffae2d5e0b3bd1617a1dbc037b.log -> /var/log/pods/kube-system_coredns-76f4967988-pkkx9_1ab7cf50-3781-4576-8a4d-d918e321ee64/coredns/1.log

※ Pod の UID は kubectl get pods -n <Namespace> <Pod Name> -o jsonpath='{.metadata.uid}' で確認可能

2. コンテナログのローテート、世代

ログが増え続けると Node のディスクが逼迫するので、ローテートと削除の設定が必要です。Kubernetes では /etc/docker/daemon.json でそれらを設定しています。

オプション 説明
log-opts.max-size ・ログをローテートするファイルサイズ
・単位はキロバイト(k)/メガバイト(m)/ギガバイト(g)
log-opts.max-file ・ログの世代数
・max-size が設定されていない場合は無効

例えば、max-size:100m,max-file:10 の場合、一つのコンテナが最大 1 GB のログを保存する状態になります。最初に記載した通り、Pod としては 2 世代のコンテナのログを保存するため最大 2 GB になります。Node のディスクをサイジングする際はこれらを考慮する必要があります。

※ kubelet フラグにも同様の意味の containerLogMaxSizecontainerLogMaxFiles がありますが、検証したところ /etc/docker/daemon.jsonlog-opts に設定されている値でローテート、削除されていました

3. 検証

3.1. 検証環境構築

eksctl コマンドで EKS Cluster を作成する - YasuBlog の記事で作成した EKS Cluster を使用します。

3.2. EKS の設定値

max-size/max-file は Node 上の /etc/docker/daemon.json で確認できます。

  1. @Node $ cat /etc/docker/daemon.json
  2. {
  3. "bridge": "none",
  4. "log-driver": "json-file",
  5. "log-opts": {
  6. "max-size": "10m",
  7. "max-file": "10"
  8. },
  9. "live-restore": true,
  10. "max-concurrent-downloads": 10,
  11. "default-ulimits": {
  12. "memlock": {
  13. "Hard": -1,
  14. "Name": "memlock",
  15. "Soft": -1
  16. }
  17. }
  18. }

max-size10m, max-file10 に設定されています。

インスタンスタイプ毎の設定値を確認してみました。Node のリソース量に関わらず固定値が設定されているようです。

インスタンスタイプ max-size max-file
t3.small 10m 10
t3.medium 10m 10
m5.large 10m 10
m5.xlarge 10m 10

3.3. 挙動確認

つづいて実際の挙動を確認してみます。

3.3.1. ローテートと世代

まずはシンプルな Pod を起動します。

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: deployment
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: app
  10. template:
  11. metadata:
  12. labels:
  13. app: app
  14. spec:
  15. containers:
  16. - name: amazonlinux
  17. image: public.ecr.aws/amazonlinux/amazonlinux:latest
  18. command:
  19. - "bin/bash"
  20. - "-c"
  21. - "sleep 3600"

コンテナ ID を確認します。

  1. $ kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. deployment-6bb985c8c9-p7b5w 1/1 Running 0 114s 10.0.102.47 ip-10-0-102-148.ap-northeast-1.compute.internal <none> <none>
  4. $ kubectl describe pod deployment-6bb985c8c9-7xmm4 | grep 'Container ID'
  5. Container ID: docker://057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7

Node 上のログを確認します。

  1. @Node $ ls -lh /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/
  2. 合計 12K
  3. -rw-r----- 1 root root 0 216 14:55 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log
  4. drwx------ 2 root root 6 216 14:55 checkpoints
  5. -rw------- 1 root root 4.8K 216 14:55 config.v2.json
  6. -rw-r--r-- 1 root root 2.1K 216 14:55 hostconfig.json
  7. drwx--x--- 2 root root 6 216 14:55 mounts
  8. @Node $ ls -lh /var/log/pods/default_deployment-6bb985c8c9-p7b5w_ef8acb63-8389-47d6-aad8-c2976eac3665/amazonlinux/
  9. 合計 0
  10. lrwxrwxrwx 1 root root 165 216 14:55 0.log -> /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log

標準出力/標準エラー出力に何も出力していないので、上記の通りサイズが 0 のファイルが一つだけあります。この状態で Pod にログインし、標準出力に大量にログを出力してみます。

  1. $ kubectl exec -it deployment-6bb985c8c9-p7b5w -- /bin/bash
  2. @Pod $ while true;do cat /etc/services > /proc/1/fd/1;done

Node 上のログを確認します。

  1. @Node $ ls -lh /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/
  2. 合計 90M
  3. -rw-r----- 1 root root 2.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log
  4. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.1
  5. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.2
  6. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.3
  7. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.4
  8. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.5
  9. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.6
  10. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.7
  11. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.8
  12. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.9
  13. drwx------ 2 root root 6 216 14:55 checkpoints
  14. -rw------- 1 root root 4.8K 216 14:55 config.v2.json
  15. -rw-r--r-- 1 root root 2.1K 216 14:55 hostconfig.json
  16. drwx--x--- 2 root root 6 216 14:55 mounts
  17. @Node $ ls -lh /var/log/pods/default_deployment-6bb985c8c9-p7b5w_ef8acb63-8389-47d6-aad8-c2976eac3665/amazonlinux/
  18. 合計 0
  19. lrwxrwxrwx 1 root root 165 216 14:55 0.log -> /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log

max-size/max-file の設定通り、ログサイズが 10M でローテートされ、10 世代保存されている事が確認できました。/var/log/pods0.log は常に最新のファイルのシンボリックリンクになっています。

3.3.2. コンテナ再起動

上記の状態で、Node 上で docker stop を実行してコンテナを再起動してみます。

  1. @Node $ docker ps | grep amazonlinux
  2. 057fc611f5c4 public.ecr.aws/amazonlinux/amazonlinux "bin/bash -c 'sleep …" 5 minutes ago Up 5 minutes k8s_amazonlinux_deployment-6bb985c8c9-p7b5w_default_ef8acb63-8389-47d6-aad8-c2976eac3665_0
  3. @Node $ docker stop 057fc611f5c4
  4. 057fc611f5c4
  5. $ kubectl get pods -o wide
  6. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  7. deployment-6bb985c8c9-p7b5w 1/1 Running 1 6m15s 10.0.102.47 ip-10-0-102-148.ap-northeast-1.compute.internal <none> <none>
  8. $ kubectl describe pod deployment-6bb985c8c9-p7b5w | grep 'Container ID'
  9. Container ID: docker://89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476

コンテナを再起動したので Pod の RESTARTS が 0 から 1 に変わり、コンテナ ID も変わりました。

Node 上のログを確認します。

  1. # 旧コンテナ
  2. @Node $ ls -lh /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/
  3. 合計 89M
  4. -rw-r----- 1 root root 2.6M 216 15:01 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log
  5. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.1
  6. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.2
  7. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.3
  8. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.4
  9. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.5
  10. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.6
  11. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.7
  12. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.8
  13. -rw-r----- 1 root root 9.6M 216 14:59 057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log.9
  14. drwx------ 2 root root 6 216 14:55 checkpoints
  15. -rw------- 1 root root 4.8K 216 15:01 config.v2.json
  16. -rw-r--r-- 1 root root 2.1K 216 15:01 hostconfig.json
  17. drwx--x--- 2 root root 6 216 14:55 mounts
  18. # 新コンテナ
  19. @Node $ ls -lh /var/lib/docker/containers/89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476/
  20. 合計 12K
  21. -rw-r----- 1 root root 0 216 15:01 89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476-json.log
  22. drwx------ 2 root root 6 216 15:01 checkpoints
  23. -rw------- 1 root root 4.8K 216 15:01 config.v2.json
  24. -rw-r--r-- 1 root root 2.1K 216 15:01 hostconfig.json
  25. drwx--x--- 2 root root 6 216 15:01 mounts
  26. @Node $ ls -lh /var/log/pods/default_deployment-6bb985c8c9-p7b5w_ef8acb63-8389-47d6-aad8-c2976eac3665/amazonlinux/
  27. 合計 0
  28. lrwxrwxrwx 1 root root 165 216 14:55 0.log -> /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7-json.log
  29. lrwxrwxrwx 1 root root 165 216 15:01 1.log -> /var/lib/docker/containers/89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476/89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476-json.log

旧コンテナ、新コンテナともにログが存在している事が確認できました。/var/log/pods の方は 0.log が旧コンテナにリンクし、1.log が新コンテナにリンクしてます。

3.3.3. Pod 削除

上記の状態で Pod を削除してみます。

  1. $ kubectl delete pod deployment-6bb985c8c9-p7b5w
  2. pod "deployment-6bb985c8c9-p7b5w" deleted
  3. @Node $ ls -lh /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/
  4. ls: /var/lib/docker/containers/057fc611f5c416c77a00cfb02e24714b52e75af0c14c42ed11c58d42ca115ea7/ にアクセスできません: No such file or directory
  5. @Node $ ls -lh /var/lib/docker/containers/89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476/
  6. ls: /var/lib/docker/containers/89f425cce426a87fad882cfc5f091b3f87dca4942bd5c9f9fbde69fc217ea476/ にアクセスできません: No such file or directory
  7. @Node $ ls -lh /var/log/pods/default_deployment-6bb985c8c9-p7b5w_ef8acb63-8389-47d6-aad8-c2976eac3665/amazonlinux/
  8. 合計 0

Pod を削除するとログも全て消える事が確認できました。

3.4. 設定変更

最後に max-size/max-file の変更方法です。

Node 上の /etc/docker/daemon.json を修正して docker デーモンを再起動する事で設定変更が可能です。 Node 再作成時にも同様に設定されるように、カスタム起動テンプレートかカスタム AMI を使用する必要があります。

例えば、max-size100mmax-file5 にしたい場合は、カスタム起動テンプレートのユーザデータに以下のようなコードを追加する事で設定変更が可能です。

  1. sed -i -e 's/"max-size".*/"max-size": "100m",/g' /etc/docker/daemon.json
  2. sed -i -e 's/"max-file".*/"max-file": "5"/g' /etc/docker/daemon.json
  3. systemctl restart docker

個人的には AWS マネージドという事は AWS が良かれと思って設計した値なのでユーザ側がカスタマイズする必要は無いと思っています。

4. まとめ

コンテナの標準出力/標準エラー出力ログまわりについて整理してみました。EKS 等のマネージドサービスの場合は特別な要件がない限り設定値は変更しなくて良いと思います。

5. 参考

Logging Architecture | Kubernetes

ロギング・ドライバの設定 — Docker-docs-ja 1.9.0b ドキュメント

Amazon EKS ワーカーノードを設定して特定のディスク使用率でイメージキャッシュをクリーンアップする

起動テンプレートのサポート - Amazon EKS