Давно был интересен вопрос резервирования DHCP-сервера. Почитав интернет, внезапно оказалось, что не одному мне пришла в голову такая мысль. Все-таки если DHCP упадет, то много пользователей могут быть недовольны 🙂
Итак, внезапно:
Допустим, DHCP у нас уже установлен, причем на двух серверах 192.168.8.10 и 192.168.8.11. Все это крутится на свежей FreeBSD 9.0 RELEASE.
Конфиги в примерах не полные, так что попытаемся изобразить всю картину.
Configuring /usr/local/etc/dhcpd.conf on the Primary
# DHCP Server - Configuration file for Primary # Global configuration # option domain-name "me.local"; option domain-name-servers 192.168.8.9, 192.168.8.8, 192.168.8.10, 192.168.8.11; option ntp-servers 192.168.8.10, 192.168.8.11; option log-servers 192.168.8.10; # 1 day default-lease-time 86400; # 1 week max-lease-time 604800; authoritative; log-facility local7; set vendorclass = option vendor-class-identifier; # DHCP Failover, Primary include "/usr/local/etc/dhcpd/dhcpd.conf_primary"; # Subnet declaration include "/usr/local/etc/dhcpd/dhcpd.subnet"; # Static IP addresses include "/usr/local/etc/dhcpd/dhcpd.static"; # EOF
/usr/local/etc/dhcpd/dhcpd.conf_primary (разные для первичного и вторичного):
########################## # DHCP Failover, Primary # ########################## failover peer "ls" { # Failover configuration primary; # I am the primary address 192.168.8.10; # My IP address port 647; peer address 192.168.8.11; # Peer's IP address peer port 647; max-response-delay 60; max-unacked-updates 10; mclt 3600; split 128; # Leave this at 128, only defined on Primary load balance max seconds 3; }
/usr/local/etc/dhcpd/dhcpd.subnet (одинаковые на обоих серверах, за исключением названия, далее пример, объявляем здесь все подсети, которые нам нужны):
subnet 192.168.6.0 netmask 255.255.255.0 { interface em0; pool { failover peer "ls"; range 192.168.6.201 192.168.6.220; } option routers 192.168.6.254; }
/usr/local/etc/dhcpd/dhcpd.static
Эти файлы одинаковые на двух серверах, их мы будем синхронизировать.
host phone07 { hardware ethernet 00:0b:82:14:36:10; fixed-address phone07; } host testcomp { hardware ethernet 1c:bd:b9:d8:1c:22; fixed-address testcomp; }
Как видно, при запросе с указанного мака сервер резолвит айпишку по имени, и выдает полученный адрес. На обоих серверах поднят BIND, который забирает зону с первичного сервера. В resolv.conf прописываем
domain me.local search me.local me.site.ua nameserver 127.0.0.1 nameserver 192.168.8.9 nameserver 192.168.8.8 nameserver 192.168.8.11
Таким образом, ищем в имена в указанных доменах, а если что-то случилось с локальным биндом, спрашиваем у друзей.
Теперь перейдем ко второму серверу:
Configuring /usr/local/etc/dhcpd.conf on the Secondary
# DHCP Server - Configuration file for Secondary # Global configuration # option domain-name "me.local"; option domain-name-servers 192.168.8.9, 192.168.8.8, 192.168.8.10, 192.168.8.11; option ntp-servers 192.168.8.10, 192.168.8.11; option log-servers 192.168.8.10; # 1 day default-lease-time 86400; # 1 week max-lease-time 604800; authoritative; log-facility local7; set vendorclass = option vendor-class-identifier; # DHCP Failover, Primary include "/usr/local/etc/dhcpd/dhcpd.conf_secondary"; # Subnet declaration include "/usr/local/etc/dhcpd/dhcpd.subnet.DONOTEDIT"; # Static IP addresses include "/usr/local/etc/dhcpd/dhcpd.static.DONOTEDIT"; # EOF
/usr/local/etc/dhcpd/dhcpd.conf_secondary:
########################## # DHCP Failover, Secondary # ########################## failover peer "ls" { # Failover configuration secondary; # I am the secondary address 192.168.8.11; # My IP address port 647; peer address 192.168.8.10; # Peer's IP address peer port 647; max-response-delay 60; max-unacked-updates 10; mclt 3600; load balance max seconds 3; }
На вторичном сервере я планирую выдавать другой диапазон для динамики, а основная часть хостов будет получать адреса статикой по макам.Поэтому следующей задачей является синхронизация файлов /usr/local/etc/dhcpd/dhcp.static между серверами.
Читаем:
By keeping the sub-configurations in sync across servers (perhaps using rsync), maintenance is reduced to a minimum.
Ну как всегда, “легко сообразить, нетрудно догадаться” 🙂
Поставим задачи:
- При перезапуске демона на Primary сделать бекап конфигов .subnets и .static.
- При перезапуске демона на Primary скопировать .subnets и .static в .subnets.DONOTEDIT и .static.DONOTEDIT на Secondary.
- На всякий случай проводить операцию копирования и сохранения бекапов каждую ночь.
Итак, создаем пользователя на обоих серверах:
ls2# adduser Username: dhcp-updater
Даем этому пользователю доступ на запись файлов на вторичном сервере:
chown dhcp-updater dhcpd.subnet.DONOTEDIT chgrp dhcp-updater dhcpd.subnet.DONOTEDIT chown dhcp-updater dhcpd.static.DONOTEDIT chgrp dhcp-updater dhcpd.static.DONOTEDIT
Дальше нужно сгенерировать ключи RSA, чтобы можно было авторизоваться по протоколу SCP без ввода пароля.
Делаем так на первичном:
su dhcp-updater ssh-keygen -t rsa
Нажать несколько раз Enter, пароль не вводить. В результате имеем 2 файла в каталоге /home/dhcp-updater/.ssh/ : id_rsa и id_rsa.pub. Это приватный и публичный ключи. Теперь нужно скопировать публичный ключ на вторичный сервер, для этого:
ls1# scp id_rsa.pub [email protected]:/home/dhcp-updater/authorized_keys
Вводим пароль пользователя dhcp-updater на вторичном сервере. Теперь мы сможем использовать SCP.
Еще нам понадобится sudo на оба сервера:
cd /usr/ports/security/sudo ; make install clean
Создаем каталоги для бекапов на обоих серверах:
mkdir /var/dhcp-backup chown dhcp-updater /var/dhcp-backup
Создаем скрипт копирования на первичном сервере:
touch /usr/local/bin/dhcp-sync chmod 755 /usr/local/bin/dhcp-sync
В скрипте пишем что-то подобное:
#!/bin/sh # Генрация бекапов date=`date -v-1d '+%Y%m%d-%H%M%s'` month=`date '+%m%Y'` sudo -u dhcp-updater cp -f /usr/local/etc/dhcpd/dhcpd.subnet /var/dhcp-backup/dhcpd.subnet.$date sudo -u dhcp-updater bzip2 -f -k -z /var/dhcp-backup/dhcpd.subnet.$date sudo -u dhcp-updater tar -r -f /var/dhcp-backup/dhcpd.subnet.$month.tar /var/dhcp-backup/dhcpd.subnet.$date.bz2 sudo -u dhcp-updater cp -f /usr/local/etc/dhcpd/dhcpd.static /var/dhcp-backup/dhcpd.static.$date sudo -u dhcp-updater bzip2 -f -k -z /var/dhcp-backup/dhcpd.static.$date sudo -u dhcp-updater tar -r -f /var/dhcp-backup/dhcpd.static.$month.tar /var/dhcp-backup/dhcpd.static.$date.bz2 sudo -u dhcp-updater scp -q /var/dhcp-backup/dhcpd.subnet.$date.bz2 dhcp-updater@ls2:/var/dhcp-backup sudo -u dhcp-updater ssh ls2 tar -r -f /var/dhcp-backup/dhcpd.subnet.$month.tar /var/dhcp-backup/dhcpd.subnet.$date.bz2 sudo -u dhcp-updater scp -q /var/dhcp-backup/dhcpd.static.$date.bz2 dhcp-updater@ls2:/var/dhcp-backup sudo -u dhcp-updater ssh ls2 tar -r -f /var/dhcp-backup/dhcpd.static.$month.tar /var/dhcp-backup/dhcpd.static.$date.bz2 sudo -u dhcp-updater ssh ls2 rm /var/dhcp-backup/dhcpd.subnet.$date.bz2 sudo -u dhcp-updater ssh ls2 rm /var/dhcp-backup/dhcpd.static.$date.bz2 sudo -u dhcp-updater rm /var/dhcp-backup/dhcpd.subnet.$date sudo -u dhcp-updater rm /var/dhcp-backup/dhcpd.static.$date sudo -u dhcp-updater rm /var/dhcp-backup/dhcpd.subnet.$date.bz2 sudo -u dhcp-updater rm /var/dhcp-backup/dhcpd.static.$date.bz2 # Собственно синхронизация и рестарт удаленного DHCP sudo -u dhcp-updater scp -q /usr/local/etc/dhcpd/dhcpd.subnet dhcp-updater@ls2:/usr/local/etc/dhcpd/dhcpd.subnet.DONOTEDIT sudo -u dhcp-updater scp -q /usr/local/etc/dhcpd/dhcpd.static dhcp-updater@ls2:/usr/local/etc/dhcpd/dhcpd.static.DONOTEDIT sudo -u dhcp-updater ssh ls2 sudo /usr/local/etc/rc.d/isc-dhcpd restart
Таким образом кроме синхронизации складываем конфиги в архивы, называния файлов генерируем на основе даты, чтобы можно было в них ориентироваться.
Теперь нам нужно запускать скрипт. Логично будет это делать при перезапуске демона dhcpd на первичном сервере. Для этого открываем файл /usr/local/etc/rc.d/isc-dhcpd, находим функцию dhcpd_checkconfig () и модифицируем ее таким образом, чтобы при удачном прохождении теста проводилось копирование конфигурации:
dhcpd_checkconfig () { local rc_flags_mod setup_flags rc_flags_mod="$rc_flags" # Eliminate '-q' flag if it is present case "$rc_flags" in *-q*) rc_flags_mod=`echo "${rc_flags}" | sed -Ee 's/(^-q | -q | -q$)//'` ;; esac if ! ${command} -t -q ${rc_flags_mod}; then err 1 "`${command} -t ${rc_flags_mod}` Configuration file sanity check failed" else sh /usr/local/bin/dhcp-sync fi }
Теперь осталась одна проблема: чтобы перезапустить DHCP на удаленном сервере, нужен root, поэтому мы делаем sudo. Но чтобы sudo не просил пароль рута, нам нужно добавить запись в /usr/local/etc/sudoers:
dhcp-updater ALL = NOPASSWD: /usr/local/etc/rc.d/isc-dhcpd restart
Таким образом разрешаем выполнять данную команды этому пользователю без ввода пароля.
Последний штрих – добавляем в кронтаб задание:
crontab -e 0 0 * * * root /usr/local/etc/rc.d/isc-dhcpd restart
Если все было сделано правильно, теперь DHCP-сервера будут синхронизироваться и работать в паре. Указываем по два ip helper address и радуемся.