Lvs自动部署及监控shell脚本

先申明,本文现在已经在我公司的测试环境和生产测试环境使用。正式环境请用keepalived+lvs.

安装ipvsadm不多说了,先说说脚本的功能,脚本分为redirect server 端和realserver 端,脚本分别为 lvs_redirector.sh 和realserver.sh脚本。另外加一个监控脚本lvs_monitor.sh(此脚本来源网友,做了一点修改,算是 取之于网络,共享给网络吧)。

脚本功能

执行 lvs_redirector.sh nat|dr|tun|stop,中的一个选项可以启动或关闭相应的lvs模式,并调用lvs_monitor.sh 监控realserver。当realserver故障,或者重新启动时,自动删除,添加相应的realserver.当realserver 全故障时,自动添加redirector server 本地127.0.0.1的web页面的故障提示。当realserver只要有一台恢复时,自动添加相应的realserver,并删除127.0.0.1。

实验环境图

Lvs具体原理可以看我的博客:Lvs通俗易懂的总结(http://qiaomiao.blog.51cto.com/484197/1729587) 。

本文脚本的使用如下图的场景:

未分类

未分类

未分类

具体脚本

lvs_redirector.sh 脚本如下:

#!/bin/bash
# blog:http://qiaomiao.blog.51cto.com
#
# 20151223 v2.8 20160115
# home:http://www.qmlab.cn 
#
# description:this script is use start lvs (nat/dr/tun),and stop lvs.


#define the variable
  NAT_VIP="172.16.8.11"
  DR_VIP="10.0.8.20"
  TUN_VIP="10.0.8.20"
  DIP="10.0.8.11"
  RIP1="10.0.8.21"
  RIP2="10.0.8.22"
  RNET="10.0.8.0/24"
  DPORT=80
  RPORT1=80
  RPORT2=80
  GATEWAY01=172.16.8.254         #做nat模式时,redirector 服务器的外网卡的路由器网关地址。
  GATEWAY02=10.0.8.254           #路由器网关地址,做dr 和 tun 模式时用到。
                                 #两个GATEWAY,请根据具体网络环境做取舍。
  logfile=/tmp/myself_log/lvs.log

#create log dir
mkdir -p /tmp/myself_log            # 在这个目录可以看到启动lvs日志。
#general funiction
lvs_monitor(){
     if [ $1 = stop  ];then
        PS=`ps -ef |grep lvs_monitor.sh |awk '{printf $2" "}'`
        for X in `echo $PS`
             do
                kill -9 $X
             done
     else
        sh  ./lvs_monitor.sh &
     fi
}

# LVS/NAT mode    
# start
function nat_start {
     nat_stop
     VIP=$NAT_VIP
     echo 1 >/proc/sys/net/ipv4/ip_forward
 # start  NAT mode
     ifconfig eth1 $VIP netmask 255.255.255.0 up
     route del -net 0.0.0.0
     route add  -net 0.0.0.0 netmask 0.0.0.0 gw $GATEWAY01
     #ifconfig eth0:0 $VIP broadcast $VIP netmask 255.255.255.0 up
     ipvsadm -C
     ipvsadm -A -t $VIP:$DPORT -s wlc
     ipvsadm -a -t $VIP:$DPORT -r $RIP1:$RPORT1 -m -w 1
     ipvsadm -a -t $VIP:$DPORT -r $RIP2:$RPORT2 -m -w 2
     ipvsadm -ln
     ipvsadm -lnc
 }
# stop
function nat_stop {
     VIP=$NAT_VIP
     echo 0 >/proc/sys/net/ipv4/ip_forward
 # stop  NAT mode
     ifconfig eth1 down
     route del -net 0.0.0.0
     route add  -net 0.0.0.0 netmask 0.0.0.0 gw $GATEWAY02 > /dev/null 2>&1
     ipvsadm -C
 }


# LVS/dricert routing  mode
# start
function dr_start {
     dr_stop
     VIP=$DR_VIP
     echo 1 >/proc/sys/net/ipv4/ip_forward
     ifconfig eth0:0 $VIP broadcast $VIP netmask 255.255.255.255 up
     route add  -host $VIP dev eth0:0
 # start  DR  mode
     ipvsadm -C
     ipvsadm -A -t $VIP:$DPORT -s wlc
     ipvsadm -a -t $VIP:$DPORT -r $RIP1 -g -w 1
     ipvsadm -a -t $VIP:$DPORT -r $RIP2 -g -w 2
     ipvsadm -ln
     ipvsadm -lnc

 }
# stop
function dr_stop {
     VIP=$DR_VIP
     echo 0 >/proc/sys/net/ipv4/ip_forward
     ifconfig eth0:0 $VIP broadcast $VIP netmask 255.255.255.255 down
     route del -host $VIP dev eth0:0 > /dev/null 2>&1
 # stop  DR  mode
     ipvsadm -C

 }



# LVS/tunneling  mode
# start
function tun_start {
     tun_stop
     VIP=$TUN_VIP
 # set interface
     #echo 1 >/proc/sys/net/ipv4/ip_forward
     ifconfig tunl0 $VIP broadcast $VIP netmask 255.255.255.255 up
     route add -host $VIP dev tunl0
 # start  tun  mode
     ipvsadm -C
     ipvsadm -A -t $VIP:$DPORT -s wlc
     ipvsadm -a -t $VIP:$DPORT -r $RIP1 -i -w 1
     ipvsadm -a -t $VIP:$DPORT -r $RIP2 -i -w 2
     ipvsadm -ln
     ipvsadm -lnc

 }
# stop
function tun_stop {
     VIP=$TUN_VIP
 # set interface
     #echo 1 >/proc/sys/net/ipv4/ip_forward
     ifconfig tunl0 $VIP broadcast $VIP netmask 255.255.255.255 down
     ip addr flush tunl0
     route del  -host $VIP dev tunl0 >/dev/null 2>&1
 # stop  tun  mode
     ipvsadm -C
}


service iptables stop
case "$1" in
        nat)
        echo -e  "n  `date +%F" "%H:%M:%S` nat模式启动...." > $logfile
        tun_stop
        dr_stop
        nat_start
        lvs_monitor $1
        ;;
        dr)
        echo -e  "n  `date +%F" "%H:%M:%S` dr模式启动...." > $logfile
        tun_stop
        nat_stop
        dr_start
        lvs_monitor $1
        ;;
        tun)
        echo -e  " n  `date +%F" "%H:%M:%S ` tun模式启动...." > $logfile
        dr_stop
        nat_stop
        tun_start
        lvs_monitor $1
        ;;
        stop)
        echo -e "n `date +%F" "%H:%M:%S` 关闭lvs...." > $logfile
        dr_stop
        nat_stop
        tun_stop
        lvs_monitor $1
        ;;
        *)
        echo $"Usage: $0 {nat|dr|tun|stop}"  
        ;;
 esac

lvs_realserver.sh 脚本如下:

#!/bin/bash
# write by lijing QQ 858080796, 
# blog:http://qiaomiao.blog.51cto.com
# 20151223 v2.8 20160115
# home:http://www.qmlab.cn 
#
# description:this script is use start lvs (nat/dr/tun).

#define the variable
  #NAT_VIP="10.0.8.20"
  DR_VIP="10.0.8.20"
  TUN_VIP="10.0.8.20"
  DIP="10.0.8.11"
  RIP1="10.0.8.21"
  RIP2="10.0.8.22"
  RNET="10.0.8.0/24"
  DPORT=80
  RPORT1=80
  RPORT2=80
  GATEWAY="10.0.8.254"
#


# LVS/NAT mode
# start
function nat_start {
    nat_stop
 # set realserver gateway
    route del -net 0.0.0.0
    route add -net 0.0.0.0 netmask 0.0.0.0 gw $DIP

 }
# stop
function nat_stop {
 # set realserver gateway
    route del -net 0.0.0.0
    route add -net 0.0.0.0 netmask 0.0.0.0 gw $GATEWAY

 }


# LVS/dricert routing  mode
# start
function dr_start {
    dr_stop
    VIP=$DR_VIP
 #  set interface
    ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
    route add -host $VIP dev lo:0
 # set realserver  
    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

 }
# stop
function dr_stop {
    VIP=$DR_VIP
 #  set interface
    ifconfig lo:0 down
    route del -host $VIP dev lo:0 >/dev/null 2>&1
 # set realserver  
    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

 }


# LVS/tunneling  mode
# start
function tun_start {
     tun_stop
     VIP=$TUN_VIP
 # set interface
     ifconfig tunl0 $VIP broadcast $VIP netmask 255.255.255.255 up
     route add -host $VIP dev tunl0
 # set realserver  
    echo 1 > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
    echo 2 > /proc/sys/net/ipv4/conf/tunl0/arp_announce
    echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
    echo 0 > /proc/sys/net/ipv4/conf/tunl0/rp_filter
    echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
 }
# stop
function tun_stop {
     VIP=$TUN_VIP
 # set interface
 ip addr flush tunl0
     ifconfig tunl0 down
     route del -host $VIP dev tunl0  >/dev/null 2>&1
 # set realserver  
    echo 0 > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
    echo 0 > /proc/sys/net/ipv4/conf/tunl0/arp_announce
    echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
    echo 0 > /proc/sys/net/ipv4/conf/tunl0/rp_filter
    echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
 }

service iptables stop
case "$1" in
        nat)
        tun_stop
        dr_stop
        nat_start
        ;;
        dr)
        tun_stop
        nat_stop
        dr_start
        ;;
        tun)
        nat_stop
        dr_stop
        tun_start
        ;;
        stop)
        nat_stop
        dr_stop
        tun_stop
        ;;
        *)
        echo $"Usage: $0 {nat|dr|tun|stop}"  
        ;;
 esac

lvs_monitor.sh 脚本如下:(注意要放在lvs_redirector.sh在同一个目录下)

#!/bin/bash
# write by http://small.blog.51cto.com/259970/1728082
# 感谢 网友 super_color

rs=("10.0.8.21" "10.0.8.22")
vip="10.0.8.20"
port=80
logfile="/tmp/myself_log/lvs_monitor.log"
function check_alldown {
   #有一个rs主机能访问,就说明不是全部掉了
   #检查到一个rs主机存活就退出检查
   #如果全部rs不能访问,说明主机全掉了
   for www in `echo ${rs[*]}`
   do
      curl --connect-timeout 1 http://$www &> /dev/null
      if [ $? -eq 0 ]
      then
          echo 0 
          exit 0
      fi
   done
   echo 100 
}
function lvs_add {
   ipvsadm -a -t $vip:$port -r $1
   echo "add rs host:$1 to lvs"
}
function lvs_rm {
   ipvsadm -d -t $vip:$port -r $1
   echo "remove rs host:$1 to lvs"
}
function lvs_local {
   #如果全部rs主机掉线,并且lvs中没有127.0.0.1就添加它
   #如果可以访问一个rs主机,并且lvs中有127.0.0.1就删除它
   all_down=`check_alldown`
   rip=$(ipvsadm -L -n | gawk '/127.0.0.1/')
   if [ $all_down -eq 100 ]
   then
       if [ "$rip" = "" ]
       then
           echo "`date +%F:%H-%M-%S` all rs host is down!" >> $logfile
           lvs_add "127.0.0.1"
       fi
   else
       if [ $all_down -eq 0 ] && [ ! "$rip" = "" ]
       then
           echo "`date +%F:%H-%M-%S` one rs host is up,remove local rs host!" >> $logfile
           lvs_rm "127.0.0.1"
       fi
   fi
}
function lvs_rs {
   #如果可以访问一个rs主机,并且lvs中没有它就添加它
   #如果不能访问一个rs主机,并且lvs中有它就删除它
   lvs_local
   for www in `echo ${rs[*]}`
   do
      rip=$(ipvsadm -L -n | gawk "/$www/")
      curl --connect-timeout 1 http://$www &> /dev/null
      if [ $? -eq 0 ]
      then
          if [ "$rip" = "" ]
          then
              echo "`date +%F:%H-%M-%S` rs host:$www is up!" >> $logfile
              lvs_add "$www"
          fi
      else
          if [ ! "$rip" = "" ]
          then
              echo "`date +%F:%H-%M-%S` rs host:$www is down!" >> $logfile
              lvs_rm "$www"
          fi
      fi
   done
}
function lvs_monitor {
   while true
   do
#     echo "check lvs rs health!"
     lvs_rs
     sleep 1
   done
}
lvs_monitor

结果验证

在验证结果之前,要保证你的路由器的端口映射是正确,且生效的,上面图中:

当外网客户端192.168.20.200访问时,nat模式路由器192.168.20.14映射到172.16.8.11这个IP,

dr和 tun模式映射到 10.0.8.20这个IP。

验证方法:先测试直接内网访问两台realserver web是不是正常,以及redirector server 的本地127.0.0.1 web 是不是正常,再测试访问192.168.20.14,当其中一台故障时是不是还可以访问,到全故障时,有没有切的本地127.0.0.1(故障提示页)的web,当其中只要有一台恢复时,会不会启动添加启用,并删除127.0.0.1的web.

未分类

未分类

LVS NAT模式负载均衡实验

实验环境:

  • LVS 调度器(BL)作为Web1、Web2 两台Web 服务器池的网关

  • BL 两块网卡,分别连接内外网

  • BL 主机(负载调度器):

外网地址:192.168.102.100/24,同时也作为整个群集的VIP
内网地址:192.168.108.113/24
Web1 主机:192.168.108.111/24
Web2 主机:192.168.108.112/24
NFS 主机:192.168.108.113/24

  • 使用轮询(rr)调度算法

一、开启两台web服务器,访问测试

  • 192.168.108.111

  • 192.168.108.222

未分类

未分类

二、开一台作为BL主机

外网地址是192.168.102.100

内网地址是192.168.108.113

LVS-NAT部署

1、加载ip_vs 模块,安装ipvsadm 工具

[root@www ~]# modprobe ip_vs     

[root@www ~]# yum -y install ipvsadm

2、配置负载调度器SNAT 转发规则

[root@www ~]# ipvsadm -A -t 192.168.102.100:80 -s rr

[root@www ~]# ipvsadm -a -t 192.168.102.100:80 -r 192.168.108.111:80 -m -w 1

[root@www ~]# ipvsadm -a -t 192.168.102.100:80 -r 192.168.108.112:80 -m -w 1

[root@www ~]# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  192.168.102.100:80 rr

  -> 192.168.108.111:80           Masq    1      0          0        

  -> 192.168.108.112:80           Masq    1      0          0     

[root@www ~]# /etc/init.d/ipvsadm save

ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm:      [确定]

[root@www ~]# chkconfig ipvsadm on

3、开启路由转发功能

[root@www ~]# sed -i '/net.ipv4.ip_forward/ s/0/1/' /etc/sysctl.conf

[root@www ~]# sysctl –p

三、客户机访问,测试rr轮换机制

未分类

未分类

四、再开一台虚拟机,作NFS 共享储存部署

1、安装nfs-utils、rpcbind 软件包

[root@www ~]# rpm -q nfs-utils rpcbind

nfs-utils-1.2.3-75.el6.x86_64

rpcbind-0.2.0-13.el6.x86_64

2、设置共享目录

将/opt/www 作为共享目录,要求192.168.108.0/24 网段只读权限访问网页数据(若增加读写速度和安全性,可结合raid5+LVM)

[root@www ~]# mkdir /opt/www

[root@www ~]# vim /etc/exports

/opt/www        192.168.108.0/24(ro,sync,no_root_squash)

3、启动服务并查看共享目录

[root@www ~]# /etc/init.d/rpcbind start

[root@www ~]# /etc/init.d/nfs start

启动 NFS 服务:                                            [确定]

关掉 NFS 配额:                                            [确定]

启动 NFS mountd:                                          [确定]

启动 NFS 守护进程:                                        [确定]

正在启动 RPC idmapd:                                      [确定]

[root@www ~]# showmount -e 192.168.108.114

Export list for 192.168.108.114:

/opt/www 192.168.108.0/24

[root@www ~]# chkconfig rpcbind on

[root@www ~]# chkconfig nfs on

[root@www ~]# echo "<h1>哈哈哈</h1>" > /opt/www/index.html

4、Web1服务器配置

[root@www ~]# yum -y install nfs-utils

[root@www ~]# mount 192.168.108.114:/opt/www/ /var/www/html/

[root@www ~]# df -hT

Filesystem           Type   Size  Used Avail Use% Mounted on

/dev/sda3            ext4    18G  4.5G   12G  28% /

tmpfs                tmpfs  491M     0  491M   0% /dev/shm

/dev/sda1            ext4   283M   35M  233M  14% /boot

192.168.108.114:/opt/www/

                     nfs     18G  4.5G   13G  27% /var/www/html

[root@www ~]# cp -p /etc/fstab /etc/fstab.bak

[root@www ~]# vim /etc/fstab

192.168.108.114:/opt/www/       /var/www/html/  nfs     defaults,_netdev 1 2

[root@www ~]# umount /var/www/html/

[root@www ~]# mount -a

[root@www ~]# df -hT

Filesystem           Type   Size  Used Avail Use% Mounted on

/dev/sda3            ext4    18G  4.5G   12G  28% /

tmpfs                tmpfs  491M     0  491M   0% /dev/shm

/dev/sda1            ext4   283M   35M  233M  14% /boot

192.168.108.114:/opt/www/

                     nfs     18G  4.5G   13G  27% /var/www/html

5、Web2 服务器配置

同web1

五、客户机访问测试

未分类

BL主机查看:

未分类

LVS三种负载均衡方式对比

未分类

LVS的三种负载均衡方式

  • Virtual Server via Network Address Translation NAT(VS/NAT)

VS/NAT用法本来是因为网络IP地址不足而把内部保留IP地址通过映射转换成公网地址的一种上网方式(原地址NAT)。如果把NAT的过程稍微变化,就可以成为负载均衡的一种方式。原理其实就是把从客户端发来的IP包的IP头目的地址在DR上换成其中一台REALSERVER的IP地址并发至此REALSERVER,而REALSERVER则在处理完成后把数据经过DR主机发回给客户端,DR在这个时候再把数据包的原IP地址改为DR接口上的IP地址即可。期间,无论是进来的流量,还是出去的流量,都必须经过DR。VS/NAT的VS/NAT的体系结构如图所示。

未分类

  • Virtual Server via IP Tunneling(VS/TUN)

IP隧道(IP tunneling)模式则类似于VPN的方式,使用网络分层的原理,在从客户端发来的数据包的基础上,封装一个新的IP头标记(不完整的IP头,只有目的IP部)发给REALSERVER,REALSERVER收到后,先把DR发过来的数据包的头给解开,还原其数据包原样,处理后,直接返回给客户端,而不需要再经过DR。需要注意的是,由于REALSERVER需要对DR发过来的数据包进行还原,也就是说必须支持IPTUNNEL协议。所以,在REALSERVER的内核中,必须编译支持IPTUNNEL这个选项。IPTUNNEL也在Net working options里面。

未分类

VS/TUN的工作流程

未分类

  • Virtual Server via Direct Routing(VS/DR)

VS/DR方式是通过改写请求报文中的MAC地址部分来实现的。Director和RealServer必需在物理上有一个网卡通过不间断的局域网相连。 RealServer上绑定的VIP配置在各自Non-ARP的网络设备上(如lo或tunl),Director的VIP地址对外可见,而RealServer的VIP对外是不可见的。RealServer的地址即可以是内部地址,也可以是真实地址。

未分类

VS/DR的工作流程

VS/DR的工作流程如图所示:它的连接调度和管理与VS/NAT和VS/TUN中的一样,它的报文转发方法又有不同,将报文直接路由给目标服务器。在VS/DR中,调度器根据各个服务器的负载情况,动态地选择一台服务器,不修改也不封装IP报文,而是将数据帧的MAC地址改为选出服务器的MAC地址,再将修改后的数据帧在与服务器组的局域网上发送。因为数据帧的MAC地址是选出的服务器,所以服务器肯定可以收到这个数据帧,从中可以获得该IP报文。当服务器发现报文的目标地址VIP是在本地的网络设备上,服务器处理这个报文,然后根据路由表将响应报文直接返回给客户。

未分类

三种负载均衡方式比较

  • Virtual Server via NAT

VS/NAT 的优点是服务器可以运行任何支持TCP/IP的操作系统,它只需要一个IP地址配置在调度器上,服务器组可以用私有的IP地址。缺点是它的伸缩能力有限,当服务器结点数目升到20时,调度器本身有可能成为系统的新瓶颈,因为在VS/NAT中请求和响应报文都需要通过负载调度器。我们在Pentium166 处理器的主机上测得重写报文的平均延时为60us,性能更高的处理器上延时会短一些。假设TCP报文的平均长度为536 Bytes,则调度器的最大吞吐量为8.93 MBytes/s. 我们再假设每台服务器的吞吐量为800KBytes/s,这样一个调度器可以带动10台服务器。(注:这是很早以前测得的数据)

基于 VS/NAT的的集群系统可以适合许多服务器的性能要求。如果负载调度器成为系统新的瓶颈,可以有三种方法解决这个问题:混合方法、VS/TUN和 VS/DR。在DNS混合集群系统中,有若干个VS/NAT负调度器,每个负载调度器带自己的服务器集群,同时这些负载调度器又通过RR-DNS组成简单的域名。

但VS/TUN和VS/DR是提高系统吞吐量的更好方法。

对于那些将IP地址或者端口号在报文数据中传送的网络服务,需要编写相应的应用模块来转换报文数据中的IP地址或者端口号。这会带来实现的工作量,同时应用模块检查报文的开销会降低系统的吞吐率。

  • Virtual Server via IP Tunneling

在VS/TUN 的集群系统中,负载调度器只将请求调度到不同的后端服务器,后端服务器将应答的数据直接返回给用户。这样,负载调度器就可以处理大量的请求,它甚至可以调度百台以上的服务器(同等规模的服务器),而它不会成为系统的瓶颈。即使负载调度器只有100Mbps的全双工网卡,整个系统的最大吞吐量可超过 1Gbps。所以,VS/TUN可以极大地增加负载调度器调度的服务器数量。VS/TUN调度器可以调度上百台服务器,而它本身不会成为系统的瓶颈,可以用来构建高性能的超级服务器。VS/TUN技术对服务器有要求,即所有的服务器必须支持“IP Tunneling”或者“IP Encapsulation”协议。目前,VS/TUN的后端服务器主要运行Linux操作系统,我们没对其他操作系统进行测试。因为“IP Tunneling”正成为各个操作系统的标准协议,所以VS/TUN应该会适用运行其他操作系统的后端服务器。

  • Virtual Server via Direct Routing

跟VS/TUN方法一样,VS/DR调度器只处理客户到服务器端的连接,响应数据可以直接从独立的网络路由返回给客户。这可以极大地提高LVS集群系统的伸缩性。跟VS/TUN相比,这种方法没有IP隧道的开销,但是要求负载调度器与实际服务器都有一块网卡连在同一物理网段上,服务器网络设备(或者设备别名)不作ARP响应,或者能将报文重定向(Redirect)到本地的Socket端口上。

三种LVS负载均衡技术的优缺点归纳以下表:

未分类

注:以上三种方法所能支持最大服务器数目的估计是假设调度器使用100M网卡,调度器的硬件配置与后端服务器的硬件配置相同,而且是对一般Web服务。使 用更高的硬件配置(如千兆网卡和更快的处理器)作为调度器,调度器所能调度的服务器数量会相应增加。当应用不同时,服务器的数目也会相应地改变。所以,以上数据估计主要是为三种方法的伸缩性进行量化比较。

LVM逻辑卷快照备份

一、简介

由MySQL AB公司开发,是最流行的开放源码SQL数据库管理系统,主要特点:

  • 是一种数据库管理系统

  • 是一种关联数据库管理系统

  • 是一种开放源码软件,且有大量可用的共享MySQL软件

  • MySQL数据库服务器具有快速、可靠和易于使用的特点

  • MySQL服务器工作在客户端/服务器模式下,或嵌入式系统中

InnoDB存储引擎将InnoDB表保存在一个表空间内,该表空间可由数个文件创建。这样,表的大小就能超过单独文件的最大容量。表空间可包括原始磁盘分区,从而使得很大的表成为可能。表空间的最大容量为64TB。

二、MySQL备份之LVM逻辑卷快照备份

1、通过LVM逻辑卷实现MySQL备份及还原(几乎热备)

前提:

  • 数据文件要在逻辑卷上;

  • 此逻辑卷所在卷组必须有足够的空间使用快照卷;

  • 数据文件和事务日志要在同一个逻辑卷上;

2、LVM快照备份步骤:

2.1 打开会话,施加读锁,锁定所有表;

mysql> FLUSH TABLES WITH READ LOCK;  #刷新表并对表施加读锁

mysql> FLUSH LOGS;   #滚动日志

2.2 通过另一个终端,保存二进制日志文件及相关位置信息;

[root@lamp ~]# mysql -uroot -p -e 'SHOW MASTER STATUSG' > /path/to/master.info  

     #不登录mysql客户端直接查看位置状态,并保存位置信息到相应目录

[root@lamp ~]# cat /tmp/master.info

*************************** 1. row ***************************

            File: mysql-bin.000005

        Position: 107

    Binlog_Do_DB: 

Binlog_Ignore_DB: 

2.3 创建快照卷

[root@lamp ~]# lvcreate -L SIZE -s -p r -n LV_NAME /path/to/source_lv #创建快照卷

-s: 指定为所创建的是快照卷s=snapshot快照;  -p: 指定权限p=permission许可;

r: 读权限;      -n: 指定快照名称;    LV_NAME: 快照名称;

/path/to/source_lv: 针对哪个逻辑卷目录;   -L: 指定快照卷大小

2.4 释放锁

mysql> UNLOCK TABLES;   #释放锁

2.5 挂载快照卷,并备份;

mount /dev/myvg/mydata-snap  /mnt -o ro  #挂载快照卷至/mnt目录,只读挂载

cp -a ./* /backup/full-backup-2017-06-06/  #挂载后把数据复制到备份目录, -a:表示

复制文件的所有属性及内容,保留源文件的所有属性及权限

2.6 删除快照卷

umount /mnt  #备份完后卸载快照卷挂载的目录

lvremove --force /dev/myvg/mydata-snap  #强制移除快照卷

rm -rf mysql-bin.*    #把备份目录中的日志文件删除掉,节省空间

2.7 增量备份二进制日志

mysqlbinlog --start-datetime='2017-06-06 10:11:02' mysql-bin.000005 mysql-bin.000006 > /backup/incremental-`date +%F-%H-%M-%S`.sql  #备份二进制日志,如果增量备份的二进制日志

含有2个或以上的日志文件,需要通过指定开始时间点来备份。

3、LVM快照备份实例演示

3.1 首先打开mysql客户端

[root@lamp ~]# mysql    #打开mysql客户端

mysql> FLUSH TABLES WITH READ LOCK;  #首先刷新表并施加读锁

Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH LOGS;   #滚动日志

Query OK, 0 rows affected (0.06 sec)

mysql> SHOW MASTER STATUS;  #查看二进制日志位置状态

+------------------+----------+--------------+------------------+

| File   | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+----------+--------------+------------------+

| mysql-bin.000005 |  107 |       |        |

+------------------+----------+--------------+------------------+

1 row in set (0.00 sec)

3.2 不退出或关闭此mysql客户端,重新打开一个服务器终端,执行位置信息的保存;

[root@lamp ~]# mkdir /backup   #新建一个备份目录

[root@lamp ~]# mysql -e 'SHOW MASTER STATUSG;' > /backup/master-`date +%F`.info 

    #不登录mysql客户端,直接通过mysql -e直接编辑数据库,把查看二进制日志位置状态备份

[root@lamp ~]# ls -lh /backup/

total 4.0K

-rw-r--r--. 1 root root 158 Jun 22 15:02 master-2017-06-22.info

3.3 对mysql数据目录执行快照(数据文件必须是存放在逻辑卷上)

[root@lamp ~]# lvcreate -L 50M -s -p r -n mydata-snap /dev/myvg/mydata

  Rounding up size to full physical extent 52.00 MiB

  Logical volume "mydata-snap" created

   #对/dev/myvg/mydata逻辑卷做快照,大小为50M,

   -s:表示snapshot快照; -p:指定权限permission;r:读的权限read; -n:指定快照卷的名称


[root@lamp ~]# lvs      #查看逻辑卷,刚新建的快照逻辑卷

  LV       VG    Attr   LSize  Origin Snap%  Move Log Copy%  Convert

  mydata    myvg  owi-ao   10.00g 

 mydata-snap  myvg  sri-a-  52.00m mydata   0.02 

[root@lamp ~]# mount       #查看挂载相关信息

/dev/sda7 on / type ext4 (rw)

proc on /proc type proc (rw)

sysfs on /sys type sysfs (rw)

devpts on /dev/pts type devpts (rw,gid=5,mode=620)

tmpfs on /dev/shm type tmpfs (rw,rootcontext="system_u:object_r:tmpfs_t:s0")

/dev/sda1 on /boot type ext4 (rw)

/dev/sda3 on /home type ext4 (rw)

/dev/sda5 on /tmp type ext4 (rw)

/dev/sda2 on /usr/local type ext4 (rw)

/dev/mapper/myvg-mydata on /mydata type ext4 (rw)

none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)

sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)

3.4 执行完快照后,即可解锁表;

mysql> UNLOCK TABLES;    #解锁

Query OK, 0 rows affected (0.00 sec)

对快照进行挂载并备份;

[root@lamp ~]# mount /dev/myvg/mydata-snap  /mnt -o ro  #以只读方式挂载刚做的快照卷

[root@lamp ~]# cd /mnt  #进入挂载目录

[root@lamp mnt]# ls

data  lost+found

[root@lamp mnt]# cd data/

[root@lamp data]# ls

hellodb      ib_logfile1  lamp.pid  mysql-bin.000001  mysql-bin.000004  performance_schema  testdb    ibdata1      jiaowu       mydb      mysql-bin.000002  mysql-bin.000005  stu

ib_logfile0  lamp.err     mysql     mysql-bin.000003  mysql-bin.index   test

[root@lamp data]# mkdir /backup/full-backup-`date +%F`  #创建备份目录并以时间格式命名

[root@lamp data]# cp -a ./* /backup/full-backup-2017-06-06/  #-a:复制当前目录的所有内容及其权限属性到备份的目录

[root@lamp data]# cd 

[root@lamp ~]# umount /mnt  #卸载挂载的目录/mnt

[root@lamp ~]# lvremove --force /dev/myvg/mydata-snap  #移除刚才创建的快照卷--force强制性

  Logical volume "mydata-snap" successfully removed

[root@lamp ~]# cd /backup/full-backup-2017-06-06/

[root@lamp full-backup-2017-06-06]# ls

hellodb      ib_logfile1  lamp.pid  mysql-bin.000001  mysql-bin.000004  performance_schema  testdb   ibdata1      jiaowu       mydb      mysql-bin.000002  mysql-bin.000005  stu

ib_logfile0  lamp.err     mysql     mysql-bin.000003  mysql-bin.index   test

[root@lamp full-backup-2017-06-06]# rm -rf mysql-bin.*   #删除相关的二进制日志文件以便节省空间

[root@lamp full-backup-2017-06-06]# ls

hellodb  ib_logfile0  jiaowu    lamp.pid  mysql               stu   testdb

ibdata1  ib_logfile1  lamp.err  mydb      performance_schema  test

root@lamp ~]# cd /mydata/data

[root@lamp data]# ls

hellodb      ib_logfile1  lamp.pid  mysql-bin.000001  mysql-bin.000004  performance_schema  testdb     ibdata1      jiaowu       mydb      mysql-bin.000002  mysql-bin.000005  stu

ib_logfile0  lamp.err     mysql     mysql-bin.000003  mysql-bin.index   test

[root@lamp data]# cat /backup/master-2017-06-06.info 

*************************** 1. row ***************************

            File: mysql-bin.000005  #记录的二进制日志文件

        Position: 107    #二进制日志的位置

    Binlog_Do_DB: 

Binlog_Ignore_DB: 

mysql> FLUSH LOGS;  #滚动日志

Query OK, 0 rows affected (0.01 sec)

mysql> USE jiaowu 

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A

Database changed

mysql> INSERT INTO tutors(Tname) VALUES ('stu0003');  #往表tutors中插入数据,字段Tname 值stu0003

Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tutors(Tname) VALUES ('stu0004');  #往表tutors中插入数据,字段Tname 值stu0004

Query OK, 1 row affected (0.00 sec)

mysql> SHOW MASTER STATUS;  #查看此时二进制日志的位置状态信息 

+------------------+----------+--------------+------------------+

| File   | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+----------+--------------+------------------+

| mysql-bin.000006 |  575 |       |        |

+------------------+----------+--------------+------------------+

1 row in set (0.00 sec)

mysql> q

Bye

[root@lamp data]# mysqlbinlog --start-datetime='2017-06-06 10:11:02' mysql-bin.000005 mysql-bin.000006 > /backup/incremental-`date +%F-%H-%M-%S`.sql  

#导出二进制日志文件bin.000005和bin.000006时间点从2017-06-06 10:11:02开始后的内容

[root@lamp data]# ls /backup/incremental-2017-06-06-17-01-41.sql 

/backup/incremental-2017-06-06-17-01-41.sql

[root@lamp data]# service mysqld stop  #停止mysqld进程

Shutting down MySQL..             [  OK  ]

[root@lamp data]# rm -rf ./*    #模拟mysql数据库数据目录内容丢失(手动删除)

[root@lamp data]# ls     #目录中的内容全部删除,查看显示为空

[root@lamp data]# cp -a /backup/full-backup-2017-06-06/* ./  #复制之前快照卷备份的内容至当前数据目录,-a:复制文件的内容及权限属性。

[root@lamp data]# ll   #确保所有文件的属主为mysql用户

total 28712

drwx------. 2 mysql mysql     4096 Jun  2 15:30 hellodb

-rw-rw----. 1 mysql mysql 18874368 Jun  5 14:00 ibdata1

-rw-rw----. 1 mysql mysql  5242880 Jun  5 14:00 ib_logfile0

-rw-rw----. 1 mysql mysql  5242880 Jun  2 15:28 ib_logfile1

drwx------. 2 mysql mysql     4096 Jun  5 14:00 jiaowu

-rw-rw----. 1 mysql root      1853 Jun  2 15:28 lamp.err

-rw-rw----. 1 mysql mysql        6 Jun  2 15:28 lamp.pid

drwx------. 2 mysql mysql     4096 Jun  2 15:30 mydb

drwx------. 2 mysql root      4096 Jun  2 15:30 mysql

drwx------. 2 mysql mysql     4096 Jun  2 15:28 performance_schema

drwx------. 2 mysql mysql     4096 Jun  2 15:30 stu

drwx------. 2 mysql root      4096 Jun  2 15:28 test

drwx------. 2 mysql mysql     4096 Jun  2 15:30 testdb

[root@lamp data]# service mysqld start  #开启mysqld进程

Starting MySQL              [  OK  ]

[root@lamp data]# mysql -uroot -p  #登录mysql客户端

Enter password: 

Welcome to the MySQL monitor.  Commands end with ; or g.

Your MySQL connection id is 3

Server version: 5.5.28-log Source distribution

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql> USE jiaowu

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A

Database changed

mysql> SELECT * FROM tutors;   #查询tutors表的内容(此时后插入的2行数据没有)

+-----+--------------+--------+------+

| TID | Tname        | Gender | Age  |

+-----+--------------+--------+------+

|   1 | HongQigong   | M      |   93 |

|   2 | HuangYaoshi  | M      |   63 |

|   3 | Miejueshitai | F      |   72 |

|   4 | OuYangfeng   | M      |   76 |

|   5 | YiDeng       | M      |   90 |

|   6 | YuCanghai    | M      |   56 |

|   7 | Jinlunfawang | M      |   67 |

|   8 | HuYidao      | M      |   42 |

|   9 | NingZhongze  | F      |   49 |

+-----+--------------+--------+------+

9 rows in set (0.00 sec)

mysql> SET sql_log_bin=0;  #导入二进制日志前,先关闭日志记录功能0为关闭,1为打开

Query OK, 0 rows affected (0.00 sec)

mysql> SOURCE /backup/incremental-2017-06-06-17-01-41.sql  #导入备份的二进制日志数据

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tutors;    #再次查询tutors表的内容,此时后插入的2行数据已经生成

+-----+--------------+--------+------+

| TID | Tname    | Gender | Age  |

+-----+--------------+--------+------+

|   1 | HongQigong   | M      |   93 |

|   2 | HuangYaoshi  | M      |   63 |

|   3 | Miejueshitai | F      |   72 |

|   4 | OuYangfeng   | M      |   76 |

|   5 | YiDeng       | M      |   90 |

|   6 | YuCanghai    | M      |   56 |

|   7 | Jinlunfawang | M      |   67 |

|   8 | HuYidao      | M      |   42 |

|   9 | NingZhongze  | F      |   49 |

|  10 | stu0003      | M      | NULL |

|  11 | stu0004      | M      | NULL |

+-----+--------------+--------+------+

11 rows in set (0.00 sec)

mysql> SET sql_log_bin=1;   #二进制日志导入后再打开二进制日志记录功能

Query OK, 0 rows affected (0.00 sec)

mysql> SHOW MASTER STATUS;  #查看此时的二进制日志位置状态信息

+------------------+----------+--------------+------------------+

| File   | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+----------+--------------+------------------+

| mysql-bin.000001 |    107 |        |       |

+------------------+----------+--------------+------------------+

1 row in set (0.00 sec)

至此通过lvm逻辑卷和二进制cp功能实现了mysql数据库备份和还原。

Linux如何使用LVM逻辑卷

背景

在学习Linux中,学习到了逻辑卷LVM,发现LVM是个十分好用的一个技术,可以多个硬盘合并在一起使用,同时还可以动态的增加和减少。在这里将Linux逻辑卷的具体实现记录下来。

介绍

逻辑卷LVM:Logica Volum Manager,它是Linux环境下对磁盘分区进行管理的一种机制,普通的磁盘分区管理方式在逻辑分区划分好之后就无法改变其大小,当一个逻辑分区存放不下某个文件时,这个文件因为受上层文件系统的限制,也不能跨越多个分区来存放,所以也不能同时放到别的磁盘上。而LVM解决了这个问题,它可以动态的改变逻辑卷大小,以及跨分区使用。

实现LVM

在实现LVM前,需要准备一些磁盘,当然一个磁盘的多个分区也可以做,不过那没什么意义,这里我准备了4个磁盘来做这个实验,分别是每个磁盘分出10个G的分区来做实验,其中一个使用整个磁盘做分区。在做分区时要,注意要将分区类型改为8e类型,最后要记得输入w保存退出,不然分区不会生效,如果保存退出出现warning,记得同步分区,命令是:partx -a /dev/sdc 。

如图:

未分类

使用同样的方法分了4个分区,结果如图:

未分类

准备好分区后,开始制作LVM,第一步就是将这些分区或者磁盘做成物理卷,命令:pvcreate /dev/sd{b,c1,d1,e1}

未分类

然后使用pvs命令或者pvdisplay来查看物理卷列表。

未分类

然后开始创建卷组,使用命令vgcreate 卷组名(自己取) 物理卷(需要加入到卷组的物理卷),使用vgs可以产看卷组列表

未分类

使用vgdisplay查看卷组详细信息

未分类

创建好卷组后就可以在卷组上创建逻辑卷,命令:/lvcreate -n 逻辑卷名 -L 10G 卷组名

在配置大小时,可以用 -l 或者 -L 选项,-l 表示用PE个数做单位,-L 可以指定大小为多大,还可以用百分比:50%vg 卷组名

未分类

使用lvdisplay查看逻辑卷详细信息

未分类

这样我们的逻辑卷就创建成功了,现在为这个逻辑卷做一个文件系统,如果你做xfs文件系统,这个逻辑卷是不可用减少的,只能增加,如果是ext4就可以增加和减少。命令:mkfs.ext4 /dev/vg0/lv0

未分类

在创建一个挂载点将这个卷挂载就可以使用了,如果需要开机知道挂载,需要写配置文件/etc/fstab。

未分类

如果我们要增加逻辑卷的大小用命令:lvextend -r -L +10G /dev/vg0/lv0

-r 可以为增加的空间同步文件系统,如果没加-r ,增加的空间是没有文件系统的,所以并不能使用,也可以用

resize2fs /dev/vg0/lv0 30G 来同步,后面的30g为增加后整个空间的大小

未分类

如果卷组的空间不够,也可以扩展。命令为:vgextend vg0 /dev/sdf1 ;在sdf1也需要像之前创建分区时那样操作。

未分类

这样就实现了LVM的增加,这时如果我们不需要这么大的空间还可以减少LVM空间。

  • 首先取消挂载:umount /mnt/lv0

  • 再检查文件系统:fsck -f /dev/vg0/lv0 这个步骤是必须的,而且必须加 -f 强制检查,不然后面会报错。

  • 再减少文件系统空间:resize2fs /dev/vg0/lv0 10G 减少到10G大小

  • 再减少逻辑卷空间:lvreduce -L 10G /dev/vg0/lv0 减少到10G大小

  • 最后在挂载:mount -a

未分类

确认逻辑卷大小变为10G

未分类

从逻辑卷中删除正在使用的物理分区

未分类

如果这个物理分区上有数据或者空间被分配出去了,可以使用pvmove /dev/sdc1 将上面的数据或者空间,转移到其他分区,具体转到哪个分区系统自己分配。

先将需要移除的分区从卷组里移除,命令:vgreduce vg0 /dev/sdb

再从物理分区中移除,命令:pvremove /dev/sdb

未分类

安装WebVirtMgr来管理KVM虚拟机

WebVirtMgr 是一个基于 libvirt 开发的用来管理虚拟机的 Web 界面。纯 Python 开发的,前端是基于 Python 的 Django,后端是基于 Libvirt 的 Python 接口。
它允许您创建和配置新的域,并调整域的资源分配。VNC 查看器向 guest 域提供完整的图形控制台。仅支持 KVM 虚拟。

Web 界面需要 Nginx 反代,本文以 CentOS 7 系统在 OneinStack 一键包下安装 LNMP 环境为例。

WebVirtMgr 面板 和 KVM 服务器 可以安装在同一主机,也可以分开安装的。我是把 WebVirtMgr 面板 装在相对国内访问稍快点的美西 VPS 上。

使用 libvirt 配置的 KVM虚拟机 网络可以使用 bridged(桥接模式)和 NAT(网络地址转换模式)。本文以单 IP 使用 NAT 模式为例。

安装 WebVirtMgr

sudo yum -y install epel-release
sudo yum -y update
sudo yum -y install git python-pip libvirt-python libxml2-python python-websockify supervisor
sudo yum -y install gcc python-devel
sudo pip install numpy

安装 Python requirements 并设置 Django 环境

cd /data/wwwroot/
git clone git://github.com/retspen/webvirtmgr.git
cd webvirtmgr
sudo pip install -r requirements.txt
./manage.py syncdb
./manage.py collectstatic

执行过程中按要求输入用户信息:

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes (Put: yes)
Username (Leave blank to use 'admin'): admin (Put: your username or login)
E-mail address: [email protected] (Put: your email)
Password: xxxxxx (Put: your password)
Password (again): xxxxxx (Put: confirm password)
Superuser created successfully.

可添加额外的超级用户

./manage.py createsuperuser

设置 Nginx

vim /usr/local/nginx/conf/nginx.conf  #按自己实际 Nginx 配置文件路径
*** 省略

  server {
    listen 9556;
    server_name $hostname;

    location /static/ {
        root /data/wwwroot/webvirtmgr/webvirtmgr;
        expires max;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
        proxy_send_timeout 600;
        client_max_body_size 1024M;
    }
  }

*** 省略
nginx -t
sudo service nginx restart
chown -R www.www /data/wwwroot/webvirtmgr

设置 Supervisor 管理进程

vim /etc/supervisord.d/webvirtmgr.ini
[program:webvirtmgr]
command=/usr/bin/python /data/wwwroot/webvirtmgr/manage.py run_gunicorn -c /data/wwwroot/webvirtmgr/conf/gunicorn.conf.py
directory=/data/wwwroot/webvirtmgr
autostart=true
autorestart=true
logfile=/var/log/supervisor/webvirtmgr.log
log_stderr=true
user=www

[program:webvirtmgr-console]
command=/usr/bin/python /data/wwwroot/webvirtmgr/console/webvirtmgr-console
directory=/data/wwwroot/webvirtmgr
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/webvirtmgr-console.log
redirect_stderr=true
user=www

若系统、环境跟本文不符请注意修改文中路径和用户权限

systemctl restart supervisord
systemctl enable supervisord

以上已完成 WebVirtMgr 面板的安装,在浏览器 http://ip:9556 打开就能看到登陆面板了,下面安装 KVM 主机服务器。

安装 libvirt 和 KVM

wget -O - http://retspen.github.io/libvirt-bootstrap.sh | sudo sh

建立两个文件夹存放 虚拟机镜像文件 和 安装系统所需的ISO文件(之后要在面板的 “存储池” 里设置)

mkdir -p /home/kvm/img
mkdir -p /home/kvm/iso

安装 TCP 授权

sudo saslpasswd2 -a libvirt dane                  #添加用户和设置密码。
sudo sasldblistusers2 -f /etc/libvirt/passwd.db   #查看用户
virsh -c qemu+tcp://127.0.0.1/system nodeinfo     #验证设置

配置防火墙

允许安装 WebVirtMgr 面板的主机访问 KVM 主机服务器

iptables -A INPUT -s 安装WebVirtMgr面板主机的IP -j ACCEPT
service iptables save
systemctl restart iptables.service

现在就可以登陆 WebVirtMgr 面板添加主机服务器和建立KVM虚拟机了。面板很简单不做记录。

切记:使用 NAT 模式 不需要按网上各种教程建立网桥桥接。

KVM 使用virtio驱动Windows Server 虚拟机

KVM安装Windows默认使用的是qemu虚拟化IDE硬盘模式,在这种情况下,IO性能比较低,如果使用virtio的方式可以提高虚拟机IO性能。而virtio所驱动的网卡,也将原来的百兆扩展到千兆。这里就简单介绍下如何使用virtio驱动安装window server 2008. 其它windows版本操作相同,只需选择对应的驱动即可。

使用virtio安装window虚拟机

KVM安装Windows需要使用virtio的驱动:

https://Fedoraproject.org/wiki/Windows_Virtio_Drivers#Direct_download

安装虚拟机步骤:

1、安装virtio驱动

wget https://fedorapeople.org/groups/virt/virtio-win/virtio-win.repo -O /etc/yum.repos.d/virtio-win.repo

yum install virtio-win -y

2、查看virtio-win提供的驱动

rpm -ql virtio-win | grep iso
/usr/share/virtio-win/virtio-win-0.1.126.iso
/usr/share/virtio-win/virtio-win.iso

3、安装windows

创建一个虚拟机磁盘:

qemu-img  create -f qcow2 win-2c8g150g.img 150G

使用virtio驱动安装虚拟机:

virt-install -n win-2c8g150g --vcpus=2 --ram=8192 --os-type=windows --os-variant=win2k8 
-c /vm/iso/cn_windows_server_2008_r2_sp1_x64.iso 
--disk path=/usr/share/virtio-win/virtio-win-0.1.126_amd64.vfd,device=floppy 
--disk path=/vm/win-2c8g150g.img,format=qcow2,bus=virtio --graphics vnc,listen=0.0.0.0 
--noautoconsole

提示: 这里是使用的是软盘方式加载,如果镜像和驱动都使用cdrom的方式加载,在有些情况系统会找不到启动镜像,导致无法启动. 加载的驱动有x86和amd64两种类型,64位系统选择amd64. 32为系统选择x86.

4、 安装过程中,在选择磁盘界面会找不到磁盘

选择“加载驱动”,“浏览”,找到“软盘驱动器”,点开后选择 “server 2008”确定,驱动加载完成后,磁盘就出现了,继续安装即可。

5、安装完成后,在设备管理器中可以看到使用的是virtio

未分类

在已安装的kvm虚拟机上添加virtio驱动

如果以传统的IDE硬盘模式安装可以使用如下命令:

virt-install  --virt-type kvm --name win-2c8g100g  --ram 8192  
-vcpus=2 -s 100 -c /vm/iso/cn_windows_server_2008_r2_sp1_x64.iso 
--os-type=windows -f /vm/win-2c8g100g.img --graphics vnc,listen=0.0.0.0 --noautoconsole

安装之后要使用virtio驱动,可以选择加载virtio驱动的iso文件到虚拟机光驱:

virsh  attach-disk  win-2c8g100g /usr/share/virtio-win/virtio-win.iso  hdb  --type cdrom

或者使用如下命令:

virsh change-media win-2c8g100g hdb /usr/share/virtio-win/virtio-win.iso

参考链接:https://superuser.com/questions/239870/change-cd-rom-via-virsh

修改虚拟机的xml文件,使其能发现virtio类型的设备,否则驱动无法安装:
增加一块virtio驱动的硬盘:

qemu-img  create -f qcow2 test.img 1G

修改虚拟机的xml文件,在原有的”disk type”区域增加一个test磁盘的配置:

  <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/vm/test.img'/>
      <target dev='vdb' bus='virtio'/>
    </disk>

修改网卡类型为 virtio, 在 interface type 区域,修改model type=’virtio’ :

<interface type='bridge'>
      <mac address='52:54:00:39:f9:60'/>
      <source bridge='br0'/>
      <model type='virtio'/>

提示:如果不是使用vnc远程连接,需要新增一个网卡配置,在没有安装驱动前,使用上面的配置,虚拟机是断网状态。
修改完成之后,重启虚拟机:

virsh shutdown win-2c8g100g
virsh start win-2c8g100g

进入虚拟机,成功添加iso驱动程序后,进入虚拟机的设备管理器界面,在“系统设备”里面对相应的驱动进行更新:
更新驱动需要找到挂载的CD中 virtio-win.iso中的对应文件。驱动镜像中分别有四种驱动,他们对应关系为:

Balloon, the balloon driver, affects the PCI standard RAM Controller in the System devicesgroup.

vioserial, the serial driver, affects the PCI Simple Communication Controller in the System devices group.

NetKVM, the network driver, affects the Network adapters group. This driver is only available if a virtio NIC is configured. Configurable parameters for this driver are documented in Appendix A, NetKVM Driver Parameters.

viostor, the block driver, affects the Disk drives group. This driver is only available if a virtio disk is configured.

参考链接:

https://access.RedHat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Virtualization_Host_Configuration_and_Guest_Installation_Guide/form-Virtualization_Host_Configuration_and_Guest_Installation_Guide-Para_virtualized_drivers-Mounting_the_image_with_virt_manager.html

如果找不到英文说明中对应的设备,使用如下方式:

对未知设备添加virtio驱动即可,如图:

未分类

安装驱动之后:

未分类

对应的磁盘驱动成功安装:

未分类

此时virtio驱动添加完成,修改虚拟机的xml文件,删除test.img的虚拟磁盘配置,修改启动磁盘驱动类型:

    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/vm/win-2c8g100g.img'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </disk>

重启虚拟机即可。

kvm虚拟机挂载lvm卷

kvm虚拟机挂载lvm卷

virsh attach-disk kvm-3 /dev/vg_shkvm3/kvm-3-data vdb --driver qemu --mode shareable

登录到kvm-3

[root@sh-kvm-3-3 ~]# fdisk -l

Disk /dev/vda: 21.5 GB, 21474836480 bytes
16 heads, 63 sectors/track, 41610 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00002155

   Device Boot      Start         End      Blocks   Id  System
/dev/vda1   *           3        1018      512000   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/vda2            1018       41611    20458496   8e  Linux LVM
Partition 2 does not end on cylinder boundary.

Disk /dev/mapper/VolGroup-lv_root: 18.8 GB, 18798870528 bytes
255 heads, 63 sectors/track, 2285 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/mapper/VolGroup-lv_swap: 2147 MB, 2147483648 bytes
255 heads, 63 sectors/track, 261 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/vdb: 53.7 GB, 53687091200 bytes
16 heads, 63 sectors/track, 104025 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
[root@sh-kvm-3-3 ~]# fdisk /dev/vdb #分区 
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x93edb871.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-104025, default 1): 
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-104025, default 104025): 
Using default value 104025

Command (m for help): p

Disk /dev/vdb: 53.7 GB, 53687091200 bytes
16 heads, 63 sectors/track, 104025 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x93edb871

   Device Boot      Start         End      Blocks   Id  System
/dev/vdb1               1      104025    52428568+  83  Linux

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

挂载lvm 到data目录

mkfs.ext4 /dev/vdb1
pvcreate /dev/vdb1
vgextend VolGroup /dev/vdb1
lvcreate -n data -L 30G VolGroup
mkdir /data
mkfs.ext4 /dev/VolGroup/data
mount /dev/VolGroup/data  /data/
echo "/dev/mapper/VolGroup-data    /data                   ext4    defaults        1 1"  >> /etc/fstab

扩容根目录

# lvextend -l +100%FREE /dev/mapper/VolGroup-lv_root
# resize2fs /dev/mapper/VolGroup-lv_root
# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root
                      103G   40G   58G  41% /
tmpfs                 4.9G   12K  4.9G   1% /dev/shm
/dev/xvda1            477M  153M  299M  34% /boot

nginx结合keepalived实现web服务器高可用方案

keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

安装Keepalived(http://www.keepalived.org/download.html)

1、上传或下载 keepalived到 /usr/local/src 目录

2、解压安装

cd /usr/local/src  
tar -zxvf keepalived-1.2.18.tar.gz  
cd keepalived-1.2.18  
./configure --prefix=/usr/local/keepalived  
make && make install  

3、将 keepalived 安装成 Linux 系统服务(因为没有使用 keepalived 的默认路径安装(默认是/usr/local),安装完成之后,需要做一些工作)

#复制默认配置文件到默认路径  
mkdir /etc/keepalived  
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/  
#复制 keepalived 服务脚本到默认的地址  
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/  
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/  
ln -s /usr/local/sbin/keepalived /usr/sbin/  
ln -s /usr/local/keepalived/sbin/keepalived /sbin/  

4、设置 keepalived 服务开机启动

chkconfig keepalived on  

5、修改 Keepalived 配置文件

MASTER 节点配置文件(192.168.1.11)

vi /etc/keepalived/keepalived.conf
global_defs {
  ##keepalived自带的邮件提醒需要开启sendmail服务。建议用独立的监控或第三方SMTP
  ##标识本节点的字条串,通常为 hostname
  router_id 192.168.1.11
}
##keepalived会定时执行脚本并对脚本执行的结果进行分析,动态调整vrrp_instance
   的优先级。如果脚本执行结果为0,并且weight配置的值大于0,则优先级相应的增加。
   如果脚本执行结果非0,并且weight配置的值小于 0,则优先级相应的减少。其他情况,
   维持原本配置的优先级,即配置文件中priority对应的值。
vrrp_script chk_nginx {
   script "/etc/keepalived/nginx_check.sh" ## 检测 nginx 状态的脚本路径
   interval 2 ## 检测时间间隔
   weight -20 ## 如果条件成立,权重-20
}
## 定义虚拟路由,VI_1为虚拟路由的标示符,自己定义名称
vrrp_instance VI_1 {
   state MASTER ## 主节点为MASTER,对应的备份节点为BACKUP
   interface eth1 ## 绑定虚拟IP的网络接口,与本机IP地址所在的网络接口相同
   virtual_router_id 11 ## 虚拟路由的ID号,两个节点设置必须一样,建议用IP最后段
   mcast_src_ip 192.168.1.11 ## 本机 IP 地址
   priority 100 ## 节点优先级,值范围0-254,MASTER要比BACKUP高
   nopreempt ## 优先级高的设置 nopreempt 解决异常恢复后再次抢占的问题
   advert_int 1 ## 组播信息发送间隔,两个节点设置必须一样,默认 1s
   ## 设置验证信息,两个节点必须一致
   authentication {
      auth_type PASS
      auth_pass 1111
   }
   ## 将 track_script 块加入 instance 配置块
      track_script {
      chk_nginx ## 执行 Nginx 监控的服务
   }
   ## 虚拟 IP 池, 两个节点设置必须一样
   virtual_ipaddress {
      192.168.1.10  ## 虚拟 ip,可以定义多个
   }
}

BACKUP 节点配置文件(192.168.1.12)  
vi /etc/keepalived/keepalived.conf

global_defs {
  router_id 192.168.1.12
}
vrrp_script chk_nginx {
   script "/etc/keepalived/nginx_check.sh"
   interval 2 
   weight -20 
}
vrrp_instance VI_1 {
   state BACKUP
   interface eth1 
   virtual_router_id 11 
   mcast_src_ip 192.168.1.12
   priority 90 
   advert_int 1 
   authentication {
      auth_type PASS
      auth_pass 1111
   }
   track_script {
      chk_nginx 
   }
   virtual_ipaddress {
      192.168.1.10  
   }
}

6、编写 Nginx 状态检测脚本 /etc/keepalived/nginx_check.sh

脚本:如果nginx停止运行,尝试启动,如果无法启动则杀死本机的keepalived进程,
keepalied将虚拟ip绑定到 BACKUP 机器上。内容如下:

vi /etc/keepalived/nginx_check.sh
!/bin/bash
A=`ps -C nginx –no-header |wc -l`
if [ $A -eq 0 ];then
    /usr/local/nginx/sbin/nginx
    sleep 2
    if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
        killall keepalived
    fi
fi

7、给脚本赋执行权限

chmod +x /etc/keepalived/nginx_check.sh

8、启动 Keepalived

service keepalived start
Starting keepalived: [ OK ]

9、Keepalived+Nginx的高可用测试

(1)关闭 192.168.1.11 中的 Nginx,Keepalived会将它重新启动

 /usr/local/nginx/sbin/nginx -s stop

(2)关闭 192.168.1.11 中的 Keepalived,VIP 会切换到 192.168.1.12 中

 service keepalived stop

(3)重新启动 192.168.1.11 中的 Keepalived,VIP 又会切回到 192.168.1.11 中来

 service keepalived start

附Keepalived 服务管理命令:

停止:service keepalived stop
启动:service keepalived start
重启:service keepalived restart
查看状态:service keepalived status

解决Kubernetes(k8s) 1.7.3 kube-apiserver频繁异常重启的问题

近期将之前的一个用kube-up.sh安装的Kubernetes 1.3.7的环境更换为最新发布的用kubeadm安装的Kubernetes 1.7.3版本。新版本的安装过程和之前的采用kubeadm安装的k8s 1.5.x、1.6.x版本类似,这里不赘述了。但在安装Dashboard后,发现了一些问题,这里记录一下解决的过程。

一、第一个问题

我们先来做一下回顾。在《解决Kubernetes 1.6.4 Dashboard无法访问的问题》一文中,我们通过把用户admin bind到cluster-admin这个clusterrole角色上使得dashboard得以正常访问。但访问几次后,我发现了一个问题:那就是用safari访问dashboard时,浏览器可以正常弹出鉴权对话框,让我输入用户名和密码;但用chrome访问时,总是无法弹出鉴权对话框,而直接显示如下错误:

User "system:anonymous" cannot get  at the cluster scope.

kube-apiserver身份验证文档中对anonymous requests做了说明:对于没有被其他身份验证方法拒绝的requests,kube-apiserver会为这样的request赋予用户名: system:anonymous和用户group: system:unauthenticated,这个request将继续流向后面的环节:authorization和admission-control,直到被后面的环节拒绝,返回失败应答。这一些都源于k8s 1.6以后的版本中,kube-apiserver的命令行选项:–anonymous-auth的默认值改为了true,即允许anonymous request的存在,因此上面chrome在访问kube-apiserver时,不输入user、password也能继续下面的环节,这就是第一个问题及其原因。

二、关闭匿名请求的身份验证权

解决上面这个问题,最直接的方法就是关闭匿名请求的身份验证权,即不接受匿名请求。我们通过在/etc/kubernetes/manifests/kube-apiserver.yaml中添加下面一行来实现:

spec:
  containers:
  - command:
    - kube-apiserver
    - --anonymous-auth=false

/etc/kubernetes/manifests/kube-apiserver.yaml被修改后,kubelet会重启kube-apiserver。重启后,我再用chrome访问dashboard,身份验证对话框就出现在眼前了。

三、kube-apiserver周期性异常重启

一直以为问题到这里就解决了。但随后又发生了一个更为严重的问题,那就是:kube-apiserver定期重启,并牵连kube-controller-manager和kube-scheduler的status也不正常了。

通过kubectl describe查看状态异常的kube-apiserver pod,发现如下输出:

root@yypdcom2:# kubectl describe pods/kube-apiserver-yypdcom2 -n kube-system|grep health
    Liveness:        http-get https://127.0.0.1:6443/healthz delay=15s timeout=15s period=10s #success=1 #failure=8

可以看到liveness check有8次failure!8次是kube-apiserver的failure门槛值,这个值在/etc/kubernetes/manifests/kube-apiserver.yaml中我们可以看到:

livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 15
      timeoutSeconds: 15

这样,一旦failure次数超限,kubelet会尝试Restart kube-apiserver,这就是问题的原因。那么为什么kube-apiserver的liveness check会fail呢?这缘于我们关闭了匿名请求的身份验证权。还是来看/etc/kubernetes/manifests/kube-apiserver.yaml中的livenessProbe段,对于kube-apiserver来说,kubelet会通过访问: https://127.0.0.1:6443/healthz的方式去check是否ok?并且kubelet使用的是anonymous requests。由于上面我们已经关闭了对anonymous-requests的身份验证权,kubelet就会一直无法访问kube-apiserver的/healthz端点,导致kubelet认为kube-apiserver已经死亡,并尝试重启它。

四、调整/healthz检测的端点

我们既要保留 –anonymous-auth=false,还要保证kube-apiserver稳定运行不重启,我们就需要调整kube-apiserver的livenessProbe配置,将liveness probe的endpoint从

https://127.0.0.1:6443/healthz

改为:

http://127.0.0.1:8080/healthz

具体对/etc/kubernetes/manifests/kube-apiserver.yaml的修改是:

spec:
  containers:
  - command:
    - kube-apiserver
    - --anonymous-auth=false
    ... ...
    - --insecure-bind-address=127.0.0.1
    - --insecure-port=8080

   livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 8080
        scheme: HTTP
      initialDelaySeconds: 15
      timeoutSeconds: 15
... ...

我们不再用anonymous-requests,但我们可以利用–insecure-bind-address和–insecure-port。让kubelet的请求到insecure port,而不是secure port。由于insecure port的流量不会受到身份验证、授权等功能的限制,因此可以成功probe到kube-apiserver的liveness,kubelet不会再重启kube-apiserver了。