2015/10/10

Rails と bind-sdb を連携してみる

DB と連携した DNS を立てることになったので、そのDBの操作を Rails でやってしまおう、というお話。

環境

  • OS : Mac OSX 10.10.5
  • Docker : 1.8.1 (docker-machine)
  • Ruby : 2.2.3
  • Rails : 4.2.4
  • PostgreSQL : 9.4
  • Bind-SDB : 9.9.4

Bind-SDB について

通常の bind だと zone ファイルとかを更新したりする必要があるのですが、 sdb インターフェースというものを使うと zone ファイルではなくてDBのレコードを使って名前解決とかできるらしいです。
具体的には CentOS とかだと bind-sdb(bind-sdb-chroot) パッケージ。
バックエンドはデフォルトでは PostgreSQL なので PostgreSQL で。 一応 MySQL のアダプタもあります。
レコードに要求されるカラムは以下の4つ。
  • name : DNS を引く時の key。 A record ならFQDNとか。
  • rdtype : レコードの種類。 A とか AAAA とか SOA とか。
  • rdata : DNS を引く時の value。 A record ならIPとか。
  • ttl : レコードのTTL
この4つがきちんと引けていれば動くようなので、この構造を持ったモデルを作ってしまえば Rails で管理できそうだな、ということで実際に作ってみました。

サンプルアプリケーション

サンプルとしてちょこっと書いてみました。(https://github.com/atton-/bind_sdb_with_rails)
*.hoge.com を解決できるようなDNSを作れます。
一応逆引きもできるようにしてるのでアドレス帯域は 10.100.200.0/24 くらい。
rails server して、 domain を入れて IP の最後のオクテットを数値で入れると名前が解決できます。
例えば、 rake db:seed では aaa.hoge.com というレコードを入れるので
$ dig aaa.hoge.com @<your-dns-ip>
とかすると 10.100.200.1 と返します。
実行コマンドは README.md に書いてますが、コンテナのIPが環境によって違うのでちょっと書き換えが必要です。
あと DOCKER_HOST が設定されていること前提。OSX で docker-machine を使っていれば設定されているはずです。

やってること

やっていることはドメインの文字列とIPの組から A レコードと PTR レコードを作ってるだけです。
ドメインとIPが入る record モデルを作って
A レコードが入る forward_record モデルと PTR レコードが入る reverse_record モデルを作って has_one で持たせる。
record モデルの after_save くらいで forward_record と reverse_record を生成してやります。
あとは bind-sdb 側がやってくれます。

bind-sdb 側の設定として、 /var/named/chroot_sdb/etc/named.conf にDBサーバのIPを指定する必要があります。
どうやら名前で書くのはダメなようで、IPで直接指定します。
今回は docker container で DB を持っているので、 docker の host か DB の container の IP を書いてから build するようにしてます。ちょっと面倒。

bind-sdb は特定の zone を特定のテーブルから引く、という処理をするようなので、正引き用の zone は forward_records テーブルを、逆引き用のzoneは reverse_records テーブルを見るようにします。
あとは forward_records/reverse_records に SOA/NS を突っこんでやれば動きます。
ただ、ゾーンを転送する際はテーブルの中に入っているもの全てを転送してしまうようなので、複数のゾーンを1つのテーブルに入れてしまわないように注意。一応転送しないのなら動きはしますが……
ちなみに select するだけのようなので、 read only の view とかを切って複数のゾーンに対応することもできます。そうすれば Rails 側の association が多くなることも無いです。
もちろん AAAA レコードも追加できるので IPv6 も対応可能。今回はゾーンを書くのが面倒だったので v4 のみで。
あとは転送とかするのなら SOA のシリアルの管理もきちんと。 record モデルの after_update くらいに SOA のシリアルを上げる処理を書いてやる形とか。

ということで、 Rails でドメインとIPを申請すると名前が解決できるようになりました。

実行コマンド例

一応置換してね、みたいな記述をしているつもりなのですけれど、具体的な値で実行してみた時の例を載せておきます。
  • $ git clone https://github.com/atton-/bind_sdb_with_rails
  • $ cd bind_sdb_with_rails
  • $  echo $DOCKER_HOST
    • tcp://192.168.99.100:2376
    • docker のホストのIP は 192.168.99.100 のようなのでこれを使います。
  • $ docker build -t pg94 docker/postgres
  • $ docker run -itd --name postgres-server -p 5432:5432 -e POSTGRES_PASSWORD=hogehoge pg94
  • $ rake db:create db:migrate db:seed
    • ここで aaa.hoge.com, 10.100.200.1 が追加される。
  • $ rails server
    • http://localhost:3000 でレコードの追加とかができます。
  • $ sed -i -e 's/postgres-server/192.168.99.100/'
  • $ docker build -t bind_sdb_with_rails/bind-sdb docker/bind-sdb
  • $ docker run -itd --name name-server -p 53:53 -p 53:53/udp bind_sdb_with_rails/bind-sdb
    • この段階でDNSが立ち上がります
  • $ dig @192.168.99.100 aaa.hoge.com
    • 正引きチェック
  • $ dig @192.168.99.100 -x 10.100.200.1
    • 逆引きチェック

参考

0 件のコメント:

コメントを投稿