[클러스터] 리눅스 미러 서버 구축하기..
Mirror 서버 구축 방안 ver 1.3 (last updated 06/28)
작성자 : 홍석범
0. 필요한 패키지
/usr/sbin/send_arp (piranha-x.x.i386.rpm 에 속함)
–>Gratuitous ARP 를 이용해 IP takeover 시 arp 캐쉬를 최소화하기 위
한 패키지이다.
Gratuitous ARP 는 캐시에 저장되어 있는 arp 를 refresh 한다.
일반적으로 서버의 arp 캐시는 10분, 라우터는 4시간 정도이다.
http.monitor (mon 내에 존재하는 module 임)
–>지속적으로 80번 포트로의 모니터링을 한다.
ping 모듈과 함께 시스템의 다운 여부를 모니터링한다.
rsync (동기화 툴)
–> /etc/inetd.conf 에
rsync stream tcp nowait root /usr/bin/rsync rsyncd –daemon 줄을 추가
한다.
rsyncd 에 대한 설정파일은 /etc/rsyncd.conf 에 위치한다.
1.위치
———————————————————
eth0(public) | eth1(private)
——————————————————–
mr1. 211.47.65.72 | 192.168.1.1 (리얼서버)
——————————————————–
mr2. 211.47.65.73 | 192.168.1.2 (미러서버)
———————————————————
Floating IP Address : 211.47.65.74 (eth0:1)
———————————————————
DNS 서버에서는 서비스하는 도메인에 대해 Floating IP Address 를 정의해
야 한다.
Floating IP 는 초기에 mirror1 에 설정된 후 이후 mirror1 이 다운시
mirror2 에 자동 설정 (IP takeover) 된다.
그리고 192.168.1.1 과 2는 내부 네트워크를 통해 서로 통신하기 위한 설
정이고
cross cable 로 직접 연결되어있어 어떠한 이유로 eth0 이 끊겨도 통신이
가능하다.
따라서 미러링 서비스가 되려면
Floating IP 주소1개 (실제 서비스를 위한IP)
Mirror1 IP 주소1개 (메인 서버에 설정될 IP)
Mirror2 IP 주소1개 (미러 서버에 설정될 IP)
————————— 이하 공인 IP 3개
Mirror1 Private IP 주소1개
Mirror2 Private IP 주소1개
————————– 이하 내부 IP 2개
——————————————
총 5개 IP 주소가 필요하다.
eth0 은 공인 IP 가 할당되어 있고 HUB 에 연결되어 있음.
eth0:1 에 할당된 IP 가 실제 서비스되는 IP 이며 초기에는 mirror1 에
할당되어 있다가 mirror1 이 다운되면 mirror2 로 할당된다.
HUB
| |
_______| |__________
| |
(eth0:1) (eth0:1)
—- eth0—— —– eth0 —–
| | | |
| mirror1 | | mirror2 |
|— eth1 —-| |—–eth1 —–|
| |
|_____________________|
eth1 은 Privare IP 가 할당되어 있고
cross cable 로 직접 연결되어 있음.
## mirror1 서버
/root/init 라는 디렉토리에 설정 파일이 위치.
* init.sh –> mirror1 다운 이후 복구가 완료되어 다시 서비스를 시작하
기 위한 script.
* standby.sh –> init.sh 에서 호출하는 expect script 로 eth1 을 통해
mirror2 에 접속하여 mirror1을 standby 상태로 설정하기 위한 script.
* mirror1 은 주되게 서비스되므로 /etc/inetd.conf 에 기본적으로 rsync
가 설정된다.
그리고 별도의 rsync 실행 스크립트는 없으며, 단지 다운이후 서비스되었
던 mirror2 서버를
통해 변경,수정된 내용만 받아오면 된다.(이는 init.sh 에 포함되어 있
다.)
* /etc/cron.hourly/rsyncd –> killall -9 -ev rsync 로 죽지않고 떠 있
는 rsync 데몬을
죽인다.
그리고 /etc/rc.d/rc.local 에
ifconfig eth0:1 211.47.65.74 를 한줄 추가한다.
(mr2 에는 추가하지 않는다.)
## mirror 2 서버
/root/check 라는 디렉토리에 설정파일이 위치.
* check.cgi –> main cgi로 메인 서버(mr1)를 모니터링한다.
check.cgi는 지속적으로 ping 과 http 감시모듈을 이용하여 모니터링한
다.
* mirror2.cgi –> check.cgi 에서 require 하여 사용되며 각종 환경설정
에 대한
설정파일이다.
* http.monitor –> 80 번 포트 감시 module
* ping.monitor –> ping check module
* rsync.sh –> mirror1 서버에 rsync 로 일정 간격으로 데이터를 동기화
하기 위한
스크립트로 check내 rsync 디렉토리에 위치한다.
* sync.cgi –> rsync.sh 를 제어하는 파일로 무한루프로 돌린다.
* /backup/backup.cgi –> 스크립트 시작시 killall -9 -ev sync.cgi 로
기존의 rsync 의 실행을 중지하고 백업완료후에는 /root/check/sync.cgi
& 로
다시 rsync 를 가동한다.
백업과 동기화가 동시에 작동할 경우 문제가 발생할 수 있다.
그리고 cron 을 이용한 백업이 오작동하여 while() 으로 무한루프가 작동
하도록 변경 하였다.
mirror2 에서는 평소에 rsyncd 를 서비스 할 필요는 없으나 mirror1 이
다운 및 복구후 다시 서비스를 시작하기 전에 받아가야 하므로
이때에만 필요하다.
따라서 mirror1 에 할당되었던 Floating IP 를 takeover 하면서
기존 inetd.conf 를 죽이고 rsyncd 정의되어 있는 inetd2.cond 를 띄운
다.
이는 check.cgi 에 포함되어 있다.
서버의 monitoring 은 직접적인 서비스를 모니터해야 하므로 eth0 을
통해 이루어지며 각 서버간 동기화는 서비스가 되지 않는 eth1 을
통해 이루어진다.
그리고 2차 backup 은 mirror2 서버에 eth0을 통해 백업이 된다.
추가로 mr2 서버의 /etc/rc.d/rc.sysinit 를 열어
# Clear mtab
>/etc/mtab
바로 윗부분에 chattr -i /etc/mtab 를 추가한다.
2. rsync 로 서로 동기화할 디렉토리
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::etc /etc
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home /home
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home2 /home2
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home3 /home3
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::tmp /tmp
/usr/bin/rsync -avz –timeout 999999
192.168.1.1::mysql /usr/local/mysql/var
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::log /var/log
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::www_conf /www/conf
/usr/bin/rsync -avz –timeout 999999
192.168.1.1::www_cgibin /www/cgi-bin
위 디렉토리 이하에 대해서는 sync.cgi 에서 무한루프가 돌아 지속적으로
동기화된다.
3.불변 설정파일
chattr +i filename 으로 설정
chattr +i /etc/HOSTNAME
chattr +i /etc/sysconfig/network
chattr +i /etc/sysconfig/network-scripts/ifcfg-eth0
chattr +i /etc/sysconfig/network-scripts/ifcfg-eth1
chattr +i /etc/sysconfig/network-scripts/ifcfg-lo
chattr +i /etc/rsyncd.conf
chattr +i /etc/crontab
chattr +i /etc/lilo.conf
chattr +i /etc/fstab
chattr +i /etc/inetd.conf
chattr +i /etc/inetd2.conf
chattr +i /etc/crontab
chattr +i /etc/hosts
chattr +i /etc/rc.d/rc.local
chattr +i /etc/mtab
chattr +i /etc/rc.d/rc.sysinit
(두 서버 모두 공통 설정)
–> mr1과 mr2 가 서로 다름
mr1에만 있는것 : chattr +i /etc/cron.hourly/rsyncd
mr2에만 있는것 : chattr +i /etc/cron.backup/backup
위 설정은 mirror1, mirror2 각각이 고유해야 하는 설정이므로
chattr +i filename 으로 동기화 과정에서 overwrite 가 되는 것을 방지한
다.
해제를 하려면 chattr -i filename 을 하면 된다.
수정후에는 반드시 chattr +i 로 닫도록 한다.
4. 작동방식
먼저 mirror1 서버에서 작동을 시작하여 서비스가 되면 mirror2 에서
check.cgi 와
sync.cgi 를 백그라운드로 시작한다.
[root@mirror2 check]# pwd
/root/check
[root@mirror2 check]# ./check.cgi & <– 백그라운드로 실행.
[root@mirror2 check]# ./sync.cgi & <– 백그라운드로 실행.
[root@mirror2 check]# ./backup.cgi & <– 백그라운드로 실행.
ps aux 로 확인해 보면 아래와 같이 check.cgi 와 monitor 프로그램이
돌고 있는 것을 확인할 수 있다.
root 11933 0.1 0.4 2292 1180 pts/0 S 14:30 0:00 perl ./sync.cgi
root 11934 0.1 0.4 2292 1180 pts/0 S 14:30 0:00 perl ./check.cgi
root 11934 0.1 0.4 2292 1180 pts/0 S 14:30 0:00 perl ./backup.cgi
root 11954 0.0 0.2 1700 760 pts/0 S 14:30 0:00 sh -c ./ping.monitor
211.47.65.xx
standby 서버인 mirror2 에서는 check.cgi 가 돌며
리얼서버인 mirror1 에 지속적으로 ping 접속이 이루어진다.
만약 리얼서버에서의 장애로 서비스가 중단되면 mirror2 서버에서는
일단 ping 으로 확인한 후 ping 이 되지 않으면 80번 포트로 재접속후
최대 30초안에 check.cgi 의 &down 서브루틴에서 정의한대로
아래와 같이 작동한다.
(1) mirror2 가 서비스되므로 mirror1 로부터 rsync를 이용하여 업데이트
를
하면 안된다. 따라서 /root/check/rsync/rsync.sh 를 400 으로 실행권한
을 조정하여
이의 실행을 막는다.
(2) 기존의 inetd를 죽이고 새로운 rsyncd 가 제공되는 inetd를 띄워
기존 mirror1 이 복구될 때까지 rsyncd 서비스 제공을 시작한다.
/etc/inetd.conf 는 telnet / pop 만 제공되는 원래의 inetd 이고
/etc/inetd2.conf 는 rsyncd 가 제공되는 inetd 이다.
(3) /sbin/ifconfig eth0:1 211.47.65.74 을 설정후
/usr/sbin/send_arp -i eth0 211.47.65.74 0001028E4732 211.47.65.255
ffffffffffff
로 기존 mirror1 에서 서비스중인 Floating IP 를 takeover 한다.
send_arp 는 arp cache 를 update 하는 것으로 mirroring 서비스의 핵심설
정이다.
(4)/www/bin/apachectl restart 로 웹데몬을 재설정한후
(5)”/usr/local/mysql/bin/mysqladmin -uroot -pxxxxx reload” 로 DB 를
재시작하고
(6) 미러링 서버가 작동을 시작했음을 관리자에게 메일로 통보한다.
(7) killall -9 -ev sync.cgi 로 현재의 sync.cgi 를 종료한다.
(8) killall -9 -ev check.cgi 로 현재의 check.cgi 를 종료한다.
### mirror1 의 복구가 시작되고 이후
mirror1 서버의 문제가 해결되어 복구가 되면
/root/init 에 있는 init.sh 를 실행한다.
mirror2 에서 mirro1 로의 복구 순서(init.sh의 실행순서)는
(1) mirror1 서버가 다운된 동안 mirror2 에서 변경,수정된 내용이 있으므
로
이의 데이터를 mirror2 서버로부터 mirror1 로 rsync를 통해
동기화(복구)한 후
(2) mirror2 에서 mirror1 로 원래의 서비스 IP 를 takeover 로 다시 가지
고 온다.
(3) mirror2 에서 임시로 서비스를 하는 동안을 제외하고는 mirror1 에는
항상
rsyncd 가 떠 있어야 한다. 따라서 mirror1의 /etc/inetd.conf 에는
rsyncd 가 정의되어 있어야 한다.
mirror1 의 inetd.conf 와 mirror2 의 inetd2.conf 에는 rsyncd 가 정의되
어 있지만
mirror1 의 inetd2.conf 와 mirror2의 inetd.conf 에는 rsyncd 가 정의되
어 있지 않다.
(4) standby.sh 라는 expect 스크립트를 이용하여 mirror2 서버에 접속하
여
mirror2의 check.cgi 를 실행하여 애초의 목적대로 mirror1 를 감시하게
한다.
mirror2 에서 rsyncd 가 서비스되던 inetd 를 kill 한후
rsyncd 가 없는 inetd 를 띄운다.
Floating IP인 eth0:1 은 이제 mirror1에서 쓰이므로 mirror2 에서의
eth0:1 은 down 한다.
그리고 chmod 700 /root/check/rsync/rsync.sh 로 rsync.sh 를 실행할수
있는 권한을
부여하고 접속을 끊는다.
## 아래는 mirror1 에 필요한 관련 설정파일이다.
#!/bin/sh
#########################################################
# mirror1 이 복구후 mirror2 가 standby 로 작동하기 위해 #
# 실행하는 스크립트입니다. #
#########################################################
# 백업서버에서 데이터를 동기화
/usr/bin/rsync -avz 192.168.1.2::etc /etc
/usr/bin/rsync -avz 192.168.1.2::home /home
/usr/bin/rsync -avz 192.168.1.2::home2 /home2
/usr/bin/rsync -avz 192.168.1.2::home3 /home3
/usr/bin/rsync -avz 192.168.1.2::home4 /home4
/usr/bin/rsync -avz 192.168.1.2::home5 /home5
/usr/bin/rsync -avz 192.168.1.2::home6 /home6
/usr/bin/rsync -avz 192.168.1.2::tmp /tmp
/usr/bin/rsync -avz 192.168.1.2::mysql /usr/local/mysql/var
/usr/bin/rsync -avz 192.168.1.2::spool /var/spool/mail
/usr/bin/rsync -avz 192.168.1.2::log /var/log
/usr/bin/rsync -avz 192.168.1.2::www_conf /www/conf
/usr/bin/rsync -avz 192.168.1.2::www_cgibin /www/cgi-bin
# 백업서버에서 IP 를 take_over 함.
/etc/rc.d/init.d/network restart
/sbin/ifconfig eth0:1 211.47.65.74
/usr/sbin/send_arp -i eth0 211.47.65.74 0001028E471A 211.47.65.255
ffffffffffff
# mysql DB 를 Reload 한다.
/usr/local/mysql/bin/mysqladmin -u root -p’xxxxxxx’ reload
# expect script 를 이용하여 mirror2 서버를 standby 모드로 전환시킴.
./standby.sh
/usr/sbin/send_arp -i eth0 211.47.65.74 0001028E471A 211.47.65.255
ffffffffffff
>== standby.sh==<
#!/usr/bin/expect
########################################
# mirror2 를 standby mode 로 전환시키기#
########################################
spawn ssh -l root 192.168.1.2
expect “password:”
sleep 1
send “xxxxxxxx\\r”
expect “root]#”
sleep 1
send “cd check\\r”
sleep 1
expect “]#”
send “./check.cgi &\\r”
sleep 1
expect “]#”
sleep 1
send “./sync.cgi &\\r”
sleep 1
expect “]#”
sleep 1
send “killall -9 -ev inetd\\r”
expect “]#”
send “/usr/sbin/inetd \\r”
expect “]#”
send “/sbin/ifconfig eth0:1 down \\r”
expect “]#”
send “chmod 700 /root/check/rsync/rsync.sh\\r”
expect “]#”
send “exit\\r”
interact
##아래는 mirror2 에 필요한 관련 설정이다.##
>== check.cgi==<
#!/usr/bin/perl
require “mirror2.cgi”;
while(1){
$tasks = `./ping.monitor $master_ip 2>&1`;
if($tasks =~ /alive/){
}
else{
$tasks2 = `./http.monitor -p 80 $master_ip 2>&1`;
sleep(3);
if($tasks2 !~ /OK/){
&down;
}
else{
}
}
sub down {
system “chmod 400 $rsync”;
system “killall -9 -ev $inetd”;
system “/usr/sbin/inetd $inetd2”;
system “/sbin/ifconfig eth0:1 $floating_ip”;
system “/usr/sbin/send_arp -i eth0 $floating_ip $standby_mac
$standby_broadcast ffffffffffff”;
system “$web_restart”;
system “$db_restart”;
open(MAIL, “|$MAIL_PROGRAM -t”);
print MAIL “To: $TO_MAIL \\n”;
print MAIL “Subject: $SUBJECT \\n”;
print MAIL “Content-type: text/html\\n\\n”;
print MAIL “<p><font face=\\”Times New Roman\\”>\\n”;
print MAIL “<b>## $master_ip Server is Down!!</b><p>\\n”;
print MAIL “<b>## Mirror Server is Working Now!!</b><br>\\n”;
close(MAIL);
system “killall -9 -ev $sync_script”;
system “killall -9 -ev $cgi_script”;
}
}
>== mirror2.cgi ==<
#!/usr/bin/perl
#####################################################
# #
# Script for Standby Mirroring Server by Hong sukbum#
# antihong at tt.co.kr #
#####################################################
$TO_MAIL = ‘antihong at tt.co.kr’;
# mirror 서버로 이전시 담당자에게 메일이 발송된다.
$SUBJECT = “Mirroring Server is Now working”;
# 메일 발송시 전송될 메일의 제목
$MAIL_PROGRAM = “/usr/sbin/sendmail”;
# sendmail 의 경로
$master_ip = “211.47.65.72”;
#Standby 서버가 감시할 Master Server 의 IP
$rsync = “/root/check/rsync/rsync.sh”;
#rsync.sh 의 절대경로 및 실행파일
$inetd = “inetd”;
# inet daemon 의 파일명
$inetd2 = “/etc/inetd2.conf”;
#rsync가 정의된 inetd2.conf 의 위치.
$floating_ip = “211.47.65.74”;
#서비스되는 Floating IP address
$standby_mac = “0001028E4732”;
#Standby 서버의 Mac address
$standby_broadcast = “211.47.65.255”;
#Standby 서버의 Broadcast IP 주소
$web_restart = “/www/bin/apachectl restart”;
#웹서버의 재실행 스크립트
$db_restart =”/usr/local/mysql/bin/mysqladmin -uroot -p’xxxxxxxxx’
reload”;
# DB서버의 재실행 스크립트
$cgi_script = “check.cgi”;
#실행되는 cgi script 의 파일명
$sync_script = “sync.cgi”;
#실행되는 cgi script 의 파일명
>==rsync.sh ==<
#!/bin/sh
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::etc /etc
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home /home
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home2 /home2
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::home3 /home3
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::tmp /tmp
/usr/bin/rsync -avz –timeout 999999
192.168.1.1::mysql /usr/local/mysql/var
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::log /var/log
/usr/bin/rsync -avz –timeout 999999 192.168.1.1::www_conf /www/conf
/usr/bin/rsync -avz –timeout 999999
192.168.1.1::www_cgibin /www/cgi-bin
>== ping.monitor ==<
#!/usr/bin/perl
#ping check module…
use strict;
use Net::Ping;
my $host = $ARGV[0];
my $p = Net::Ping->new(“icmp”);
if ($p->ping($host)) {
print “$host is alive.\\n”;
} else {
print “$host is not reachable.\\n”;
}
>==http.monitor==< 는 아래 링크 참조..
http://system.tt.co.kr/wwwboard/data/1/http.monitor.txt
>==/etc/rsycnd.conf==< 는 아래 링크 참조
http://system.tt.co.kr/wwwboard/data/1//rsyncd.conf.txt
[etc]
path = /etc
comment = etc
uid = root
gid = root
use chroot = yes
read only = yes
hosts allow = 192.168.1.2
[home]
path = /home
comment = home
uid = root
gid = root
use chroot = yes
read only = yes
hosts allow = 192.168.1.2
[home2]
path = /home2
comment = home2
uid = root
gid = root
use chroot = yes
read only = yes
hosts allow = 192.168.1.2
### 이하 생략 ####
## 결론 .
주의점 :
(1) 각각의 설정은 root 권한으로 700 설정하여 임의로 read 할 수 없도
록 한다.
(2) 각 서버에 이더넷 카드는 2개씩 장착하며 모두 kernel 에 포함시켜 커
널 컴파일을 한다.
(3) chattr +i 로 동기화시 다른 파일을 overwrite 할 수 없도록 한다.
특히 /etc/fstab 파일이 가장 중요하다.
(4) /etc/ssh2/sshd2_config 의 설정중
AllowHosts 에 192.168.1.* 를 추가한다.
(5) 초기에 서버 셋팅중
# init 1
# cat /dev/sda > /dev/sdb 로 각 서버를 똑같이 설정한다.
이는 run level 1(single mode) 로 들어간후 hdd를 복사하는 과정이다.
(6) 다운타임 : 테스트결과 다운후 mirroring 이 작동시까지는 대략 30초
정도 소요된다.
(7) backup 은 mirror2 에서만 진행된다.
따라서 mirror1 에서 /etc/cron.backup 에 대해서는 cron이 작동하지 않으
며 2차 백업서버에는
mr.tt.co.kr 이 아닌 mr2.tt.co.kr 로 백업을 받는다.
(8) rsync 의 경우 파일의 사이즈가 큰 것은 관계없으나 파일의 양이 많
을 경우
파일을 읽어올때 시간이 많이 소요되고 있다. 따라서 길게는 10분 정도까
지 차이가 있으며
이를 극복하는 것이 가장 큰 문제중 하나이다.
덧말: 초기에 미러링을 고민시에는 LVSP(Linux Virtual Server Project)
와 redhat 의 Piranha 를 보았지만 위 설정 모두 미러링이 아니라 Load
Balancing 이어서 방향을 잡기가 매우 혼란스러웠습니다. 그래서 개념 설
정부터 스크립팅까지 모두 제 생각대로 작성하였습니다.
(send_arp 는 piranha 에서 채용하고 http module 은 mon 이라는 패키지에
서 참고하였습니다.)