zaki work log

作業ログやら生活ログやらなんやら

[Kubernetes] podに任意のログを発生させてkubectl logs -fの出力を自由にコントロールしたい

podのログの監視ツール作成みたいな作業をしているときに「任意のログをpod内に発生させたい!」ということがあったので、その方法について。

TL;DR

ログを発生させたい対象podのシェル上(kubectl exec -it ... -- shなどで)で、/proc/1/fd/1に対して発生させたいログ文字列を書き込む

echo "sample log" > /proc/1/fd/1

こんな感じ。

nekopさんありがとうございました。

解説

man procより。

       /proc/[pid]/fd/
              This is a subdirectory containing one entry for each file  which
              the process has open, named by its file descriptor, and which is
              a symbolic link to the actual file.  Thus, 0 is standard  input,
              1 standard output, 2 standard error, and so on.

プロセスごとのファイルディスクリプタがこのディレクトリ配下に存在している。

など。
(プロセスが開いているファイルやソケットなども存在する)

つまり、/proc/1/fd/1というのは、「PID1のプロセスの標準出力」ということになる。
pod(の中で動いているコンテナ)は、(通常は)PID1でアプリケーションが動作し、そのプロセスの標準出力への出力がコンテナのログとして扱われるため、/proc/1/fd/1への書き込みがpodのログとして出力される、という動作になる。

podで動作確認

こんな実行状態とする。

[zaki@k8s-master01 ~]$ kubectl get pod
NAME                          READY   STATUS    RESTARTS   AGE
sample-web-7dbc56cb5b-gxj6l   1/1     Running   0          79s

sample-web(中身はhttpdサーバ)のログを表示

[zaki@k8s-master01 ~]$ kubectl logs -f sample-web-7dbc56cb5b-gxj6l 
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.244.219.194. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.244.219.194. Set the 'ServerName' directive globally to suppress this message
[Sat Jun 13 13:17:38.991237 2020] [mpm_event:notice] [pid 1:tid 140014371525760] AH00489: Apache/2.4.43 (Unix) configured -- resuming normal operations
[Sat Jun 13 13:17:38.991616 2020] [core:notice] [pid 1:tid 140014371525760] AH00094: Command line: 'httpd -D FOREGROUND'

この状態で、別のターミナルでシェルを起動し、シェル上で/proc/1/fd/1へ文字列を書き込み

[zaki@k8s-master01 ~]$ kubectl exec -it sample-web-7dbc56cb5b-gxj6l -- bash
root@sample-web-7dbc56cb5b-gxj6l:/usr/local/apache2# echo "sample log" > /proc/1/fd/1
root@sample-web-7dbc56cb5b-gxj6l:/usr/local/apache2# 

すると、podのログに書き込んだ文字列が出力されるのを確認。

[zaki@k8s-master01 ~]$ kubectl logs -f sample-web-7dbc56cb5b-gxj6l 
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.244.219.194. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.244.219.194. Set the 'ServerName' directive globally to suppress this message
[Sat Jun 13 13:17:38.991237 2020] [mpm_event:notice] [pid 1:tid 140014371525760] AH00489: Apache/2.4.43 (Unix) configured -- resuming normal operations
[Sat Jun 13 13:17:38.991616 2020] [core:notice] [pid 1:tid 140014371525760] AH00094: Command line: 'httpd -D FOREGROUND'
sample log

普通のLinux OS上で確認

仕組み自体はLinux一般の話なので、そもそも素のLinux OS上でも確認できるはず。

ターミナル1で引数無しでcatを実行

[zaki@manager-dev ~]$ cat

とうぜん標準入力が何も無いので出力も何もない。

ここでターミナル2でcatのPIDを調べる

[zaki@manager-dev ~]$ ps -u
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
zaki     103986  0.0  0.1 116860  3508 pts/0    Ss   20:17   0:00 -bash
zaki     104015  0.0  0.1 116732  3240 pts/1    Ss   20:17   0:00 -bash
zaki     104142  0.0  0.0 108072   356 pts/1    S+   22:31   0:00 cat
zaki     104143  0.0  0.0 155472  1848 pts/0    R+   22:31   0:00 ps -u

104142であることが確認できたので、それを指定してechoを実行。

[zaki@manager-dev ~]$ echo "nya-n" >  /proc/104142/fd/0
[zaki@manager-dev ~]$

するとcatのプロセスが"nya-n"とう標準入力を受け取るという動作になるため、cat実行中のターミナルに文字列が出力される。

[zaki@manager-dev ~]$ cat
nya-n

CentOS 7.7、Ubuntu 18.04で確認