一、環境介紹
阿里雲服務器CentOS 7.9
[root@keep1 ~]# cat /etc/hosts ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 172.16.208.195 keep1 172.16.208.196 keep2
二、創建阿里雲彈性網卡
三、安裝keepalived
yum install keepalived -y
四、安裝安裝自動配置eni網卡(2台都需安裝)
阿里雲的eni只對CentOS 7.3和CentOS 6.8能自動識別到網卡,其他版本需要配置網卡參數
官方文檔
https://www.alibabacloud.com/help/zh/doc-detail/56955.htm?spm=a2c63.p38356.b99.398.5367779fyWo75G
1、安裝自動配置eni網卡(系統需高於CentOS 7.3版本)
wget https://image-offline.oss-cn-hangzhou.aliyuncs.com/multi-nic-util/multi-nic-util-0.6.tgz tar -zxvf multi-nic-util-0.6.tgz cd multi-nic-util-0.6 bash install.sh
五、創建阿里雲的accessKeyId和accessSecret,授權ECS管理權限(AliyunECSFullAccess)
六、go環境安裝
go sdk安裝文檔:https://help.aliyun.com/document_detail/63640.htm?spm=5176.12573546.1318498.5.433c97a5QYvwVA
api文檔:https://www.alibabacloud.com/help/zh/doc-detail/25485.htm?spm=a2c63.p38356.b99.657.25a92647ynVJk3
1、golang安裝與代理配置
#golang安裝 yum install -y golang #添加代理 go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn,direct
七、創建eni項目
1、創建目錄
mkdir /go/eni/ -p
2、創建main腳本文件
package main import ( "encoding/json" "flag" "fmt" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/buger/jsonparser" "time" ) type aliyunAuth struct { regionId string accessKeyId string accessSecret string } func (self aliyunAuth) ecsBindingEni(NetworkInterfaceId,InstanceId string) { client, err := ecs.NewClientWithAccessKey(self.regionId,self.accessKeyId,self.accessSecret) request := ecs.CreateAttachNetworkInterfaceRequest() request.Scheme = "https" request.NetworkInterfaceId = NetworkInterfaceId request.InstanceId = InstanceId response, err := client.AttachNetworkInterface(request) if err != nil { fmt.Print(err.Error()) } fmt.Printf("response is %#v\n", response) } func (self aliyunAuth) ecsRemoveEni(NetworkInterfaceId,InstanceId string) { client, err := ecs.NewClientWithAccessKey(self.regionId,self.accessKeyId,self.accessSecret) request := ecs.CreateDetachNetworkInterfaceRequest() request.Scheme = "https" request.NetworkInterfaceId = NetworkInterfaceId request.InstanceId = InstanceId response, err := client.DetachNetworkInterface(request) if err != nil { fmt.Print(err.Error()) } fmt.Printf("response is %#v\n", response) } func (self aliyunAuth) getEcsId( eni_ip string) string { client, err := ecs.NewClientWithAccessKey(self.regionId,self.accessKeyId,self.accessSecret) request := ecs.CreateDescribeNetworkInterfacesRequest() request.Scheme = "https" request.PrimaryIpAddress = eni_ip response, err := client.DescribeNetworkInterfaces(request) result, _ := json.Marshal(response) ecs_id, _ := jsonparser.GetString(result,"NetworkInterfaceSets","NetworkInterfaceSet","[0]","InstanceId") if err != nil { fmt.Print(err.Error()) } fmt.Printf("response is %#v\n", response) return ecs_id } func main() { var ( behavior = flag.String("b","attach","執行操作") eniInterfaceId = flag.String("n", "", "彈性網卡Id") ecsId = flag.String("e", "", "ECSId") eniIp = flag.String("i", "", "彈性網卡Ip") ) flag.Parse() var eni = new(aliyunAuth) eni.regionId = "cn-hangzhou" eni.accessKeyId = "xxxxxxxxxxxx" eni.accessSecret = "xxxxxxxxxxxxxx" switch *behavior { case "attach" : ecs_id := eni.getEcsId(*eniIp) if ecs_id == "" { eni.ecsBindingEni(*eniInterfaceId,*ecsId) }else { if *ecsId == ecs_id { break } eni.ecsRemoveEni(*eniInterfaceId,ecs_id) for i := 0;i < 10; i++ { time.Sleep(time.Millisecond*500) if eni.getEcsId(*eniIp) == ""{ eni.ecsBindingEni(*eniInterfaceId,*ecsId) break } } } case "remove": eni.ecsRemoveEni(*eniInterfaceId,*ecsId) default: fmt.Println("Usage: { attach|remove }") } }
3、go mod與go vendor
[root@keep1 ~]# cd /go/eni/ [root@keep1 eni]# ls main.go [root@keep1 eni]# go mod init eni go: creating new go.mod: module eni [root@keep1 eni]# go mod vendor go: finding module for package github.com/buger/jsonparser go: finding module for package github.com/aliyun/alibaba-cloud-sdk-go/services/ecs go: downloading github.com/aliyun/alibaba-cloud-sdk-go v1.61.865 go: downloading github.com/buger/jsonparser v1.1.1 go: found github.com/aliyun/alibaba-cloud-sdk-go/services/ecs in github.com/aliyun/alibaba-cloud-sdk-go v1.61.865 go: found github.com/buger/jsonparser in github.com/buger/jsonparser v1.1.1 go: downloading github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af go: downloading github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 go: downloading gopkg.in/ini.v1 v1.42.0 go: downloading github.com/json-iterator/go v1.1.5 go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
4、編譯
go build -o eni main.go
八、keepalived檢查腳本
[root@keep2 ~]# cat /etc/keepalived/check_eni.sh #!/bin/bash KEEPALIVED_VIP=192.168.1.100 ENI_VIP=172.31.0.240 if [ `ip a s eth0|grep ${KEEPALIVED_VIP}|wc -l` -eq 1 ]; then if [ `ip a s eth1|grep $ENI_VIP|wc -l` -eq 1 ]; then ping -c 1 -w 1 $ENI_VIP >/dev/null [ $? -ne 0 ]&& exit 1 fi fi
九、keepalived配置文件
1、主配置文件

! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc #發送郵箱 } notification_email_from Alexandre.Cassen@firewall.loc #郵箱地址 smtp_server 127.0.0.1 #郵件服務器地址 smtp_connect_timeout 30 router_id LVS_DEVEL-01 #主機名,每個節點不同即可 } vrrp_script check_LVS { script "/etc/keepalived/check_eni.sh" #腳本路徑 interval 2 #2秒執行一次 timeout 2 #超時時長 weight -2 #腳本執行失敗優先級降低2 rise 3 #連續3次執行腳本成功表示ok fall 3 #連續3次腳本執行失敗表示失敗 } vrrp_instance VI_1 { state MASTER #節點主從,在另一個節點上為BACKUP interface eth0 #IP地址漂移到的網卡 virtual_router_id 51 #多個節點必須相同 priority 100 #優先級,備用節點的值必須低於主節點的值 advert_int 1 #通告間隔1秒 authentication { auth_type PASS #預共享密鑰認證 auth_pass 1111 #密鑰 } unicast_src_ip 172.16.208.195 #本機地址 unicast_peer { 172.16.208.196 #目標地址 } notify_master "/go/eni/eni -b attach -n 彈性網卡Id -e ECSId -i 172.16.208.200" track_script { check_LVS } virtual_ipaddress { 192.168.1.100/24 dev eth0 #VIP地址 } }
2、備配置

! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_DEVEL-02 } vrrp_script check_LVS { script "/etc/keepalived/check_eni.sh" interval 2 timeout 2 weight -2 rise 3 fall 3 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 99 advert_int 1 authentication { auth_type PASS auth_pass 1111 } unicast_src_ip 172.16.208.196 unicast_peer { 172.16.208.195 } notify_master "/go/eni/eni -b attach -n 彈性網卡Id -e ECSId -i 彈性網卡Ip" track_script { check_LVS } virtual_ipaddress { 192.168.1.100/24 dev eth0 } }
3、啟動keepalived
systemctl start keepalived.service
十、測試
keep1服務器停止keepalived后查看eni的ip是否會綁定到keep2服務器上
1、keep1服務器操作
[root@keep1 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:16:3e:12:e6:15 brd ff:ff:ff:ff:ff:ff inet 172.16.208.195/20 brd 172.16.223.255 scope global dynamic eth0 valid_lft 315354146sec preferred_lft 315354146sec inet 192.168.1.100/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe12:e615/64 scope link valid_lft forever preferred_lft forever 8: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:16:3e:16:d2:e5 brd ff:ff:ff:ff:ff:ff inet 172.16.208.200/20 brd 172.16.223.255 scope global dynamic eth1 valid_lft 315359996sec preferred_lft 315359996sec inet6 fe80::216:3eff:fe16:d2e5/64 scope link valid_lft forever preferred_lft forever [root@keep1 ~]# systemctl stop keepalived.service
2、keep2服務器查看(彈性網卡已綁定到keep2服務器)
[root@keep2 ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:16:3e:16:c4:39 brd ff:ff:ff:ff:ff:ff inet 172.16.208.196/20 brd 172.16.223.255 scope global dynamic eth0 valid_lft 315353960sec preferred_lft 315353960sec inet 192.168.1.100/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe16:c439/64 scope link valid_lft forever preferred_lft forever 9: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:16:3e:16:d2:e5 brd ff:ff:ff:ff:ff:ff inet 172.16.208.200/20 brd 172.16.223.255 scope global dynamic eth1 valid_lft 315359985sec preferred_lft 315359985sec inet6 fe80::216:3eff:fe16:d2e5/64 scope link valid_lft forever preferred_lft forever