阿里云基于弹性网卡实现高可用ip

一、环境介绍

阿里云服务器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

 

posted @ 2021-01-18 14:40  巽逸  阅读(941)  评论(0编辑  收藏  举报