完全に消費税に負けた...
今日も小ネタです。
一般に、以下のようなことを調べる時 netstat
や ss
などのツールは便利です。
- あるポートがリッスンされているか知りたい
- あるコネクションに実際に通信があるか知りたい
- MySQLサーバなど外部プロセス/サーバにコネクションが貼られているか知りたい
でもコンテナ環境では、そんな余計なツールは入っていない!!!ことも多い。
そんな時でも、 /proc
ファイルシステムはほぼ間違いなくマウントされているはずです。 なのでそこを直接見ることも検討しましょう。
/proc/net/tcp(6)
を眺める
コンテナのネットワークに直接入るには、 nsenter
などを使うことができます。今回はすぐ用意できる環境があったので Haconiwa ですが、 Docker などで置き換えて試してください。
$ ps auxf ... root 13252 0.0 0.1 21600 4400 pts/3 S 11:20 0:00 ./mruby/bin/haconiwa run sample/criu-rails.haco root 13253 1.0 0.1 21600 5440 pts/3 S 11:20 0:00 \_ ./mruby/bin/haconiwa run sample/criu-rails.haco root 13295 25.3 1.6 658332 67404 ? Ssl 11:20 0:01 \_ puma 3.12.0 (tcp://0.0.0.0:3000) [helloworld] <- ここからコンテナ $ sudo nsenter --net -t 13295 # cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 00000000:0BB8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 197041 1 ffff9a80671f5d80 100 0 0 10 0
netstatやssは基本的にこの情報を加工しているだけです。
あるいは、こうなっているかもしれません。
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 7C02010A:A6F2 8E0116AC:0CEA 06 00000000:00000000 03:00000ACA 00000000 0 0 0 3 ffff881f6de59c70 1: 7C02010A:E076 8E0116AC:0CEA 06 00000000:00000000 03:00000AC0 00000000 0 0 0 3 ffff881f7fa76990
読み方は man proc やカーネルのドキュメントにある通りなんですが、
https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt
とりあえず見るのは...
2番目 local_address
自分側のアドレスポート
前者の例は 00000000:0BB8
で、見慣れている表記に直すと:
#!ruby "00000000".scan(/(..)/).flatten.map{|v| v.to_i(16)}.reverse #=> [0, 0, 0, 0] "0BB8".to_i(16) #=> 3000
他の言語でも適宜置き換えてください(String#to_i が便利なのであれですが、他の言語にもあるのかな...)。
ようするに自分のアドレスを 0.0.0.0
で 3000 番ポートをリスンしています。
3番目 rem_address
相手側のアドレスポート
後者の例では3番目に 8E0116AC:0CEA
というアドレスがあり、見慣れている表記に直すと:
#!ruby "8E0116AC".scan(/(..)/).flatten.map{|v| v.to_i(16)}.reverse # 逆になるのに注意 #=> [172, 22, 1, 142] "0CEA".to_i(16) #=> 3306
172.22.1.142:3306
につなぎに行っています。 3306 なのでMySQLかなんかでしょう。
4番目 st
ステータス
この数字がどの状態なのかは例えばカーネルのヘッダー net/tcp_states.h
にあるので、
これを参考に10進数に変換するといいです。
- ESTABLISHED =
01
- TIME_WAIT =
06
- LISTEN =
0A
(10)
など。前者はLISTEN、後者はTIME_WAITですね。
9番目 timeout
この値があまりにカウントアップしていたら、その通信は何かしらの理由で腐っているかもしれません。相手側が応答しないとか。
ちなみに
tcp
でリスンしていなくても tcp6
でリスンしている場合もあります。以下はとある Apache の例。
$ sudo nsenter --net -t 27866 cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode $ sudo nsenter --net -t 27866 cat /proc/net/tcp6 sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 00000000000000000000000000000000:1F90 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 41622137 1 ffff955d74551100 100 0 0 10 0
tcp6、めっちゃ長い。ポートは同じように "1F90".to_i(16) => 8080
。
にも関わらず ipv4 127.0.0.1:8080
などでアクセスできるのですが、これはIPv4-mapped IPv6アドレスというやつですね。こちらが詳しいです。
全く知らないとハマる(ハマった)こともあると思いますので一応。