VyattaのWAN Load Balancing機能とUnboundでWAN Proofを行う

VyattaでWAN Proofを行います。サービス対象のDNSゾーンのNSをWAN Proof Vyattaに向け、DNSレコードをWAN側の状況に応じて更新することで、常にActiveなネットワークのIPアドレスが引けるようになります。通常時は両側のIPアドレスをラウンドロビンで返しますが、どちらかのWANがfailするとそれを検知して生きている側のIPアドレスだけを返すようになります。ゾーンのNSには両側のWANのIPアドレスを指定しておく必要があります。実際のコンテンツを持っているサーバはVyatta下にDNATされていて、どちらのWANからのリクエストかは意識する必要がありません。

Vyatta-WAN-Proofこの機能の実現にはVyatta標準のWAN Load Balancing機能と、そのフックスクリプト機能、それからUnboundのunbound-controlでDDNSを利用します。DDNSはBINDのnsupdateでも大丈夫でしょう。

まずは外に出ていけるようにしてリポジトリの追加

set interfaces ethernet eth0 address '192.168.20.252/24'
set interfaces ethernet eth0 address '192.168.20.20/24'
set interfaces ethernet eth1 address '192.168.30.252/24'
set interfaces ethernet eth1 address '192.168.30.20/24'
set interfaces ethernet eth2 address '10.168.40.1/24'
set protocols static route 0.0.0.0/0 next-hop '192.168.20.2'
set protocols static route 0.0.0.0/0 next-hop '192.168.30.2'
set protocols static route 192.168.10.251/32 next-hop '192.168.20.2'
set protocols static route 192.168.10.253/32 next-hop '192.168.30.2'
set nat source rule 4000 outbound-interface 'any'
set nat source rule 4000 source address '10.168.40.0/24'
set nat source rule 4000 translation address 'masquerade'
set system name-server '192.168.11.254'
set system package repository squeeze components 'main contrib non-free'
set system package repository squeeze distribution 'squeeze'
set system package repository squeeze url 'http://ftp.jaist.ac.jp/pub/Linux/debian'
set system package repository squeeze-backports components 'main contrib non-free'
set system package repository squeeze-backports distribution 'squeeze-backports'
set system package repository squeeze-backports url 'http://ftp.jaist.ac.jp/pub/Linux/debian-backports'
commit

operation modeでUnboundとPythonのYAMLライブラリをインストールしてUnboundの設定

sudo aptitude update
sudo aptitude safe-upgrade
sudo aptitude hold lighttpd live-initramfs
sudo aptitude install unbound=1.4.17-2~bpo60+1 python-yaml
sudo unbound-control-setup
sudo vi /etc/unbound/unbound.conf
# server: セクションに以下を設定
#  interface: 0.0.0.0
#  interface-automatic: yes
#  rrset-roundrobin:yes
#  access-control: 0.0.0.0/0 allow
# remote-control: セクションに以下を設定
#  control-enable: yes

WAN Load Balancingの監視に基いてDNSレコードを更新するフックスクリプト

/config/scripts/update-lc.py

#!/usr/bin/env python

import os
import os.path
import glob
import shlex
from subprocess import call
import yaml
from optparse import OptionParser

op = OptionParser()
op.add_option("-d", "--debug", dest="debug", help="debug mode", action="store_true", default=False)
op.add_option("-i", "--interface", dest="if_name", help="interface", metavar="INTERFACE")
op.add_option("-s", "--state", dest="state", help="state", metavar="STATE")
op.add_option("-c", "--conf", dest="conf_file", help="conf file", metavar="CONFFILE", default="/config/scripts/update-lc.yaml")
(ops, args) = op.parse_args()
work_dir = "/tmp/lc"
log_file = "%(work_dir)s/lc.log" % locals()

log = open(log_file,"w")

if ops.debug:
  if_name = ops.if_name
  state = ops.state
else:
  if_name = os.environ["WLB_INTERFACE_NAME"]
  state   = os.environ["WLB_INTERFACE_STATE"]

log.write(if_name+"n")
log.write(state+"n")

lc_conf = yaml.load(open(ops.conf_file).read())

if not os.path.exists(work_dir):
  os.mkdir(work_dir)

for k,v in lc_conf.iteritems():
  domain_dir = "%(work_dir)s/%(k)s" % locals()
  domain_if_dir = "%(domain_dir)s/%(if_name)s" % locals()
  ip_addr = v[if_name]
  entry_file_name = "%(domain_if_dir)s/%(ip_addr)s" % locals()
  changed = False
  if not os.path.exists(domain_dir):
    os.mkdir(domain_dir)
  if not os.path.exists(domain_if_dir):
    os.mkdir(domain_if_dir)
  if state == "ACTIVE" and not os.path.exists(entry_file_name):
    open(entry_file_name,"wb").close()
    changed = True
  if state == "FAILED" and os.path.exists(entry_file_name):
    os.remove(entry_file_name)
    changed = True

  if changed:
    remove_cmd = "/usr/sbin/unbound-control local_data_remove %(k)s" % locals()
    args = shlex.split(remove_cmd)
    call(args)
    nics = os.listdir(domain_dir)
    for nic in nics:
      addrs = os.listdir("%(domain_dir)s/%(nic)s" % locals())
      for addr in addrs:
        add_cmd = "/usr/sbin/unbound-control local_data %(k)s 5 IN A %(addr)s" % locals()
        args = shlex.split(add_cmd)
        call(args)

log.close()

WAN ProofでホストするFQDNと、各WAN側のIPアドレスをYAMLで記述

/config/scripts/update-lc.yaml

lc.kawataso.net:
  eth0: 192.168.20.20
  eth1: 192.168.30.20

ホストするリアルサーバに対して各WAN側からDNATを設定

set nat destination rule 2020 destination address '192.168.20.20'
set nat destination rule 2020 inbound-interface 'eth0'
set nat destination rule 2020 protocol 'all'
set nat destination rule 2020 translation address '10.168.40.20'
set nat destination rule 3020 destination address '192.168.30.20'
set nat destination rule 3020 inbound-interface 'eth1'
set nat destination rule 3020 protocol 'all'
set nat destination rule 3020 translation address '10.168.40.20'
commit

WAN Load Balancingを有効化

set load-balancing wan 'enable-local-traffic'
set load-balancing wan 'flush-connections'
set load-balancing wan hook '/config/scripts/update-lc.py'
set load-balancing wan interface-health eth0 failure-count '2'
set load-balancing wan interface-health eth0 nexthop '192.168.20.2'
set load-balancing wan interface-health eth0 success-count '1'
set load-balancing wan interface-health eth0 test 10 resp-time '5'
set load-balancing wan interface-health eth0 test 10 target '192.168.10.251'
set load-balancing wan interface-health eth0 test 10 ttl-limit '1'
set load-balancing wan interface-health eth0 test 10 type 'ping'
set load-balancing wan interface-health eth1 failure-count '1'
set load-balancing wan interface-health eth1 nexthop '192.168.30.2'
set load-balancing wan interface-health eth1 success-count '1'
set load-balancing wan interface-health eth1 test 10 resp-time '5'
set load-balancing wan interface-health eth1 test 10 target '192.168.10.253'
set load-balancing wan interface-health eth1 test 10 ttl-limit '1'
set load-balancing wan interface-health eth1 test 10 type 'ping'
set load-balancing wan rule 10 inbound-interface 'eth2'
set load-balancing wan rule 10 interface eth0 weight '1'
set load-balancing wan rule 10 interface eth1 weight '1'
set load-balancing wan rule 10 'per-packet-balancing'
set load-balancing wan rule 10 protocol 'all'
commit

新しいFQDNを追加する場合はリアルサーバと、公開用グローバルアドレスを決めたら/config/scripts/update-lc.yamlをこんな感じに追記して

lc.kawataso.net:
  eth0: 192.168.20.20
  eth1: 192.168.30.20
lc2.kawataso.net:
  eth0: 192.168.20.30
  eth1: 192.168.30.30

NATを追加して

set nat destination rule 2030 destination address '192.168.20.30'
set nat destination rule 2030 inbound-interface 'eth0'
set nat destination rule 2030 protocol 'all'
set nat destination rule 2030 translation address '10.168.40.30'
set nat destination rule 3030 destination address '192.168.30.30'
set nat destination rule 3030 inbound-interface 'eth1'
set nat destination rule 3030 protocol 'all'
set nat destination rule 3030 translation address '10.168.40.30'
commit

Operation Modeで

restart wan-load-balance

を実行するとWAN Proof対象に新しいFQDNが追加されます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください