keepalived实战之小试牛刀

keepalived是什么

keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障。

keepalived工作原理

keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。 虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip(该路由器所在局域网内其他机器的默认路由为该vip),master会发组播,当backup收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master。这样的话就可以保证路由器的高可用了。 keepalived主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式。vrrp模块是来实现VRRP协议的。

keepalived的配置文件

keepalived只有一个配置文件keepalived.conf,里面主要包括以下几个配置区域:
global_defs 主要是配置故障发生时的通知对象以及机器标识
static_ipaddress和static_routes区域配置的是是本节点的IP和路由信息
vrrp_script用来做健康检查的,当时检查失败时会将vrrp_instance的priority减少相应的值
vrrp_instance用来定义对外提供服务的VIP区域及其相关属性
vrrp_rsync_group用来定义vrrp_intance组,使得这个组内成员动作一致

keepalived实战之-小试牛刀主备模型

实验目标: 通过keepalived+lvs部署DR类型集群,实现高可用、负载均衡;主、备两台调度器均处于在线状态,当任意一台调度器宕机或出现故障时,VIP会“漂移”到另外一台服务器上,继续提供服务。

1.机器准备,做好时间同步,host解析

172.16.251.90  node1 [keepalived master]
172.16.251.91  node2 [keepalived backup]
172.16.251.92  node3 [web1 httpd rs1] 
172.16.251.94  node4 [web2 httpd rs2] 
172.16.251.95  node5 [client]

2.安装lvs和keepalived,我们在node1,node2上安装
node1:
(1).安装ipvsadm组件

yum install ipvsadm keepalived -y

(2).启动网卡间核心转发功能

sysctl -w net.ipv4.ip_forward=1
cat /proc/sys/net/ipv4/ip_forward

node2:同上

3.准备好web服务,实现web访问正常
node3:
(1).安装httpd

yum install httpd -y
echo "this is web1 test page." >/var/www/html/index.html

(2).启动httpd并测试一下子

systemctl start httpd
curl 127.0.0.1
[root@node3 ~]# curl 127.0.0.1
this is web1 test page.

node4:
(1).安装httpd

yum install httpd -y
echo "this is web2 test page." >/var/www/html/index.html

(2).启动httpd并测试一下子

systemctl start httpd
[root@node4 bin]# curl 127.0.0.1
this is web2 test page.

4.在node3,node4节点上配置vip

node3节点:
(1).配置VIP

ifconfig lo:0 172.16.50.50 netmask 255.255.255.255 broadcast 172.16.50.50 up
route add -host 172.16.50.50 dev lo:0

(2).配置rs主机参数

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

node4节点同上:

我们这里有个脚本可以通行配置:

cd /server/script/
vim setparam.sh

#!/bin/bash
        #
        vip=172.16.50.50
        mask='255.255.255.255'

        case $1 in
        start)
          echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
          echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
          echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
          echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

          ifconfig lo:0 $vip netmask $mask broadcast $vip up
          route add -host $vip dev lo:0
          ;;

         stop)
          ifconfig lo:0 down
          echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
          echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
          echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
          echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
          ;;

         *) 
          echo "Usage $(basename $0) start|stop"
          exit 1
      ;;
esac

5.在node1,node2上配置keepalived脚本

vim /etc/keepalived/keepalived.conf

node1脚本如下:

! Configuration File for keepalived

global_defs {

   #故障发生时给谁发邮件通知
   notification_email {
     root@localhost
   }
   #通知邮件从哪个地址发出
   notification_email_from keepalived@localhost
   #通知邮件的smtp地址
   smtp_server 127.0.0.1
   #连接smtp服务器的超时时间
   smtp_connect_timeout 30
   #通过组播地址通告状态和优先级信息
   vrrp_mcast_group4 224.0.100.24  
}

vrrp_instance sr1 {
    #MASTER或BACKUP
    state MASTER
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 51
    #设置优先级,选举master,取值范围1-255
    priority 100
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node1
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9RbiPlp
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.50.50/24 dev ens33 label ens33:0
    }
}

virtual_server 172.16.50.50 80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}

node2脚本如下:

! Configuration File for keepalived

global_defs {

   #故障发生时给谁发邮件通知
   notification_email {
     root@localhost
   }
   #通知邮件从哪个地址发出
   notification_email_from keepalived@localhost
   #通知邮件的smtp地址
   smtp_server 127.0.0.1
   #连接smtp服务器的超时时间
   smtp_connect_timeout 30
   #通过组播地址通告状态和优先级信息
   vrrp_mcast_group4 224.0.100.24  
}

vrrp_instance sr1 {
    #MASTER或BACKUP
    state BACKUP
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 51
    #设置优先级,选举master,取值范围1-255
    priority 96
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node2
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9RbiPlp
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.50.50/24 dev ens33 label ens33:0
    }
}

virtual_server 172.16.50.50 80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    nat_mask 255.255.255.255
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}

6.测试关掉其中任何一个keepalived,都可访问curl 172.16.50.50

keepalived实战之-小试牛刀双主模型

我们刚刚做了一个主备模型,现在我们将这个主备模型稍微改造一下,我们只需要改造keepalived的配置文件即可:

1.在这之前,因为我们做的是lvs-dr模型,所以同样我们需要在node3,node4上做另外一个vip 因此在node3,node4上操作:

ifconfig lo:1 172.16.60.60 netmask 255.255.255.255 broadcast 172.16.60.60 up
route add -host 172.16.60.60 dev lo:1

我们用ifconfig可以看到两个

lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 172.16.50.50  netmask 255.255.255.255
        loop  txqueuelen 1  (Local Loopback)

lo:1: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 172.16.60.60  netmask 255.255.255.255
        loop  txqueuelen 1  (Local Loopback)

通用脚本改成如下:

#!/bin/bash

# Filename:    setvip.sh
# Revision:    1.1
# Date:        2017/06/24
# Author:      Srayban
# Email:       626612631@qq.com
# Website:     no
# Description: 设置vip

. /etc/init.d/functions


vip="172.16.50.50"
vip2="172.16.60.60"
mask="255.255.255.255"
case $1 in
start)
     echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
     echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
     echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
     echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

     ifconfig lo:0 $vip netmask $mask broadcast $vip up
     ifconfig lo:1 $vip2 netmask $mask broadcast $vip2 up
     route add -host $vip dev lo:0
     route add -host $vip2 dev lo:1
     ;;

 stop)
     ifconfig lo:0 down
     ifconfig lo:1 down
     echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
     echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
     echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
     echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
     ;;

 *) 
     echo "Usage $(basename $0) start|stop"
     exit 1
     ;;
 esac
 action "setvip is success." true

2.在node1,node2上改造keepalived脚本

vim /etc/keepalived/keepalived.conf

node1脚本如下:

! Configuration File for keepalived

global_defs {

   #故障发生时给谁发邮件通知
   notification_email {
     root@localhost
   }
   #通知邮件从哪个地址发出
   notification_email_from keepalived@localhost
   #通知邮件的smtp地址
   smtp_server 127.0.0.1
   #连接smtp服务器的超时时间
   smtp_connect_timeout 30
   #通过组播地址通告状态和优先级信息
   vrrp_mcast_group4 224.0.100.24  
}

vrrp_instance sr1 {
    #MASTER或BACKUP
    state MASTER
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 51
    #设置优先级,选举master,取值范围1-255
    priority 100
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node1
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9RbiPlp
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.50.50/24 dev ens33 label ens33:0
    }
}


vrrp_instance sr2 {
    #MASTER或BACKUP
    state BACKUP
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 61
    #设置优先级,选举master,取值范围1-255
    priority 96
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node1
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9ObiP0p
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.60.60/24 dev ens33 label ens33:1
    }
}


virtual_server 172.16.60.60  80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}


virtual_server 172.16.50.50 80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}

node2脚本如下:

! Configuration File for keepalived

global_defs {

   #故障发生时给谁发邮件通知
   notification_email {
     root@localhost
   }
   #通知邮件从哪个地址发出
   notification_email_from keepalived@localhost
   #通知邮件的smtp地址
   smtp_server 127.0.0.1
   #连接smtp服务器的超时时间
   smtp_connect_timeout 30
   #通过组播地址通告状态和优先级信息
   vrrp_mcast_group4 224.0.100.24  
}

vrrp_instance sr1 {
    #MASTER或BACKUP
    state BACKUP
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 51
    #设置优先级,选举master,取值范围1-255
    priority 96
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node2
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9RbiPlp
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.50.50/24 dev ens33 label ens33:0
    }
}


vrrp_instance sr2 {
    #MASTER或BACKUP
    state MASTER
    #节点固有IP(非VIP)的网卡,用来发VRRP包
    interface ens33
    #取值在0-255之间,用来区分多个instance的VRRP组播
    virtual_router_id 61
    #设置优先级,选举master,取值范围1-255
    priority 100
    #健康查检时间间隔
    advert_int 1
    #定义 router_id
    router_id node2
    #认证区域,认证类型有PASS和HA(IPSEC),密码8位字符
    authentication {
        auth_type PASS
        auth_pass r9ObiP0p
    }
    #配置要监控的网络接口,一旦接口出现故障,则转为FAULT状态;
    track_interface {    
        ens33                        
    }
    #nopreempt #非抢占模式
    #配置虚拟IP地址(vip)
    virtual_ipaddress {
        172.16.60.60/24 dev ens33 label ens33:1
    }
}


virtual_server 172.16.60.60  80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    nat_mask 255.255.255.255
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}

virtual_server 172.16.50.50 80 {
    #定义延迟轮询时间(单位秒)  
    delay_loop 6
    #设定VS的调用算法
    lb_algo wrr
    #设定lvs调度类型
    lb_kind DR
    nat_mask 255.255.255.255
    persistence_timeout 50
    #工作的协议
    protocol TCP
    #当所有real server宕掉时,sorry server顶替
    sorry_server 127.0.0.1 80     

    #真正提供服务的服务器RS1
    real_server 172.16.251.92 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }

    #真正提供服务的服务器RS2
    real_server 172.16.251.94 80 {
        #权重
        weight 1

        #设置健康状态检测方法
        HTTP_GET  {
            url {

              #定义要监控的URL;
              path /

              #判断上述检测机制为健康状态的响应码;
              status_code 200
            }

            #连接请求的超时时长
            connect_timeout 3
            #重试次数
            nb_get_retry 3
            #下次重试的延迟时间
            delay_before_retry 1
        }
    }


}

3.脚本改造以后,启动keepalived

for i in {1..12};do curl 172.16.50.50; curl 172.16.60.60; done

可以看到两个都能正常访问了

原创文章,作者:srayban,如若转载,请注明出处:http://www.178linux.com/78490

(0)
sraybansrayban
上一篇 2017-06-24
下一篇 2017-06-25

相关推荐

  • 关于大型网站技术演进的思考(十二)–网站静态化处理—缓存(4)

    原文出处: 夏天的森林   上篇我补充了下SSI的知识,SSI是一个十分常见的技术,记得多年前我看到很多门户网站页面的后缀是.shtml,那么这就说明很多门户网站都曾经使用过SSI技术,其实现在搜狐网站也还在用shtml,如下图所示: 由此可见SSI在互联网的应用还是非常广泛的。其实互联网很多网页如果我们按照动静分离策略拆分,绝…

    2015-03-11
  • grep

    1. 文本处理工具的使用:   cat 连接文件并打印到标准输出设备,但是文件较大时,翻屏太快,与more或者less连用 命令反着输入(tac)将会反向输出文本文件 用法: cat 选项 参数   选项: -A 显示不可打印字符 -b 对行进行编号,空白行不编号 -s 压缩空白行 -n 对行进行编号,包括空白航  参数: &n…

    Linux干货 2016-08-08
  • N25-第4周作业(用户权限,grep用法)

    复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有访问权限.      [root@bogon ~]# chmod -R o=—,g=— /home/tuser1/ [root@bogon ~]# chmod -R o=,g= /home/tuser1/ 编辑/etc/…

    Linux干货 2016-12-26
  • 在linux中创建虚拟网卡(网卡别名)的方法

    由于业务需要,要在单个物理网卡上建立多个虚拟网卡,操作如下:cd /etc/sysconfig/network-scripts/   #进入网卡目录cp ifcfg-eth0 ifcfg-eth0:1   # 复制出ifcfg-eth0:1虚拟网卡vim ifcfg-eth0:1    #配置ifcfg-eth0:1虚…

    Linux干货 2016-09-06
  • 第十周 N21 总有刁民想害朕

    1、请详细描述CentOS系统的启动流程(详细到每个过程系统做了哪些事情)   加电-MBR-GRUB-/sysinit-init X 对应的服务-/etc/rc.d     MBR        读取分区表     GRUB      &…

    Linux干货 2016-09-26
  • 课后习题3–正则表达式

    1、查出分区空间使用率的最大百分比值 [root@centos7 ~]# df | grep "^/dev" | grep -v "cdrom$" | tr ' '&nb…

    Linux干货 2016-08-07