インフラエンジニアの中西です。 最近プログラマーからこのような話を耳にします。
「ネットワークって難しい/よくわからない」
最近では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アドレスを経由していることが分かります。 詳細な解説はさておき、辿りつけなかった場合は問題が発生しています。詳しい人間を呼んだほうが良いです。
また、下記のページも押さえておくと良いと思います。
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 | 状態不明のソケット |
とこれだけのステータスがあります。書いてみたものの分かりにくいので図を探したところ分かりやすいものがあったので貼っておきます。
こちらの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
ポートスキャンをかけることが出来るコマンドです。 こちらについては下記がよくまとまっているので参考にしてください。
くれぐれも実行はローカル環境にて行うようにしましょう。 不正アクセス禁止法に抵触する可能性や、裁判沙汰になる可能性があるので、面白いからといって様々な外部サービスにポートスキャンをしないようにしましょう。
自社サービスのリリース前等に試しておくのが良いと思います。
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 も皆さん良く使うと思います。 奥が深いのでどこまで知るかは差が出るところですが、このあたりは便利だと思います。
丸投げですいません。
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しているので何かの役に立てばという思いで書いたのが始まりです。
最後までお付き合い頂きありがとうございました!