昨天老毕跟我讨论dns的问题,今天想了想,其实实际在生产环境中用到的dns大体有3种:
1.内网调用DNS
 一般是每个机房一组,做ms结构,主要功能是供机房内部应用之间调用解析,减少对hosts的依赖,避免硬编码。一般ms结构就可以了,不太会做其他的高可用。
2.回源调用dns
 和内网调用dns功能差不多,不过这个是跨机房的调用,而且一般会通过view做智能dns解析。
比较常见的应用场景就是webcdn的回源dns,结构上和内部调用dns差不多。
3.外网dns
 提供各种针对外网的解析,A记录,CNAME,MX等等。。
作为用户访问的入口,其重要性也不言而喻,因此对可用性和扩展性以及性能要求会比较高。
 一般的做法是在BGP机房做一个高可用的集群做主要的解析工作,同时在双线或者单线机房做一组冷备的高可用DNS集群。
 这里讨论下用lvs做dns高可用的方案,主要借鉴了mysql高可用的方案(一般都是一个主库,后面挂多个丛库,丛库前面使用lvs+keepalived做ha,程序写入主库,读取丛库)。
具体的流程如下:
1.用户通过web前端来做dns的增删改等操作(如果是python程序的话,可以通过dnspython操作)。
2.slave通过对比zone文件的serial值来决定是否需要更新记录。
3.用户查询请求至由lvs(dr模式)+keepalived组成的前端负载均衡。
4.lvs分发请求至slave server,最后由slave server直接向用户响应请求。

由于dns一般情况是用udp协议的(关于dns使用的协议可以参考之前的blog),而大家一般都是用lvs做tcp的load balance.
在用lvs实现udp的load balance时主要注意以下几点:
1.添加realserver时选择udp,配置文件中设置 protocol UDP
2.应用的监听IP要设置为vip,在这个场景中可以更改slave dns的设置 listen-on port 53 {vip ;物理ip;};
其中vip用来实现接收lvs的转发包并返回数据给用户,物理ip用来实现master到slave的同步
3.health check需要注意,lvs提供的HTTP_GET和TCP_CHECK都是基于TCP协议的(TCP的SYNC包来检查应用)
对于udp的检查可以使用 MISC_CHECK的方式。
比如下面个设置:
virtual_server vip 53 {
     delay_loop 2
     lb_algo rr
     lb_kind DR
     protocol UDP
     real_server real_server1 53 {
     weight 100  
     MISC_CHECK {
          misc_path "/etc/keepalived/check_named.sh real_server1"
          misc_timeout 5
        }
     }
        real_server real_server2 53 {
        weight 100
     MISC_CHECK {
          misc_path "/etc/keepalived/check_named.sh real_server2"
          misc_timeout 5
        }
        }
}
其中/etc/keepalived/check_named.sh的内容如下:
#!/bin/bash
SERVER=$1
OK=`nslookup  www.test.com $SERVER|grep ipxxxx`
if [ "$OK" == "" ] ; then
    exit 1;
else
    exit 0;
fi
即返回0代表dns服务正常,返回1代表服务异常,将会被lvs踢出。
高可用的dns结构图:

高可用dns方案_第1张图片

最后附一个自己写的spec文件,用来实现chroot的自定义rpm包,继承到yum源中实现dns的快速部署。
Name:           Vipshop-Bind-Chroot
Summary:        This is for Vipshop dns server.
Group:          System Environment/Daemons
Version:        1.0
Release:        0
License:        Copyright 2011 Vipshop Inc.
Source:         Vipshop-Bind-Chroot-1.0.tar.gz
URL:            http://www.vipshop.com
Packager:       EricNi
Vendor:         Vipshop Inc.
Provides:       Vipshop Inc.
BuildRequires:  gcc-c++
%description
This is DNS Service pakeage , and it only distributed in Vipshop Servers .
%prep
test -d /usr/local/named && rm -rf /usr/local/named
[ `cat /etc/passwd|grep named|wc -l` -eq 0 ] && useradd named -M -s /sbin/nologin
mkdir -p  /usr/local/named /usr/local/named/var/slaves  /usr/local/named/var/named /usr/local/named/var/etc  /usr/local/named/var/log
mkdir -p  /var/named/chroot/etc/namedb /var/named/chroot/etc/log /var/named/chroot/etc/run   /var/named/chroot/var/run /var/named/chroot/dev/  /var/named/chroot/etc/namedb/slaves  /var/named/chroot/etc/namedb/acl
%setup -n %{name}-%{version}
%build
export BIND_HOME=/usr/local/named
export BIND_CHROOT_HOME=/var/named/chroot
./configure --prefix=${BIND_HOME} --enable-threads  --sysconfdir=/etc  --disable-openssl-version-check
make
make install
cat > ${BIND_CHROOT_HOME}/etc/named.conf << "EOF"
options {
directory "/etc/namedb";
version "vipshop-cdn-dns";
pid-file "/etc/run/named.pid";
listen-on port 53 {any;};
allow-query {any;};
recursion yes;
dump-file "/etc/namedb/cache_dump.db";
zone-statistics yes;
statistics-file "/etc/namedb/named_stats.txt";
};
logging {
   channel warning
   {file "/etc/log/named.log" versions 3 size 2048k;
   severity warning;
   print-severity yes;
   print-category yes;
   print-time yes;
  };
   channel query
   {file "/etc/log/query.log" versions 3 size 2048k;
   severity info;
   print-category yes;
   print-severity yes;
   print-time yes;
   };
category queries
   {
    query;
   };
category default
   {
    warning;
   };
};
zone "." IN {
type hint;
file "named.root";
};
zone "localhost" IN {
type master;
file "localhost.zone";
};
zone "0.0.127.in-addr.arpa" IN {
type master;
file "slaves/localhost.rev";
};
zone "vipshop.com" IN {
type master;
file "vipshop.zone";
notify yes;
also-notify {180.186.22.62;};
allow-transfer {
     180.186.22.62;
                };
};
key "rndc-key" {
        algorithm hmac-md5;
        secret "f8Na2kl/4NuCNPEZ0f2C1Q==";
};
controls {
        inet 127.0.0.1 port 953
                allow { 127.0.0.1; } keys { "rndc-key"; };
};
EOF
cat > ${BIND_CHROOT_HOME}/etc/rndc.conf << "EOF"
key "rndc-key" {
        algorithm hmac-md5;
        secret "f8Na2kl/4NuCNPEZ0f2C1Q==";
};
options {
        default-key "rndc-key";
        default-server 127.0.0.1;
        default-port 953;
};
EOF
cat > ${BIND_CHROOT_HOME}/etc/rndc.key << "EOF"
key "rndc-key" {
        algorithm hmac-md5;
        secret "f8Na2kl/4NuCNPEZ0f2C1Q==";
};
EOF
cat > /etc/rndc.conf << "EOF"
key "rndc-key" {
        algorithm hmac-md5;
        secret "f8Na2kl/4NuCNPEZ0f2C1Q==";
};
options {
        default-key "rndc-key";
        default-server 127.0.0.1;
        default-port 953;
};
EOF
cat >  ${BIND_CHROOT_HOME}/etc/namedb/named.root << "EOF"
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  "
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:    Jan 3, 2013
;       related version of root zone:   2013010300
;
; formerly NS.INTERNIC.NET
;
.                        3600000  IN  NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:BA3E::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     192.228.79.201
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2D::D
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2F::F
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     128.63.2.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::803F:235
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7FE::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:C27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7FD::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:3::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:DC3::35
; End of File
EOF
cat > ${BIND_CHROOT_HOME}/etc/namedb/localhost.zone << "EOF"
$TTL 86400
$ORIGIN localhost.
@ 1D IN SOA @ root (
42 ; serial (d. adams)
3H ; refresh
15M ; retry
1W ; expiry
1D ) ; minimum
1D IN NS @
1D IN A 127.0.0.1
EOF
cat > ${BIND_CHROOT_HOME}/etc/namedb/localhost.rev << "EOF"
$TTL 86400
@ IN SOA localhost. root.localhost. (
1997022700 ; Serial
28800 ; Refresh
14400 ; Retry
3600000 ; Expire
86400 ) ; Minimum
IN NS localhost.
1 IN PTR localhost.
EOF
cat > ${BIND_CHROOT_HOME}/etc/namedb/vipshop.zone << "EOF"
$TTL  86400
@     IN      SOA     ns1.vipshop.com.  root.vipshop.com.  (
                                        2013051501 ; Serial
                                        28800     ; Refresh
                                        14400     ; Retry
                                        3500000   ; Expire
                                        86400 )   ; Minimum
@        IN      NS      dns1
@       IN      NS      dns2
localhost       IN      A       127.0.0.1
img1            IN      A       xxxx
img3            IN      A       xxxx
img2            IN      A       xxxx
img2            IN      A       xxxx
dns1            IN      A       xxxx
dns2            IN      A       xxxx
EOF
cat > /etc/init.d/named << "EOF"
#!/bin/bash
#
# named           This shell script takes care of starting and stopping
#                 named (BIND DNS server).
#
# chkconfig: - 13 87
# description: named (BIND) is a Domain Name Server (DNS) \
# that is used to resolve host names to IP addresses.
# probe: true
                
# Source function library.
. /etc/rc.d/init.d/functions
                
# Source networking configuration.
[ -r /etc/sysconfig/network ] && . /etc/sysconfig/network
                
[ -r /etc/sysconfig/named ] && . /etc/sysconfig/named
         [ -f /usr/local/named/sbin/named  ] || exit 0
       #  [ -f /chroot/named/etc/named.conf ] || exit 0
        case "$1" in
           start)
                  # Start daemons.
                  echo -n "Starting named:"
                  daemon /usr/local/named/sbin/named -c /etc/named.conf -u named -t /var/named/chroot
                  echo
                  touch /var/lock/subsys/named
                  ;;
           stop)
                  # Stop daemons.
                  echo -n "Shutting down named:"
                  #killproc named
          killall named
                  rm -f /var/lock/subsys/named
                  echo
                  ;;
           status)
          #status named
                  pid=`pidof -o %PPID -x named`
                  if [ -z $pid ]
                  then
                        echo "named is stopped!!!"
                  else
                        echo "named is running: pid is $pid"
                  fi
                  exit $?
                  ;;
           restart)
                  $0 stop
                  $0 start
                  exit $?
                  ;;
           reload)
                  /usr/local/named/sbin/rndc reload
                  exit $?
                  ;;
           probe)
                  /usr/local/named/sbin/rndc reload >/dev/null 2>&1 || echo start
                  exit 0
                  ;;
           *)
                  echo "Usage: named {start|stop|status|restart|reload}"
                  exit 1
        esac
        exit 0
EOF
chmod 755 /etc/init.d/named
mkdir -p  /usr/local/named /usr/local/named/var/slaves  /usr/local/named/var/named /usr/local/named/var/etc  /usr/local/named/var/log
mkdir -p /var/named/chroot/usr  /var/named/chroot/etc/namedb  /var/named/chroot/var/run /var/named/chroot/dev/  /var/named/chroot/etc/namedb/slaves /var/named/chroot/etc/run /var/named/chroot/etc/log /var/named/chroot/etc/namedb/acl
chown named:named  /var/named/chroot -R
chown 700 /var/named/chroot
mknod /var/named/chroot/dev/null c  1 3
mknod /var/named/chroot/dev/random c  1 8
cp /etc/localtime  /var/named/chroot/etc/
sed -i 's/SYSLOGD_OPTIONS=\(.*\)/SYSLOGD_OPTIONS=\"-m 0 -a \/var\/named\/chroot\/dev\/log\"/g' /etc/sysconfig/syslog
/etc/init.d/syslog restart
%pre
if [ ! `grep named /etc/passwd` ];then
useradd  -M named  -s /sbin/nologin
fi
%post
chkconfig --add named
chkconfig named on
chown named:named  /var/named/chroot -R
chown named:named /usr/local/named -R
chown 700 /var/named/chroot
%clean
rm -rf /usr/local/named
rm -rf /var/named
%files
/etc/init.d/named
/usr/local/named/
/var/named/chroot/
%doc
%changelog
* Thu May 16 2013 Ericni .
- Create SPEC file.