LIVESENSE ENGINEER BLOG

リブセンスエンジニアの活動や注目していることを発信しています

プログラマーが「ネットワーク怪しくない?」と思った時に覚えておくと便利なことまとめ

インフラエンジニアの中西です。 最近プログラマーからこのような話を耳にします。

「ネットワークって難しい/よくわからない」

最近ではAWS,GCPをはじめとするクラウドサービスが充実しているのでWeb界隈のエンジニアはなおさら気にするシーンが少なくなったように思います。 今日は最低限これだけ覚えていたら有事の際にちょっとは役に立ちますよという話が出来たらなと思います。

書式統一のため sudo を省略しています。ご容赦下さい。

コマンド編

ping

ping です。疎通確認を行う時のコマンドです。 さすがに分かると聞こえてきそうですね。

例えば、192.168.1.1 というサーバに通信を確認したい場合はこうです。

$ ping 192.168.1.1

繋がる場合はこうなります。

$ ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: icmp_seq=0 ttl=60 time=5.614 ms

複数台を一気に確認したい場合はこうなります。

$ for i in $(seq 1 10) ; do ping -c 1 -i 0.5 -w 1 192.168.1.${i} ; done

-c は送信回数、-i は送信間隔、-w はタイムアウトする時間(秒)です。

ping で疎通が確認できなかった場合は、ネットワーク、サーバに異常が考えられるのでより詳しい人間を呼んだほうが良いです。

traceroute

対象のサーバまでのネットワーク的な経路を教えてくれるコマンドです。

$ traceroute 192.168.1.1
traceroute to 192.168.1.1 (192.168.1.1), 64 hops max, 52 byte packets
 1  192.168.24.1 (192.168.24.1)  4.159 ms  2.258 ms  2.014 ms
 2  10.27.3.1 (10.27.3.1)  2.189 ms  1.894 ms  2.027 ms
 3  172.16.24.4 (172.16.24.4)  3.845 ms  5.210 ms  3.908 ms
 4  192.168.1.1 (192.168.1.1)  4.830 ms  6.539 ms  4.964 ms

これは弊社のとある環境の出力なのですが、192.168.1.1 というサーバに辿りつくには3つのIPアドレスを経由していることが分かります。 詳細な解説はさておき、辿りつけなかった場合は問題が発生しています。詳しい人間を呼んだほうが良いです。

また、下記のページも押さえておくと良いと思います。

orebibou.com

traceroute はオプションによって、UDP/TCP を使い分けることができるので便利ですね。

netstat

ホストのネットワーク接続状態を確認するコマンドです。こちらも便利なコマンドなので覚えておくと良いと思います。

使い方は下記です。

$ netstat -n
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 192.168.1.1:33863             192.168.1.2:22              ESTABLISHED

プロトコルが TCP、接続元が 192.168.1.1 の 33863 番ポート、接続先が 192.168.1.2 の 22 番ポート、状態が ESTABLISHED であることが分かります。

netstat ではオプションをよく使うので以下に代表的なものを紹介しておきます。

オプション 意味
-a 全ての接続を表示
-n ホスト名/IPアドレス等を解決せずに数字で表示
-r ルーティングテーブルを表示
-t tcpに限定する
-u udpに限定する
-i ネットワークインターフェースの情報を表示
-p PIDと各ソケットが属するプログラム名を表示
-l listen してるもののみ表示

また、上記出力で出てきた State ですが ESTABLISHED 以外にも以下の State があるので押さえておくと良いです。

よくある話だと、SYN_SENT でステータスが止まる状態かと思います。 これは接続先側でファイアーウォール等で DROP されている可能性があったりします。

State 意味
ESTABLISHED 接続が確立されている状態
SYN_SENT 接続要求(SYN)を送信した状態(応答/ACKは受けてない状態)
SYN_RECV 接続要求(SYN)を受け取った状態
FIN_WAIT1 ソケットを閉じ、接続を落としている状態
FIN_WAIT2 接続はクローズされ、ソケットはリモート側からの切断を待っている状態
TIME_WAIT 接続終了を待っている状態
CLOSED ソケットが使用されていない
CLOSE_WAIT 接続相手はクローズし、自身はクローズ待ちの状態
LAST_ACK FINに対する応答(ACK)待ち
LISTEN 接続待受状態
CLOSING FIN_WAIT1でFINを受け取り接続が閉じられた状態
UNKNOWN 状態不明のソケット

とこれだけのステータスがあります。書いてみたものの分かりにくいので図を探したところ分かりやすいものがあったので貼っておきます。

www.atmarkit.co.jp

こちらのTCPの状態遷移図を参照してください。

telnet

telnet はいいコマンドです。そんなに難しくもないので覚えておくが吉です。 何がいいかというと手早くポートが空いているか確認できます。

下記は空いているケースです。

$ telnet www.example.com 80
Trying 93.184.216.34...
Connected to www.example.com.
Escape character is '^]'.

空いていないと Trying から進まなかったり、 Connection refused と返ってきたりします。 コンテンツが閲覧できないなぁと思った時にとりあえず対象サーバの80番ポートに試してみると良いかと思います。

nmap

ポートスキャンをかけることが出来るコマンドです。 こちらについては下記がよくまとまっているので参考にしてください。

orebibou.com

くれぐれも実行はローカル環境にて行うようにしましょう。 不正アクセス禁止法に抵触する可能性や、裁判沙汰になる可能性があるので、面白いからといって様々な外部サービスにポートスキャンをしないようにしましょう。

自社サービスのリリース前等に試しておくのが良いと思います。

lsof

もし、nmap 等で空いているポートが見つかった場合などはこのコマンドです。 特定のポートがどのプロセスによって使われているか調べることができます。

$ lsof -i:80
COMMAND   PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
nginx   11302  root    8u  IPv4 68106520      0t0  TCP *:http (LISTEN)
nginx   11303 nginx    8u  IPv4 68106520      0t0  TCP *:http (LISTEN)
nginx   11304 nginx    8u  IPv4 68106520      0t0  TCP *:http (LISTEN)

といった具合ですね。あれ?このポート何で使ってるんだっけ?という時に便利です。

dig

名前解決の確認に使うコマンドです。

$ dig j-sen.jp

; <<>> DiG 9.8.3-P1 <<>> j-sen.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39969
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;j-sen.jp.            IN  A

;; ANSWER SECTION:
j-sen.jp.     2013    IN  A   180.214.38.227

;; Query time: 23 msec
;; SERVER: 192.168.20.221#53(192.168.20.221)
;; WHEN: Tue Apr 26 17:38:55 2016
;; MSG SIZE  rcvd: 42

かいつまんで簡単に説明しますと ANSWER SECTION: ここが大事です。 名前解決できていないケースだと ANSWER SECTION: が表示されません。

SERVER: についてですが名前解決を行っているサーバのIPアドレスです。いわゆるDNSサーバと呼ばれるものです。

といった感じですが、出力が長いですね。ちょっとした小技があります。

$ dig +short j-sen.jp
180.214.38.227

ANSWER SECTION: 部分だけを出力してくれます。簡単に確認するならこれが楽でいいです。 さて、名前解決が出来ない場合どうしましょう。詳しい人を呼ぶのはもちろんですが外部のDNSを利用している場合は、そのDNSサーバだけなのかを切り分ける必要がありそうです。

DNSサーバを指定して名前解決を試みることができます。

$ dig @8.8.8.8 +short j-sen.jp
180.214.38.227

@ にIPアドレス or ドメイン名で行えます。 これによってDNS全域なのか特定のDNSサーバだけなのかが分かります。 また、上記で紹介したコマンドたちと組み合わせることによってネットワーク経路の問題なのか、DNS側の問題なのかも切り分け可能となります。

ssh

ssh も皆さん良く使うと思います。 奥が深いのでどこまで知るかは差が出るところですが、このあたりは便利だと思います。

qiita.com

丸投げですいません。

ifconfig/ip addr show

そもそもアドレスなんだっけ・・・?となった時はこれです。

$ ifconfig
$ ip addr show

どちらのコマンドでもIPアドレスの確認が行えます。 ちなみに ifconfig の man には This program is obsolete! とあるので今後は ip addr show の流れのようです。

ちなみに上記のコマンドで自身に付与されているIPアドレスの確認が行えますが、自分が使用しているグローバルIPアドレスを確認したくなるシーンがあるかと思います。そのような時には下記で確認できます。

$ curl inet-ip.info
$ curl httpbin.org/ip

等で取得することができます。

実装編

プログラマーの方から見たときにネットワーク的なところで気をつけないといけないことはあるのでしょうか。 インフラから見ている私が1つだけ考慮に入れておいたほうが良いと思うことがあるので紹介します。

  • ネットワークは切れるという前提を考慮しておく

例えば、日時でデータベースへレコードを更新するバッチ処理があったとします。そのバッチ処理にはデータベースへの接続断が発生した場合の再接続と必要に応じたリトライ処理が考慮されていませんでした。結果、バッチ全体が異常終了し、日時でのデータ更新が行えませんでした。

こんなケースもあるので実装の際にはネットワークは切れることもあると頭の片隅に置いておくのが良いかと思います。

学習編

ここまでは知っておいて損はないコマンドを紹介してみました。 では、ネットワークをほとんど意識してこなかった方が勉強するにあたって良い教材をいくつか紹介したいと思います。

超初心者向けはここです。

ちなみに3分間を終えると30分間版もあります。

一通り読んで、次の段階へ行きたいなぁと思う人はこのあたりが良いと思います。

さらにさらにという方は、

こちらもいかがでしょうか。

さいごに

簡単ではありますが、ネットワークについてプログラマー視点で書いてみました。 弊社でも新卒のプログラマーが数名JOINしているので何かの役に立てばという思いで書いたのが始まりです。

最後までお付き合い頂きありがとうございました!