入門 eBPF 番外編:bpftrace + systemdでexecveログを常時収集する
この記事は ↓ の続きです。
前回は、
-
execve.btを作る -
sudo bpftrace execve.btを叩いて、短時間だけログを眺める
というお試し用の使い方でした。
今回はそれを一歩進めて、
bpftrace + systemd で、execve のログを常時取りっぱなしにする
ためのセットアップをまとめます。
最後に、
- 「ログを止めたいときどうするの?」
- 「ログファイルを消したいときどうするの?」
もまとめてあります!
1. 今回のゴール
- VM のどこかに
execve.btを置いている -
systemdのサービスとしてbpftraceを登録 - VM 起動時に自動で
bpftraceが動き始める - ログは
/var/log/bpftrace/execve_YYYYMMDD.logみたいな日付付きファイルに追記されていく - 止めたいときは
systemctl stopで一発停止できる
※パスやファイル名は自分の環境に合わせて変えてください!
ここでは例として、
- スクリプト →
/opt/watchlog/bpftrace/execve.bt - ログディレクトリ →
/var/log/bpftrace/
という前提で書きます!
2. 前提 execve.bt を用意する
前回の記事のおさらいです。
sudo mkdir -p /opt/watchlog/bpftrace
sudo vim /opt/watchlog/bpftrace/execve.bt
tracepoint:syscalls:sys_enter_execve
{
time("%Y-%m-%d %H:%M:%S ");
printf("pid=%d comm=%s filename=%s\n", pid, comm, str(args->filename));
}
保存したら、念のため権限も整えておきます(ここでは root 実行前提)
sudo chown -R root:root /opt/watchlog
sudo chmod -R 755 /opt/watchlog
3. ログ出力先ディレクトリを作る
ログ置き場として /var/log/bpftrace を作ります。
sudo mkdir -p /var/log/bpftrace
sudo chown root:root /var/log/bpftrace
sudo chmod 755 /var/log/bpftrace
今回はシンプルに
-
rootがbpftraceを叩く -
/var/log/bpftrace/配下にログを追記
という想定で行います。
4. bpftrace を起動するラッパースクリプトを作る
日付ごとにログファイルを分けるために、bash スクリプト側でファイル名を決めるようにします。
sudo vim /usr/local/bin/bpftrace-execve.sh
中身の例
#!/usr/bin/env bash
set -euo pipefail
LOG_DIR=/var/log/bpftrace
mkdir -p "$LOG_DIR"
# 起動した日付ごとにログファイルを分ける
LOG_FILE="$LOG_DIR/execve_$(date +%Y%m%d).log"
# ここで bpftrace 実行(標準出力+標準エラーをファイルに追記)
exec /usr/bin/bpftrace /opt/watchlog/bpftrace/execve.bt >> "$LOG_FILE" 2>&1
保存したら、実行権限を付けます。
sudo chmod +x /usr/local/bin/bpftrace-execve.sh
sudo chown root:root /usr/local/bin/bpftrace-execve.sh
ポイントはこの行です
LOG_FILE="$LOG_DIR/execve_$(date +%Y%m%d).log"
-
$(date +%Y%m%d)が bash 上で展開 されるので
例 >>/var/log/bpftrace/execve_20251217.log
"$LOG_FILE" 2>&1 で標準出力・標準エラーをそのファイルに追記します。
5. systemd ユニットファイルを作る
次に、systemd のサービスとして登録します。
/etc/systemd/system/bpftrace-execve.service を作成します。
sudo vim /etc/systemd/system/bpftrace-execve.service
[Unit]
Description=bpftrace: log execve() system calls
After=network.target
[Service]
Type=simple
User=root
# bpftrace を起動するラッパースクリプト
ExecStart=/usr/local/bin/bpftrace-execve.sh
# ログ本体はスクリプト側でファイルに書き出すので、
# systemd 側では journal にだけ流しておく
StandardOutput=journal
StandardError=journal
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
StandardError=journal について
StandardOutput=journal / StandardError=journal としておくと、
sudo systemctl status bpftrace-execve.servicesudo journalctl -u bpftrace-execve.service
から、サービスの起動・停止・エラーなどを確認できます。
execve のログ本体は /var/log/bpftrace/execve_YYYYMMDD.log に出る、
運用ログは journal に残る、という分担です。
なぜ unit ファイルに $(date ...) を書かないの?
最初は
StandardOutput=append:/var/log/bpftrace/execve_$(date +%%Y%%m%%d).log
のように書きたくなりますが、
systemd ユニットはシェルではないので $(date ...) は展開されません。
そのため、日付付きファイル名のような「シェルっぽい処理」は
bash スクリプト(bpftrace-execve.sh)の側に全部寄せる構成にしています。
なぜ絶対パスなの?
-
ExecStart=のコマンドは、基本カレントディレクトリを期待しないほうが安全 -
bpftraceやexecve.btの場所がはっきりしているほうが、後から見たときに分かりやすい
/usr/bin/bpftrace や /opt/watchlog/bpftrace/execve.bt のように絶対パスで書いておくのが定石です。
6. systemd に読み込ませて起動する
ユニットファイルを書いたら、systemd に再読み込みさせます。
sudo systemctl daemon-reload
続いて、サービスを有効化 + 即起動します。
sudo systemctl enable --now bpftrace-execve.service
状態を確認する
sudo systemctl status bpftrace-execve.service
active (running) になっていれば成功です🐤
7. ログがちゃんと出ているか確認する
ログディレクトリを覗いてみましょう。
ls -l /var/log/bpftrace
例
-rw-r--r-- 1 root root 12345 XXX XX XX:XX execve_YYYYMMDD.log
中身をtailしてみます。
sudo tail -f /var/log/bpftrace/execve_YYYYMMDD.log
別ターミナルから、適当にコマンドを叩きます。
ls
uname -a
python3 -V
ログ側にこんな感じで流れてくれば成功です。
xxxx-xx-xx xx:xx:xx pid=1234 comm=ls filename=/usr/bin/ls
xxxx-xx-xx xx:xx:xx pid=1235 comm=uname filename=/usr/bin/uname
xxxx-xx-xx xx:xx:xx pid=1236 comm=python3 filename=/usr/bin/python3.12
8. ログをオフにする方法
「常時取りっぱなし」にしたら、次に気になるのがここですよね。
いま撮ってるログを止めたいとき、どうすればいいのかを、パターン別にまとめます。
8.1 systemd サービスを一時停止する
いま作ったサービスを一旦止めるだけならこれです。
sudo systemctl stop bpftrace-execve.service
これで bpftrace プロセスが終了し、ログも流れなくなります。
状態確認
sudo systemctl status bpftrace-execve.service
inactive (dead) や inactive (stopped) になっていれば OK です。
8.2 起動時に自動で動いてほしくない場合
VM を再起動したときに もう自動で動いてほしくない 場合は、disable します。
sudo systemctl disable bpftrace-execve.service
これで、次回ブート時にはこのサービスは起動されません。
-
stop… 今だけ止める -
disable… そもそも自動起動しないようにする
というイメージになります。
Discussion