Kekeの日記

エンジニア、読書なんでも

DNSの仕組みとIPアドレス

https://beyondjapan.com/wp/wp-content/uploads/2018/01/Cloud-DNS-1.png

DNSとはおおまかに何?

詳しいことはあとで解説します。

DNSとはDomain Name Systemの略で、例えばhttps://yahoo.co.jpがどのIPアドレスを指して、それを返すことで私たちはヤフーというサイトをみることができる。

そのようにIPアドレスという通信相手の特定のために使われうる機械に優しいように2進数で表されているものを、私たち人間が通信相手を直感的にすぐわかるようにドメイン名で対応づけするのがDNSの役割である。

yahoo.co.jpというドメイン名をDNSから対応するIPアドレスを取得することをDNSに問い合わせるという。また紐づくIPアドレスとドメイン名を取得することを名前解決という。

f:id:bobchan1915:20181025223313p:plain

もちろんDockerをはじめとする仮想コンテナ同士の通信や、Kubernetesのコンテナオーケストラソフトウェアも同様の仕組みを持っている。

Kubernetesクラスタ内で問い合わせられる内部DNSが存在していて、例えばService FrontendからService backendはクラスタ内ではhttp://backendで問い合わせられたりする。

今回はこのDNSがどのように機能しているのか、どう設計したら良いのかを考える。

IPアドレスとは

IPアドレスとは、ビット列であり、101010100000101...のようなものである。

f:id:bobchan1915:20181025223349p:plain

しかし、私たちが開発しているときに見るとするIPアドレスは192.101....のような形をしている。

これは先ほどのビット列を8ビット(256)区切りした、2進数に直している。このようにすることでIPアドレスを私たち人間が簡単に管理しやすくなる。

f:id:bobchan1915:20181025223259p:plain

つまり、もっとも小さな0だけのビット列で構成されるIPアドレスは0.0.0.0で、最大でも255.255.255.255にしかIPアドレスは存在しないことになる。

余談になるが、電話番号のうんちく話があって、電話番号自体が10進数で多くても10桁なのは人間の記憶限界を調査した上で人間が覚えられるもっとも多い桁数らしい。

自分の今のIPアドレスは以下のように確認することができる。

$ ifconfig

IPアドレスの一意性

IPアドレスを知ることは通信相手を特定することと同値である。それは国民ナンバーも同様である。つまり、一意でなければならないのだ。

あるサイト、例えばhttp://futatu_ip_aru_siteを開こうとDNSに問い合わせてIPアドレス35.103.40.10134.293.203.2が帰ってきたらだめである。

ポータルサイトを開こうとしたら、悪質なサイトを開いてしまうかもしれない。(実際にDNSを書き換えられるDNSキャッシュポイゾニングという手法がある)

その一意性を管理するためにもICANNという組織がある。

グローバルIPアドレスとプライベートIPアドレス

IPアドレスには大きく4つの種類がある。

名前 概要
グローバルIPアドレス 一意に定まるIPアドレス
プライベートIPアドレス ローカルなネットワーク(例えばLAN)などで有効なIPアドレス
ループバックIPアドレス 自分自身を指す特別なIPアドレスで127.0.0.1でありlocalhostと言う名前です。
ブロードキャストIPアドレス そのネットワークに所属するすべてのホスト全体を示すものである。ネットワーク全体に通信ができて、ホスト部がすべて1であるもの。

注意点としてはプライベートIPアドレスからはインターネットに接続できないので、送信元にも受信元にもなることができない。なので、ゲートウェイなり何らかの処置をしなければいけなくなるが、大体はインターネットにアクセスする必要性はない。

またプライベートアドレスで使われるIPは以下の通りである。

  • 10.xxx.xxx.xxx
  • 172.xxx.xxx.xxx
  • 192.168.xxx.xxx

この範囲のIPアドレスであればプライベートアドレスであることがわかる。

例えばKubernetesのPodのIPアドレスもプライベートIPアドレスであり、以下のように取得することができる。もちろん、このIPアドレスに外部からアクセスすることはできない。

PODIP=kubernetes get pod  -o=jsonpath='{.status.podIP}'

curl $PODIP
curl: (7) Failed to connect to 10.28.1.77 port 80: Connection refused

サブネットマスクとCIDR記法

よくインフラ構築などをしているとサブネットマスクとCIDR記法に出くわすので知っておいた方がいいでしょう。

サブネットマスク

IPアドレスの先頭の何ビットをネットワークアドレスに使うかを定義する32ビットの数値である。

CIDR記法

ネットワークアドレスを任意に決められる仕組みです。

経路制御

IPアドレスを知ると通信ができる。と述べたが、ただやみくもに相手に届けようとするのではなくて、れっきとした通信経路をもつ。

例えば電話番号でいう+81だろう。

IPアドレスにもネットワーク部とホスト部があり、ネットワーク部が電話番号でいう地理的な譲歩を持っていて、ホスト部でだれかを特定する。

インターネットとは、そもそもネットワークの集まりであり、それぞれはルーターによって接続されている。

それぞれのネットワークは主に企業がもっていて、ルータ内への通信を受け、ルータ内でないなら他へ転送する仕組みである。

つまり、ネットワーク部を見れば誰に接続すればいいのかがわかる。さらに、ホスト部はそのネットワーク部内の特定する仕組みなので、ホスト部を見れば通信相手が特定できるというわけである。

また、このような誰がどのIPアドレスを管理するのがIPテーブルというものである。

ドメイン名の構造

以下のようにドメイン名の構造は階層化されている。

もともとはフラットで階層がなく、すべてのIPアドレスを一つのシステムで管理していた。

しかし、インターネットが普及すると対応しきれずに.jpや.comのように管理をそれぞれの管理組織(レジストリ)に委任していった。

それぞれの.で区切ったものをラベルと呼び、右側から左側へいくほど階層が下位のものになっていく。

f:id:bobchan1915:20181025224834p:plain

短縮URLって?

せっかくドメインについて学ぶなら特に身近なものを取り上げる。

特にTwitterをしていると短縮URLという、人間が読んでもわからない短かいリンクが貼っているのを目にした人がいるかもしれない。

ユースケースとしては例えばクエリパラメータが大量に付与されていたりするリンクは長いときである。これを短縮URL提供サービスに送信すると何らかの一意に短くできるアルコリズムで短縮URLを生成されて返される。

f:id:bobchan1915:20181025225330p:plain

また、この生成元となったリンクと生成後を紐づけてデータベースで永続化をする。

f:id:bobchan1915:20181025225420p:plain

リンクが開かれると元のURLを返すという仕組みである。

f:id:bobchan1915:20181025225647p:plain

名前解決の仕組み

まず、スタブリゾルバというクライアント側のソフトウェアが、利用しているISPのキャッシュDNSに名前解決を要求する。

ここでISPとは、インターネットサービスプロバイダのことで、あなたをインターネットに接続してくれる役割を担っている人である。

キャッシュDNSは何をするかというと、それぞれの権威DNSサーバーに階層ごとに問い合わせしてIPアドレスを解決していく。

つまりまず権威DNSサーバーにアクセスして、ここにはそのIPアドレスはないが.jpのDNSサーバに聞いてくれとレスポンスが入る。

次に.jpのDNSサーバにアクセスするとここにはそのIPアドレスはないがexample.jpのDNSサーバに聞いてくれとレスポンスが入る。

また、最後にexample.jpのDNSサーバにアクセスするとやっとIPアドレスが取得できスタブリゾルバが取得して、PCのアプリケーションに引き渡すっという感じである。

この仕組みによって、柔軟に、非常に大きなスケールでIPアドレスとドメインを対応させることができたのである。

また、名前解決にも二つの種類がある。

正引き

ドメイン名からIPアドレスを取得する方法である。

f:id:bobchan1915:20181026002337p:plain

これはDNSクエリをすることができます。

$ host example.com
=> IPアドレスが返ってきます

ここでリソースレコードを取得したければ-tオプションで-anyをつけると取得することができます。

逆引き

あまり使いませんが、IPアドレスからドメイン名を取得する方法です。

f:id:bobchan1915:20181026002327p:plain

より深く知る

サブドメインとゾーン

例えばAPIサーバーなどはapi.hogehoge.comのようにサブドメインであるapi.がつけられていて、本体のWebアプリケーションはhogehoge.comだったりする。

サブドメインというようにドメインよりも下位の概念であり、左にいけばいくほど下位の概念になるルールからもわかると思う。

しかし、注意点としてサブドメインで定義されるゾーンにも委任をするかしないかでゾーンとして成立する場合と成立しない場合の二つ種類がある。api.で委任されずにhogehoge.comと同様に管理されていて同じゾーンであるケースや逆の場合もある。

ゾーンごとに権限が管理されているので、それを知る必要がある。

DNSの詳しいこと

動作原理

最初に大まかに動作を簡単に説明した。しかし、キャッシュっという言葉が名前解決をしてくれるサーバーについているようにキャッシュ機能を使っていることを理解するにはもう少し具体的に説明する必要がある。

  1. まずアプリケーションからクライアント側のスタブリゾルバにドメイン名が渡されて、名前解決が始まる。このときにhogehoge.comのIPアドレスをくれ!というリクエストをキャッシュDNSサーバーに送る。

f:id:bobchan1915:20181026001046p:plain

  1. キャッシュDNSサーバーからは自身のキャッシュに「hogehoge.comがIPアドレス34.193.234.3ですよ」などの情報をキャッシュしてなければ、権威DNSサーバに名前解決のために反復検索をするようになる。ここではヒントファイルといるルートサーバーの一覧があって、そのルートサーバーに問い合わせるようになる。

f:id:bobchan1915:20181026001153p:plain

  1. ドメインの委任から.jpや.comのゾーンを管理しているDNSサーバーに問い合わせろとレスポンスが返る。
  2. これをどんどん下位のIPアドレスが特定できるまでのゾーンまで続ける。IPアドレスを渡す際に、そのサーバーは権限をもってIPアドレスを返す。

f:id:bobchan1915:20181026001251p:plain

  1. スタブリゾルバがアプリケーションにIPアドレスを渡す。IPアドレスはキャッシュ用のデータベースにも記録される。キャッシュは有効期限が切れるまではスタブリゾルバに直接的にIPアドレスを返すために使われる。

以上のような流れになっている。厳密に書くと以下のようになります。

f:id:bobchan1915:20181026001444p:plain

負荷分散

階層構造

私たちがIPアドレスに紐づくようなWebページ(すべてだが)にアクセスをすると、この問い合わせが始まる。

しかしYahooにもyahoo.comyahoo.co.jpのようにルート自体がもっとも負荷のかかるようになっている。これは仕方ないが、逆に下位の.jpなどは負荷がかからないのである。

f:id:bobchan1915:20181026001714p:plain

キャッシュを使う

また、先ほどの動作原理にもあったようにキャッシュという仕組みを使っているので一回問い合わせて名前解決をされた履歴があれば、一定期間ないなら反復解決をしなくてもIPアドレスを取得することができる。

f:id:bobchan1915:20181026001831p:plain

ネガティブキャッシュ

次にネガティブキャッシュをいう仕組みを説明しておく。あるドメインに対して毎回IPアドレスを取得せずに保存しておくのがキャッシュであった。その反対に、IPアドレスが存在せずに名前解決できないものもキャッシュしておくのがネガティブキャッシュである。これは間違ったドメイン名を問い合わせているときに毎回名前解決のために反復検索をしなくて済むようしているのである。

f:id:bobchan1915:20181026001904p:plain

TTL、DNS浸透期間とサービスダウンのリスクは

f:id:bobchan1915:20181029014819p:plain

キャッシュの有効期限をTTL(Time to live)といい、どれだけ保持し、同じドメインに対してキャッシュを使うかを設定する。

逆をいうと、変更されてもキャッシュDNSサーバーに保持されているため、DNSのリソースレコードを設定してもすぐに反映されるわけではない。

この時に有効期限内ならば元のIPアドレスをキャッシュをしているので新しいIPアドレスを取得せずに返してしまう。 キャッシュの有効期限が切れると新しいIPアドレスにアクセスできるようになります。この期間をDNS浸透期間と言う。

このこれを設定することでいつまでも古いIPアドレスにアクセスしないようにすることができる。

しかし、これがリスクになったりします。例えばサーバーを移行して古いサーバーを削除した場合、キャッシュでは世の中にすでにないIPアドレスを持っていたりしていて、このときにアクセスすると404が返ってくる。このような面でDNS浸透期間は早ければ早いほどいい(=すぐに新しいIPが反映される)状態は必ずしもいいわけではなく、運用という面ではリスクがある。

f:id:bobchan1915:20181029015111p:plain

長いのとは反対に、TTLが短いとキャッシュをしなくなるので毎回権威DNSサーバーにアクセスをするのでキャッシュDNSサーバーのキャッシュをうまく使えず、負荷がかかってしまう。

つまりTTLはトレードオフになっていて、DNSサーバーへの負荷とリソースレコードの移行のしやすさを適切に選ばない。

f:id:bobchan1915:20181029015436p:plain

まとめ

DNSを理解することは、ドメインとIPアドレスがどのように名前解決されるのかを知るには重要な概念です。

また、自分のドメインを取得して割り当てたりするにはこのような知識が必要です。

ドメインレジストラというドメインを買えたりするシステムがあるからこそ重要になってきます。