cd /usr/local
1、下载安装包并解压
sudo wget http://www.keepalived.org/software/keepalived-1.2.13.tar.gz
tar zxvf keepalived-1.2.13.tar.gz
2、编译安装
cd keepalived-1.2.13
./configure --prefix=/usr/local/keepalived
[如果出现configure: error:
!!! OpenSSL is not properly installed on your system. !!!
则需要先安装openssl和openssl-devel, yum install openssl openssl-devel]
make
sudo make install
sudo cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
sudo cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
sudo cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
mkdir /etc/keepalived
cd /etc/keepalived
sudo cp /usr/local/keepalived/etc/keepalived/keepalived.conf ./
3、将keepalived添加到开机启动服务中,并进行测试
chkconfig keepalived on
chkconfig --list | grep keepalived
sudo service keepalived restart
修改keepalived.conf文件(smtp_server 改成localhost, router_id变成NodeMaster, virtual_ipaddress 改成你自己网段内且没有被使用的如10.1.xx.xx/24格式的.
运行ip addr查看vip
运行ping命令访问vip。
4、在从服务器上进行步骤1-3
注意:router_id变成NodeBackup,priority变成99, state变成BACKUP,主从服务器要在同一个网段内。
1.安装LVS前系统需要安装popt-static,kernel-devel,make,gcc,openssl-devel,lftp,libnl*,popt*
#yum –y install popt-static,kernel-devel,make,gcc,openssl-devel,lftp,libnl*,popt*
#ln -s /usr/src/kernels/2.6.32-431.17.1.el6.x86_64/ /usr/src/linux
#tar -zxvf ipvsadm-1.26.tar.gz
#cd ipvsadm-1.26
#make && make install
2.安装keepalived
#wget http://www.keepalived.org/software/keepalived-1.2.13.tar.gz
#tar –zxvf keepalived-1.2.13.tar.gz
#cd keepalived-1.2.13
#./configure
#make && make install
######### 将keepalived做成启动服务,方便管理##########
# cp /usr/local/etc/rc.d/init.d/keepalived /etc/init.d/
# cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
# mkdir /etc/keepalived/
# cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/
# cp /usr/local/sbin/keepalived /usr/sbin/
# service keepalived start | stop
3.开启路由转发
1 #vi /etc/sysctl.conf
2 #sysctl –p
4.配置keepalived
1 #vi /etc/keepalived/keepalived.conf
keepalive.conf具体如下:
! Configuration File for keepalived
global_defs {
notification_email {
382566697@qq.com
}
smtp_connect_timeout 30
router_id LVS_MASTER #备份服务器上将MASTER改为BACKUP
}
vrrp_sync_group KEEPALIVED_LVS {
group {
KEEPALIVED_LVS_MASTER
}
}
vrrp_instance KEEPALIVED_LVS_MASTER {
state MASTER #备份服务器上将MASTER改为BACKUP
interface eth0 #该网卡名字需要查看具体服务器的网口
lvs_sync_daemon_interface eth2
virtual_router_id 51
priority 100 # 备份服务上将100改为90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.0.209
#(如果有多个VIP,继续换行填写.)
}
}
virtual_server 192.168.0.209 80 {
delay_loop 6 #(每隔6秒查询realserver状态)
lb_algo rr #(rr 算法)
lb_kind DR #(Direct Route)
nat_mask 255.255.255.0
persistence_timeout 0 #会话保存时长(秒),0表示不使用stickyness会话
protocol TCP #(用TCP协议检查realserver状态)
real_server 192.168.0.212 80 {
weight 1 #(权重)
TCP_CHECK {
connect_timeout 10 #(10秒无响应超时)
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.0.227 80 {
weight 1
TCP_CHECK {
connect_timeout 10 #连接超时时间
nb_get_retry 3 #重试次数
delay_before_retry 3 #每次重试前等待延迟时间
connect_port 80
}
}
}
需要注意的是{前面需要有空格,我在配置时TCP_CHECK没有空格导致无法找到real_server eth2为机器网卡名称
RS真实服务器的脚本
#!/bin/bash
SNS_VIP=172.16.62.100
/etc/rc.d/init.d/functions
case "$1" in
start)
ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP #netmask 255.255.255.255注意
/sbin/route add -host $SNS_VIP dev lo:0
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
sysctl -p > /dev/null 2>&1
echo "RealServer started!"
;;
stop)
ifconfig lo:0 down
/sbin/route del $LVS_VIP > /dev/null 2>&1
echo "0" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" > /proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer stopped!"
;;
*)
echo "Usage: $0 {start | stop}"
exit 1
esac
exit 0
3,发送邮件的perl脚本sendmail.pl内容如下:
vrrp_sync_group KEEPALIVED_LVS {
group {
KEEPALIVED_LVS_JIM2
}
notify_master /etc/keepalived/sendmail.pl
}
注意主备发送邮件的标题是不一致的,只要你能识别漂移IP在哪台服务器上即可。
#!/usr/bin/perl -w
use Net::SMTP_auth;
use strict;
my $mailhost = 'smtp.163.com';
my $mailfrom = 'test@163.com';
my @mailto = ('123456@139.com');
my $subject = 'keepalived up on backup';
my $text = "正文\n第二行位于此。";
my $user = 'test@163.com';
my $passwd = 'xxxxxxx';
&SendMail();
##############################
# Send notice mail
##############################
sub SendMail() {
my $smtp = Net::SMTP_auth->new( $mailhost, Timeout => 120, Debug => 1 )
or die "Error.\n";
$smtp->auth( 'LOGIN', $user, $passwd );
foreach my $mailto (@mailto) {
$smtp->mail($mailfrom);
$smtp->to($mailto);
$smtp->data();
$smtp->datasend("To: $mailto\n");
$smtp->datasend("From:$mailfrom\n");
$smtp->datasend("Subject: $subject\n");
$smtp->datasend("\n");
$smtp->datasend("$text\n\n");
$smtp->dataend();
}
$smtp->quit;
}
说明:
a、由于keeplived自带的发送邮件机制是个鸡肋,如果本地不启动25端口就无法实现邮件发送,就琢磨着能不能通过自定义脚本来实现,真的是很幸运,就采用了认证的方式。
b、其他的配置说明就不详细讲了,网上很多资料。
4,测试keepalived
主备调度器都开启80端口,两台服务器上的测试内容不一致,这样更方便测试。
##########################
#所需安装模块
#use Net::SMTP
#Authen::SASL
##########################
#$stmp->auth('user','pass');
#大部分SMTP服务器为了防止 spam /垃圾邮件,就需要用户验证身份。
#此方法需要另外安装模块:Authen::SASL, 此模块可能系统不自带
##########################
#Debug => 1
#此段代码用于测试之用,所以开启了Debug,一般测试一次完毕,正式使用的话会关闭它。
注:可在命令行界面直接执行:/etc/keepalived/sendmail.pl,看看能否发送邮件成功,如果失败的话则需要安装Net::SMTP_auth模块
安装方法:
yum -y install perl-CPAN
cpan Net::SMTP_auth
|
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.util.Map;
/**
* 上传文件到服务器
*
* @author Administrator
*
*/
public class SocketHttpRequester {
/**
* 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能:
* <FORM METHOD=POST ACTION="http://192.168.1.101:8083/upload/servlet/UploadServlet" enctype="multipart/form-data">
<INPUT TYPE="text" NAME="name">
<INPUT TYPE="text" NAME="id">
<input type="file" name="imagefile"/>
<input type="file" name="zip"/>
</FORM>
* @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.iteye.cn或http://192.168.1.101:8083这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static boolean post(String path, Map<String, String> params, FormFile[] files) throws Exception{
final String BOUNDARY = "---------------------------7da2137580612"; //数据分隔线
final String endline = "--" + BOUNDARY + "--\r\n";//数据结束标志
int fileDataLength = 0;
for(FormFile uploadFile : files){//得到文件类型数据的总长度
StringBuilder fileExplain = new StringBuilder();
fileExplain.append("--");
fileExplain.append(BOUNDARY);
fileExplain.append("\r\n");
fileExplain.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
fileExplain.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
fileExplain.append("\r\n");
fileDataLength += fileExplain.length();
if(uploadFile.getInStream()!=null){
fileDataLength += uploadFile.getFile().length();
}else{
fileDataLength += uploadFile.getData().length;
}
}
StringBuilder textEntity = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {//构造文本类型参数的实体数据
textEntity.append("--");
textEntity.append(BOUNDARY);
textEntity.append("\r\n");
textEntity.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
textEntity.append(entry.getValue());
textEntity.append("\r\n");
}
//计算传输给服务器的实体数据总长度
int dataLength = textEntity.toString().getBytes().length + fileDataLength + endline.getBytes().length;
URL url = new URL(path);
int port = url.getPort()==-1 ? 80 : url.getPort();
Socket socket = new Socket(InetAddress.getByName(url.getHost()), port);
OutputStream outStream = socket.getOutputStream();
//下面完成HTTP请求头的发送
String requestmethod = "POST "+ url.getPath()+" HTTP/1.1\r\n";
outStream.write(requestmethod.getBytes());
String accept = "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n";
outStream.write(accept.getBytes());
String language = "Accept-Language: zh-CN\r\n";
outStream.write(language.getBytes());
String contenttype = "Content-Type: multipart/form-data; boundary="+ BOUNDARY+ "\r\n";
outStream.write(contenttype.getBytes());
String contentlength = "Content-Length: "+ dataLength + "\r\n";
outStream.write(contentlength.getBytes());
String alive = "Connection: Keep-Alive\r\n";
outStream.write(alive.getBytes());
String host = "Host: "+ url.getHost() +":"+ port +"\r\n";
outStream.write(host.getBytes());
//写完HTTP请求头后根据HTTP协议再写一个回车换行
outStream.write("\r\n".getBytes());
//把所有文本类型的实体数据发送出来
outStream.write(textEntity.toString().getBytes());
//把所有文件类型的实体数据发送出来
for(FormFile uploadFile : files){
StringBuilder fileEntity = new StringBuilder();
fileEntity.append("--");
fileEntity.append(BOUNDARY);
fileEntity.append("\r\n");
fileEntity.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
fileEntity.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
outStream.write(fileEntity.toString().getBytes());
if(uploadFile.getInStream()!=null){
byte[] buffer = new byte[1024];
int len = 0;
while((len = uploadFile.getInStream().read(buffer, 0, 1024))!=-1){
outStream.write(buffer, 0, len);
}
uploadFile.getInStream().close();
}else{
outStream.write(uploadFile.getData(), 0, uploadFile.getData().length);
}
outStream.write("\r\n".getBytes());
}
//下面发送数据结束标志,表示数据已经结束
outStream.write(endline.getBytes());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if(reader.readLine().indexOf("200")==-1){//读取web服务器返回的数据,判断请求码是否为200,如果不是200,代表请求失败
return false;
}
outStream.flush();
outStream.close();
reader.close();
socket.close();
return true;
}
/**
* 提交数据到服务器
* @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static boolean post(String path, Map<String, String> params, FormFile file) throws Exception{
return post(path, params, new FormFile[]{file});
}
}
|