“pstree”を使ってあるプロセスの子プロセス・孫プロセスを確認する

Bash

はじめに

子プロセスをバックグラウンド起動して並列処理行うシェルスクリプトを作成したが以下の点を確認したいと思いました。

  • 子プロセスが正しく立ち上がっているのか?
  • 子プロセスが過剰に立ち上がっていないか?
  • 子プロセスはどのぐらいの期間生存しているのか?

確認する方法を以下にまとめます。

検証環境

今回も検証環境として Docker を使いました。
もちろんDockerを使う必要はないのですが、クリーンな環境が欲しかったので利用しました。

$ docker run --rm -v $PWD:/mnt -it genzouw/centos-sandbox bash
$ uname -a
Linux 0869a1789807 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

$ bash -version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

pstreeコマンド

pstreeは、現在動作しているプロセスをツリー形式で表示するコマンドです。

コマンド名のとおり、「どのプロセスからどのプロセスが起動しているのか」という ツリー構造 が分かりやすく表示されるので、プロセスの実行状況を確認するのに便利です。

pstreeコマンドのインストール

早速実行してみます。

$ pstree
bash: pstree: command not found

いきなりですが、「コマンドが見つからない」というエラーが発生しました。
普通にCD/DVDからインストールしたLinuxディストリビューションにはインストール済みかと思いますが、 Docker 環境は軽量化のために必要最低限のコマンドしかインストールされていないことが多いです。

インストールする場合は以下のコマンドを実行します。

$ yum install -y psmisc

出力される内容を見てみる

早速実行してみます。
いくつかの環境で試してみます。

Docker環境の場合

$ pstree

bash---pstree

なんだかよくわからない表示がされていますね。

CentOS7環境の場合

ちなみに「さくらのVPS」上のCentOS7で実行した結果は次のとおりです。

$ pstree

systemd─┬─NetworkManager───2*[{NetworkManager}]
        ├─abrt-dbus───2*[{abrt-dbus}]
        ├─abrt-watch-log
        ├─abrtd
        ├─agetty
        ├─anacron───run-parts─┬─awk
        │                     └─yum-cron
        ├─atd
        ├─auditd───{auditd}
        ├─containerd─┬─containerd-shim─┬─apache2───5*[apache2]
        │            │                 └─9*[{containerd-shim}]
        │            └─14*[{containerd}]
        ├─crond

CentOS6環境の場合

また別環境のCentOS6で実行した結果は以下の通りです。

$ pstree

init─┬─atd
     ├─auditd───{auditd}
     ├─17*[bash]
     ├─2*[bash───awk]
     ├─bash───tail
     ├─cat
     ├─crond───crond───bash─┬─grep
     │                      ├─2*[sed]
     │                      └─ssh
     ├─cupsd

プロセスツリー

環境によって、出力されている内容が異なりますね。

ツリー上に表示された内容は「プロセスツリー」と呼ばれます。

Linux上の全てのプロセスは必ず他のプロセスの子プロセスとなります。
ただし、例外がいて、「すべてのプロセスの親」となるプロセスが存在し、これには「親プロセス」が存在しません。

Linuxだと大体 init もしくは systemd というプログラムが必ず1番目のプロセス(PID:1)となります。
Linux上で動くすべてのプログラムは、 init または systemd の子プロセス・孫プロセスであると言えます。

ユーザーが実行するプログラムはシェルから実行されますが、そのシェルも元をたどればinitから実行されたプログラムです。

本当に「プロセスツリー」のルートとなっているプロセスはPID=1となっているか確認してみましょう。

ps 1PID=1 のプロセスを確認できます。

Docker環境のルートプロセス

$ ps 1
  PID TTY      STAT   TIME COMMAND
    1 pts/0    Ss     0:00 bash

CentOS7環境のルートプロセス

$ ps 1
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss   135:10 /usr/lib/systemd/systemd --system --deserialize 21

CentOS6環境のルートプロセス

$ ps 1
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     3:20 /sbin/init

Dockerのルートプロセスについて

Linux上で動くすべてのプログラムは、 init または systemd の子プロセス・孫プロセスであると言えます。

と断っていながら、Dockerは bash となっていますね。

Dcokerの思想と関係がありますが、Dockerは基本的に割り当てられた環境内で「1つのことを行う」ためのソフトウェアです。

起動時に以下のようなコマンドを実行しましたが、コマンドの最終引数に指定されたコマンド(ここではbash)がDockerのルートプロセスとなります。

$ docker run --rm -v $PWD:/mnt -it genzouw/centos-sandbox bash

もう少しpstreeを触ってみる

Docker環境内でもう少し触ってみます。
子プロセスを2つ立ち上げて、表示がどうなるかを見てみます。

$ bash -c 'while :; do date; done > list' &
[1] 17600

$ bash -c 'while :; do date; done > list' &
[2] 19762

$ pstree
bash-+-2*[bash---bash]
     `-pstree

ノードが2つしか表示されていません。
同じコマンドのプロセスが複数実行されている場合には、マージされます。
-c オプションでマージさせないようにすることができます。

$ pstree -c
bash-+-bash---date
     |-bash
     `-pstree

$ pstree -c
bash-+-bash---date
     |-bash---date
     `-pstree

タイミングによって、bash プロセスが date コマンドを実行しておりツリーの表示内容が変わっています。

それぞれのプロセスIDも追加で表示したい場合は-pオプションを指定します。

$ pstree -p
bash(1)-+-bash(17600)
        |-bash(19762)---date(95091)
        `-pstree(95086)

特定のプロセスをプロセスツリーのルートとして表示する場合は引数にプロセスIDを指定します。

$ pstree 19762
bash---date

Dcoker環境とその他の環境でpstreeの表示内容が異なっていましたが、同じ表示に合わせるためには-Uオプションを指定します。

$ pstree
bash-+-2*[bash]
     `-pstree

$ pstree -U
bash─┬─bash───date
     ├─bash───bash
     └─pstree

ひとこと

あまりトラブルシューティングの際に使わないですね。
デバッグのときぐらいかな。

Bash