![画像](https://habrastorage.org/getpro/habr/post_images/fb1/8fc/86a/fb18fc86aa5282002f42d1c5979b5a92.jpg)
ログや監視インジケーターがないものをデバッグするとき、sshを介してリモートコンピューターに接続します。 もちろん、このアプローチは限られているため、それほど単純ではなく、DevOpsのファッショントレンドや、インターネットで読むことができるすべての現代的なものには対応していませんが、驚くほど状況をすばやく分析するのに適しています。
実際、これはプログラムのデバッグ時に
print
コマンドを使用するのと似ています。 ここで私は、私がSREまたはIT運用エンジニアではないことをすぐに明確にしたいと思います。 私の活動の主な分野は開発です。
時々、私が書いたコードをデプロイし、何か問題が発生したときにデバッグする必要があります。 ほとんどの場合、自分自身の新しいシステムに自分自身を見つけるとき 、私にとって最も難しいことは何かを見つけることです。 たとえば、プロセスがリッスンしているポートを見つけます。 または、特定のデーモンがログを書き込むファイルを見つけるために、より頻繁に必要なもの。 そして、
ps
、
pstree
、および
ls
の呼び出しを多数使用し、
grep
多くの呼び出しを使用して、これらの質問に対する答えを見つけることができたとしても、多くの場合、「答え」には有用なものが含まれていないか、間違っていることが判明します。
現在読んでいるのがCPythonの主任開発者であるRaymondGöttingerによるプレゼンテーションである場合、「より良い方法が必要です」というフレーズを聴衆が待っているときが来るでしょう。
そして、実際、そのような方法があります。 必要なものをシステムで検索するために常に使用するツールは、
lsof
と呼ばれる素晴らしいツールです。
lsof
ユーティリティ(名前はel-soffに似ていますが、liss-offやel-es-o-effのようなものを好む人もいます)は、開いているすべてのファイル(LiStはすべてOpen Files)のリストを表示する非常に便利なコマンドです。
Unixのようなシステムではすべてがファイルであるため、
lsof
何かを見つけるのに特に適しています。 これは、
ps
、
netstat
ユーティリティ、およびその他のツールを非常に簡単に置き換えることができる、驚くほど汎用性の高いデバッグツールです。
LSOFオプション
「SRE」という用語が登場する数十年前にこのビジネスに携わってきたSREのベテランは、かつて私にこう語った。「必要なものをすべて認識したらすぐにlsofオプションの勉強をやめました。 最も重要なことを学び、それがあなたが必要とするすべてです。」
lsof
ユーティリティには、広範なオプションセットがあります。
NAME lsof - list open files SYNOPSIS lsof [ -?abChKlnNOPRtUvVX ] [ -AA ] [ -cc ] [ +cc ] [ +|-dd ] [+|-DD ] [ +|-es ] [ +|-f [cfgGn] ] [ -F [f] ] [ -g [s] ] [ -i [i] ] [-k k ] [ +|-L [l] ] [ +|-mm ] [ +|-M ] [ -o [o] ] [ -ps ] [ +|-r[t[m<fmt>]] ] [ -s [p:s] ] [ -S [t] ] [ -T [t] ] [ -us ] [ +|-w ] [ -x[fl] ] [ -z [z] ] [ -Z [Z] ] [ -- ] [names]
あなたはそれらすべてを勉強したい場合- 男はあなたを助けます。 ここで、私が普段使っているものについてお話したいと思います。
▍-uオプション
-u
オプションは、特定のユーザーが開いたファイルをリストします。 次の例は、
cindy
が開いているファイルの数を確認する方法を示しています。
cindy@ubuntu:~$ lsof -u cindy | wc -l 248
通常、パラメータ「^」(カバー)がオプションのパラメータの前に置かれている場合、これは否定を意味し、このパラメータに一致するファイルがプログラムの出力から除外されます。 たとえば、
cindy
を除くすべてのユーザーが開いているコンピューター上のファイルの数を調べる方法を次に示します。
cindy@ubuntu:~$ lsof -u^cindy | wc -l 38193
▍オプション-U
-U
オプション
-U
、Unixドメイン内のすべてのソケットファイルを
-U
します。
cindy@ubuntu:~$ lsof -U | head -5 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME init 1 root 7u unix 0xffff88086a171f80 0t0 24598 @/com/ubuntu/upstart init 1 root 9u unix 0xffff88046a22b480 0t0 22701 socket init 1 root 10u unix 0xffff88086a351180 0t0 39003 @/com/ubuntu/upstart init 1 root 11u unix 0xffff880469006580 0t0 16510 @/com/ubuntu/upstart
▍-cオプション
-c
オプション
-c
、指定された文字で始まる名前のコマンドを実行するオープンプロセスを保持するファイルに関する情報を
-c
。 たとえば、次のコマンドは、コンピューターで実行されているすべてのPythonプロセスによって開かれた最初の15ファイルを表示します。
cindy@ubuntu:~$ lsof -cpython | head -15 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME python2.7 16905 root cwd DIR 9,1 4096 271589387 /home/cindy/sourcebox python2.7 16905 root rtd DIR 9,1 4096 2048 / python2.7 16905 root txt REG 9,1 3345416 268757001 /usr/bin/python2.7 python2.7 16905 root mem REG 9,1 11152 1610852447 /usr/lib/python2.7/lib-dynload/resource.x86_64-linux-gnu.so python2.7 16905 root mem REG 9,1 101240 1610899495 /lib/x86_64-linux-gnu/libresolv-2.19.so python2.7 16905 root mem REG 9,1 22952 1610899509 /lib/x86_64-linux-gnu/libnss_dns-2.19.so python2.7 16905 root mem REG 9,1 47712 1610899515 /lib/x86_64-linux-gnu/libnss_files-2.19.so python2.7 16905 root mem REG 9,1 33448 1610852462 /usr/lib/python2.7/lib-dynload/_multiprocessing.x86_64-linux-gnu.so python2.7 16905 root mem REG 9,1 54064 1610852477 /usr/lib/python2.7/lib-dynload/_json.x86_64-linux-gnu.so python2.7 16905 root mem REG 9,1 18936 1610619044 /lib/x86_64-linux-gnu/libuuid.so.1.3.0 python2.7 16905 root mem REG 9,1 30944 1207967802 /usr/lib/x86_64-linux-gnu/libffi.so.6.0.1 python2.7 16905 root mem REG 9,1 136232 1610852472 /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so python2.7 16905 root mem REG 9,1 77752 1610852454 /usr/lib/python2.7/lib-dynload/parser.x86_64-linux-gnu.so python2.7 16905 root mem REG 9,1 387256 1610620979 /lib/x86_64-linux-gnu/libssl.so.1.0.0
別の興味深い例を示します。 たとえば、Python 2.7プロセスとPython 3.6プロセスが多数あり、Python 2.7プロセスではないプロセスによって開かれているファイルを把握する必要があります。 次の方法で実行できます。
cindy@ubuntu:~$ lsof -cpython -c^python2.7 | head -10 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME python 20017 root cwd DIR 9,1 4096 2048 / python 20017 root rtd DIR 9,1 4096 2048 / python 20017 root txt REG 9,1 3345416 268757001 /usr/bin/python2.7 python 20017 root mem REG 9,1 11152 1610852447 /usr/lib/python2.7/lib-dynload/resource.x86_64-linux-gnu.so python 20017 root mem REG 9,1 6256 805552236 /usr/lib/python2.7/dist-packages/_psutil_posix.x86_64-linux-gnu.so python 20017 root mem REG 9,1 14768 805552237 /usr/lib/python2.7/dist-packages/_psutil_linux.x86_64-linux-gnu.so python 20017 root mem REG 9,1 10592 805451779 /usr/lib/python2.7/dist-packages/Crypto/Util/strxor.x86_64-linux-gnu.so python 20017 root mem REG 9,1 11176 1744859170 /usr/lib/python2.7/dist-packages/Crypto/Cipher/_ARC4.x86_64-linux-gnu.so python 20017 root mem REG 9,1 23560 1744859162 /usr/lib/python2.7/dist-packages/Crypto/Cipher/_Blowfish.x86_64-linux-gnu.so
▍オプション+ d
+d
オプションを使用すると、特定のディレクトリで開いているフォルダとファイルを見つけることができます(ただし、そのサブディレクトリではありません)。
cindy@ubuntu:~$ lsof +d /usr/bin | head -4 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME circusd 1351 root txt REG 9,1 3345416 268757001 /usr/bin/python2.7 docker 1363 root txt REG 9,1 19605520 270753792 /usr/bin/docker runsvdir 1597 root txt REG 9,1 17144 272310314 /usr/bin/runsvdir
▍-dオプション
おそらく
-d
オプションは、私が最も頻繁に使用するオプションの1つです。
-p
オプションのみが失われます。 このオプションを使用すると、出力に含めるか出力から除外する必要があるファイル記述子のリストをコンマで区切って指定できます。 これについてはドキュメントに次のように書かれています:
, «^». , «^». .
, , , - : «0-7» «3-10».
, «^», - «^0-7» 0 7.
, , .
, lsof .
▍-pオプション
lsof
使用するときに
-p
オプションを使用しなかった時期を思い出せません。 PIDコマンドの呼び出し時に指定されたプロセスで開かれたすべてのファイルを表示できます。
たとえば、プロセスによって開かれたすべてのファイル(PID 1など)に関する情報を表示するUbuntuの例を次に示します。
![](https://habrastorage.org/getpro/habr/post_images/e98/575/166/e98575166593363948969af414854944.png)
Ubuntuで-pオプションを指定して呼び出されたlsofコマンドの出力
これが私のMacBook Airに表示されるものです。
![](https://habrastorage.org/getpro/habr/post_images/3b2/1d4/634/3b21d463486257337769122555c94580.png)
MacBook Airで-pオプションを使用して呼び出されたlsofコマンドの出力
▍オプション-P
-P
オプションは、ネットワークファイルの場合、ポート番号からポート名への変換を抑制します。 ポート名の解決が正しく機能しない場合に使用すると便利です。
このオプションは、別のオプション
-n
とともに使用できます。これは、ネットワーク番号のネットワークファイルのホスト名への変換を抑制します。 また、ホスト名を誤って解決する場合にも役立ちます。
上記の両方の変換を抑制すると、
lsof
高速化できる場合があります。
▍オプション-i
-i
オプション
-i
、指定されたアドレスに対応するインターネットアドレスを持つファイルに関する情報を
-i
ます。 コマンドを呼び出すときにアドレスを指定しない場合、このオプションを使用すると、すべてのインターネットソケットとネットワークファイルに関する情報を表示できます。
たとえば、
lsof
を使用すると、SlackまたはDropboxクライアントによって開かれたTCP接続を確認できます。 楽しみのために、Chromeタブが開いている接続の数を見てみてください。各接続は個別のプロセスです。 Slackが開いた接続を見てみましょう。
lsof -i -a -u $USER | grep Slack
![](https://habrastorage.org/getpro/habr/post_images/b88/eb5/51a/b88eb551a63c9423142e626a66781d6f.png)
Slackによって開かれた接続の一覧表示
Dropboxクライアントによって開かれたTCPソケットについて
lsof
使用すると、次のことがわかります。
![](https://habrastorage.org/getpro/habr/post_images/ef5/594/f44/ef5594f44ce6c546573dbd35246f2ec0.png)
開かれた接続Dropboxのリスト
Lsof
では、
lsof -iUDP
を使用してUDP接続に関する情報を表示する
Lsof
でき
Lsof
。
![](https://habrastorage.org/getpro/habr/post_images/ef9/cf4/d57/ef9cf4d57514cd28ad3b219d91970b14.png)
UDP接続情報の表示
lsof -i 6
コマンドを使用すると、開いているIPv6接続をリストできます。
![](https://habrastorage.org/getpro/habr/post_images/e71/f0b/8cb/e71f0b8cb26e78e77bc0b4a409598512.png)
IPv6接続情報の表示
▍オプション-t
-t
オプションは、プロセスIDを除くすべての情報の出力を抑制します。 PIDリストを他のコマンド(ほとんどが
kill-9
にリダイレクトする場合によく使用します。
cindy@ubuntu:~$ lsof -t /var/log/dummy_svc.log 1235 2171 2188 2189 16758 16761 16762
オプションの組み合わせ
通常、
lsof
は、論理ORの原則に従って、いくつかのオプションを使用した結果を結合します。
-a
オプションを指定すると、論理Iの規則に従って結果が結合されます。
もちろん、このルールにはいくつかの例外があります。ここでは、通常どおり、ドキュメントを参照することをお勧めしますが、簡単に言えば、次のように機能します。
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
-
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
-
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
-
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
-
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
-
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
, , -i , -u foo, , , «foo». :
ID (UID) «^» (), -u;
(PID) «^» (), -p;
(PGID) «^» (), -g;
«^» (), -c;
TCP UDP, -s [p:s].
- , , .
-a . , -a, -U -u foo, UNIX, , «foo».
大勝利の物語
ここで少し誇張しているかもしれませんが、「勝利」はそれほど大きくありませんでしたが、何かが起こったとき、議論されることになるので、
lsof
は非常に役に立ちました。
数週間前、テスト環境で新しいサービスのインスタンスを1つ上げる必要がありました。 問題のテストサービスは、稼働中の監視インフラストラクチャに接続されていませんでした。 開始したばかりのプロセスがConsulに登録されなかった理由を見つけようとしました。その結果、他のサービスがそれを検出できませんでした。 「だから、何が問題なのかわかりませんが、ログを見てみます」と思いました。 期待どおりに機能しない場合は、修正しようとしているサービスのログを確認します。ほとんどの場合、ログは問題の根本をすぐに示しています。
問題のサービスは、 サーカスプロセスとソケットマネージャーを使用して起動されました。
circus
下で実行されているプロセスのログは、ホスト上の特別な場所に保存されます-それを
/var/log/circusd
と呼びましょう。 ホスト上の新しいサービスは、別の場所にログを書き込む別のマネージャーs6によって開始されました。 次に、
socklog/svlogd,
ログもありますが、これもまた別の場所にあります。 要するに、ログの不足はなく、主な問題は、どのファイル記述子でログが失敗したプロセスを書き込むかを見つけることでした。
私が理解しようとしているプロセスが
circus
下で実行されていることを知っていたので、
/var/log/circusd/whatever_tab_completion_suggested
tail
コマンドで接続すると、このプロセスの
stdout
および
stderr
スレッドを見ることができます。 確かに、ログを表示してもまったく何も得られませんでした。 私が間違ったログファイルを読んでいたことがすぐに明らかになり、実際に、詳しく見ると、
/var/log/circusd
stage-svcname-stderr.log
と
staging-svcname.stderr.log
2つのファイルがある
/var/log/circusd
が
staging-svcname.stderr.log
。 次に、Tabキーを使用してコマンドを自動補完しましたが、自動的に選択されたファイルは必要なものではありませんでした。
興味のあるプロセスがロギングのために実際にどのファイルを使用したかを理解する1つの方法は、
lsof -l filename
を使用することでした。これは、開いているファイル記述子を持つすべてのプロセスに関する情報を
lsof -l filename
ます。 実行中のプロセスにログファイルが関連付けられていないことがわかりました。このコマンドは
tail
コマンドで調べたため、このファイルは安全に削除できました。
別のファイルを見ると、プロセスがクラッシュした理由がすぐにわかりました(クラッシュ後に
circus
がプロセスを再起動したため、再起動が無限に繰り返されました)。
まとめ
lsof
コマンドを頻繁に使用するほど、より多くのツールが置き換えられ、より便利になります。
lsof
があなたに
lsof
利益をもたらすチャンスを持っていることを願ってい
lsof
。
親愛なる読者! 特によく知られていないLinuxコマンドラインツールは何ですか?