Bind 9.10のGeoIP機能を使って、リクエスト元に近いサーバのIPを返す


はじめに

海外から日本のサーバに接続すると、予想外の遅さに少し驚くことがあります。
例えば、ロンドンから日本のサーバにHTTPでアクセスをすると、明らかにワンテンポ遅い感じです。
試しにhttpingコマンドでqiita.comへのHTTP接続を計測してみたところ、547msの平均応答速度でした。

仮に日本以外に海外でも展開するサービスを作るとしたら、もっと応答時間を早くしたいものです。

$ httping -c 3 qiita.com
PING qiita.com:80 (/):
connected to 54.248.127.202:80 (386 bytes), seq=0 time=579.29 ms
connected to 54.248.127.202:80 (386 bytes), seq=1 time=530.49 ms
connected to 54.248.127.202:80 (386 bytes), seq=2 time=533.82 ms
--- http://qiita.com/ ping statistics ---
3 connects, 3 ok, 0.00% failed, time 4645ms
round-trip min/avg/max = 530.5/547.9/579.3 ms

これは、予算に余裕があれば、Amazon Route 53Amazon CloudFront CDN, CloudFlare等を使えばすぐに解決できる問題ですけど…。
ConoHaにもGeoDNS機能があり、コスパも高いし魅力的なのですが、リージョンにヨーロッパがないのが残念。

オレオレCDN

  1. 海外の格安VPSを活用して、複数の大陸にサーバを設置
  2. DNSでの名前解決で、リクエスト元に近いサーバのIPを返せばOK

Bind 9.10 の新機能として、GeoIP機能が搭載されており、クライアントのIPの国・都市・タイムゾーンなどを元に、名前解決の結果を分ける事ができます。
この機能を使って、例えばヨーロッパの利用者はヨーロッパのサーバのIP、アジアの利用者は日本のサーバのIPを返すように構成すれば良さそうです。

構成

リクエスト元 近いサーバの場所
ヨーロッパ・アフリカ・中東・ロシア ロンドン
日本・韓国・中国・東南アジア 東京
北米・南米・その他 ニューヨーク

海外格安VPSを活用する (Vultr編)

最近、格安海外VPSのVultrを使い始めました。
Vultrを選んだ理由は、ArchLinuxをインストールできる事と安い事なのですが、ふと簡易CDNとしても使えるのではないかと思い立ちました。

Vultrは、DigitalOcean的な立ち位置のVPS業者ですが、東京にもリージョンがある、月$5の最安プランでのサーバのメモリ容量が768MBとDigitalOceanより256MB多い(その代りSSD容量は5GB少ない)のがより魅力的に感じました。
オフィシャルのクーポンもあり、2016年1月現在では$50(ただし2ヵ月で消える)のクレジットが貰えるようです。

ヨーロッパと日本、アメリカに3台サーバを設置したとして、月$15です。
転送量は月1TBまで無料。
小規模のスタートアップや個人で運用するサービスには、なかなか良いのではないでしょうか。

動作確認環境

  • Ubuntu 14.04 64-bit
  • BIND 9.10.3

Bind 9.10

インストール

ubuntu14.04-add-bind9.10-ppa.sh
#!/bin/bash
sudo add-apt-repository ppa:mgrocock/bind9
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 083F021DDC682B55
sudo apt-get up{dat,grad}e -y

BindでGeoIP機能が有効かを確認

$ named -V | sed -r 's/ +/\n/g'|grep geoip
'--with-geoip=/usr'
# OK

GeoIPデータベースを入れる

# $ sudo apt-get install geoip-database
or
$ sudo apt-get install geoip-database-contrib

※geoip-databaseの方は内容が古いようで、一部のIPの国を認識できなかったので、geoip-database-contribの方がお勧めです。

設定

試しに、日本と英国、二カ国からのアクセスに対して設定してみます。

  • 「example.com」への名前解決要求

    • クライアントのIPが日本 ⇒ 東京サーバのIPを返す
    • クライアントのIPが英国 ⇒ ロンドンサーバのIPを返す
/etc/bind/named.conf.options
/* 地域 */
acl "jp" { geoip country JP; };                                                                                    
acl "uk" { geoip country GB; }; 

/* 中略 */

/* 追記 */
options {
    geoip-directory "/usr/share/GeoIP";
};

国コードには、ISO-3166-1の2文字、又は3文字のコードを指定します。

geoip ディレクティブには、他にも都市やタイムゾーンも指定できるとのことです。
Chapter 6. BIND 9 Configuration Reference より抜粋:

geoip [db database] field value

# examples
geoip country US;
geoip country JAP;
geoip db country country Canada;
geoip db region region WA;
geoip city "San Francisco";
geoip region Oklahoma;
geoip postal 95062;
geoip tz "America/Los_Angeles";
geoip org "Internet Systems Consortium";

次にゾーンファイルを更新します。`
match-clients に、先ほど定義した国に対応したaclを指定するだけです。

/etc/bind/named.conf.default-zones
view "jp" {
 match-clients { jp; };
 zone "example.com" {
  type master;
  file "/etc/bind/example.com.tokyo.zone";
  /* 以下略 */
 };
};

view "uk" {
 match-clients { uk; };
 zone "example.com" {
  type master;
  file "/etc/bind/example.com.london.zone";
  /* 以下略 */
 };
};

view "other" {
 zone "example.com" {
  type master;
  file "/etc/bind/example.com.other.zone";
  /* 以下略 */
 };
};

ゾーンファイルの example.com.london.zone の内容は、特筆することはなくごく普通です。
IPのAレコードが国ごとに違うだけ。

デバッグ

国と対応させたviewが正しく識別されているかをログで確認します。

参考: BINDのviewを用いた内部向けDNS構築メモ

named.conf.options
logging {
 channel queries_file {
  file "/var/log/named/queries.log"
  versions 3 size 5m;
  severity dynamic;
  print-time yes;
 };
};

各国のクライアントからテストでDNSクエリを送ります。
※1.2.3.4は本当は上で設定したIP

$ nslookup examples.com 1.2.3.4 

ログを確認します。

/var/log/named/queries.log
08-Jan-2016 8:45:10.527 client 104.238.171.177#39341 (example.com): view uk: query: example.com IN A + (172.31.22.25)
08-Jan-2016 8:49:30.593 client 202.157.182.142#2043 (example.com): view other: query: example.com IN SOA -T (172.31.22.25)
08-Jan-2016 8:54:06.839 client 157.192.160.134#40687 (example.com): view jp: query: example.com IN A + (172.31.22.25)

OK

あとは、aclでの国定義を増やしていき、クライアントの国に対応したサーバを更に適切に返せるように詰めていけば良さそうです。

参考