阿里雲負載均衡權重管理腳本


阿里雲權重管理

背景

我們的公司采用的是阿里雲環境,發布體系中需要滾動更新功能,需要編寫腳本來完成負載均衡對應主機的權重為0,然后發布代碼到這個服務器上, 重啟成功后修改回原有權重,然后一個一個處理完畢集群的所有主機。

阿里雲負載均衡簡介

負載均衡的幾個常見概念。

名詞 說明
負載均衡服務 (Server Load Balancer) 阿里雲計算提供的一種網絡負載均衡服務,結合阿里雲提供的ECS服務,提供四層和七層負載均衡服務。
負載均衡實例(Server Load Balancer Instances) 負載均衡實例是一個運行的負載均衡服務。要使用負載均衡服務,必須先創建一個負載均衡實例。
服務地址 (SLB IP address) 系統為創建的負載均衡實例分配的服務IP地址。根據創建的負載均衡實例的類型,服務地址可能是公網IP也可能是私網IP。您可以將域名解析到公網IP地址提供對外服務。
監聽 (Listeners) 負載均衡服務監聽規定了如何將請求轉發給后端服務器。一個負載均衡實例至少添加一個監聽。
后端服務器 (Backend Servers) 處理負載均衡分發的前端請求的ECS實例。
虛擬服務器組 (Backend Servers Groups) 一組處理負載均衡分發的前端請求的ECS實例。不同的監聽可以關聯不同的虛擬服務器組,實現監聽維度的請求轉發。

阿里雲提供2種服務器組, 一個是默認服務器組,一個是虛擬服務器組, 如果一個負載均衡上面只掛一個域名的多個主機,建議直接將后端的服務器加入到默認服務器組即可,

如果你的負載均衡掛多個域名的話, 建議以域名為虛擬服務器的名字,創建多個虛擬服務器組,每個組下面掛載對應的后端服務器。

我們的線上環境建議采用一個域名一個負載均衡, 測試環境可以考慮一個負載下弄多個域名,省點錢,我們簡單算下使用多負載均衡和一個負載負載多域名方案價格差異。

阿里雲官方的負載均衡配置價格不貴,配置費用為0.02元每小時。公網流量費用0.48元/GB,對於2種方案來說流量都是一樣的。采用多負載均衡會多出多個配置費用, 1個負載均衡的配置費用1年下來大概為0.02*24*365≈175元。可以根據自身公司情況選擇一種方案。

管理腳本

使用這個腳本,需要安裝python3環境,並安裝如下包

pip install aliyun-python-sdk-core-v3
pip install aliyun-python-sdk-ecs
pip install aliyun-python-sdk-slb

slb_manager.py內容如下:

# !/usr/bin/env python
# -*-coding:utf-8 -*-

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest

import json
import os
import sys

from enum import Enum


def byte_to_json(response):
    response_str = str(response, encoding='utf-8')
    response_json = json.loads(response_str)
    return response_json


class SlbManagerInfo():
    def __init__(self, exit_code=0, exit_message=""):
        self.exit_code = exit_code
        self.exit_message = exit_message
        self.extra_message = {}

    def __str__(self):
        return str(self.__dict__)


class SlbManager():
    """
        阿里雲負載均衡管理,支持對默認的組和虛擬服務器組的管理
    """

    def __init__(self, slb_config_file, region_id="cn-beijing"):
        """
        初始化client,slb_config_file內容為以下格式
        {
            "slb_ak":"xxxxxxxxxxxxxx",
            "slb_sk":"xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
        """
        self.slb_config_file = slb_config_file
        self.region_id = region_id

        self.slb_manager_info = SlbManagerInfo()

        self.ak, self.sk = self.get_aksk_from_config_file()
        self.client = AcsClient(self.ak, self.sk, self.region_id)
    def pre_check(self):
        if isinstance(self.weight,int):
            if (self.weight >100 or self.weight <0):
                self.slb_manager_info.exit_code = 1
                self.slb_manager_info.exit_message = "權重設置不符合要求(0=100)" + "你的設置為" +str(self.weight)
        else:
            self.slb_manager_info.exit_code = 2
            self.slb_manager_info.exit_message = "權重不是int的,請檢查"
    def set_comm_request(self, request, product_type="slb"):
        request.set_accept_format('json')
        request.set_method('POST')
        request.set_domain(product_type + '.aliyuncs.com')

    def get_aksk_from_config_file(self):
        if not (os.path.exists(self.slb_config_file)):
            self.slb_manager_info.exit_code = 1
            self.slb_manager_info.exit_message = self.slb_config_file + "文件找不到"
        try:
            with open(self.slb_config_file, 'r') as f:
                slb_config = json.load(f)
        except IOError as e:
            self.slb_manager_info.exit_code = 2
            self.slb_manager_info.exit_message = "文件讀取失敗" + str(e)
        return slb_config["slb_ak"], slb_config["slb_sk"]

    def get_slb_id(self):
        request = CommonRequest()
        self.set_comm_request(request)
        request.set_version('2014-05-15')
        request.set_action_name('DescribeLoadBalancers')
        request.add_query_param('LoadBalancerName', self.slb_name)
        response = self.client.do_action_with_exception(request)
        response_json = byte_to_json(response)
        if response_json["TotalCount"] != 1 :
            self.slb_manager_info.exit_code = 3
            self.slb_manager_info.exit_message ="根據負載均衡名字獲取到的總個數不為1 ,請確認負載的名字,真實獲取的個數為" +str(response_json["TotalCount"] )
        else:
            self.slb_id = response_json["LoadBalancers"]["LoadBalancer"][0]["LoadBalancerId"]
        a=1
    def get_ecs_id(self):
        request = CommonRequest()
        self.set_comm_request(request, product_type='ecs')
        request.set_version('2014-05-26')
        request.set_action_name('DescribeInstances')
        request.add_query_param('InstanceName', self.ecs_name)
        response = self.client.do_action_with_exception(request)
        response_json = byte_to_json(response)
        if response_json["TotalCount"] != 1 :
            self.slb_manager_info.exit_code = 4
            self.slb_manager_info.exit_message = "獲取不到ecsid,請檢查ecs_name"
        else:
            self.ecs_id = response_json["Instances"]["Instance"][0]["InstanceId"]

    def set_weight_for_ecs(self):
        for backend_server in self.backend_servers:
            backend_server["ServerId"] = backend_server["VmName"]
            if backend_server["VmName"] == self.ecs_id:
                # 保留下設置前的權重
                self.slb_manager_info.extra_message["old_weight"] = backend_server["Weight"]
                backend_server["Weight"] = self.weight

    def set_weight_for_default_group_backend_servers(self):
        request = CommonRequest()
        self.set_comm_request(request)
        request.set_version('2014-05-15')
        request.set_action_name('SetBackendServers')
        request.add_query_param('LoadBalancerId', self.slb_id)
        request.add_query_param('BackendServers', self.backend_servers)
        response = self.client.do_action_with_exception(request)
        response_json = byte_to_json(response)
        # 這個貌似沒法對結果進行判定。

    def set_weight_for_virtual_group_backend_servers(self):
        request = CommonRequest()
        self.set_comm_request(request)
        request.set_version('2014-05-15')
        request.set_action_name('SetVServerGroupAttribute')
        request.add_query_param('LoadBalancerId', self.slb_id)
        request.add_query_param('VServerGroupId', self.virtual_group_id)
        # request.add_query_param('VServerGroupName', 'test2')
        request.add_query_param('BackendServers', self.backend_servers)
        response = self.client.do_action_with_exception(request)
        response_json = byte_to_json(response)
        # 這個貌似沒法對結果進行判定。

    def get_slb_info(self):
        request = CommonRequest()
        self.set_comm_request(request)
        request.set_version('2014-05-15')
        request.set_action_name('DescribeLoadBalancersRelatedEcs')
        request.add_query_param('LoadBalancerId', self.slb_id)
        response = self.client.do_action_with_exception(request)
        response_json = byte_to_json(response)
        if not response_json["Success"]:
            self.slb_manager_info.exit_code = 4
            self.slb_manager_info.exit_message = response_json["Message"]
        else:
            self.slb_info = response_json["LoadBalancers"]["LoadBalancer"][0]

        if self.is_default_group:
            self.backend_servers = self.slb_info["BackendServers"]["BackendServer"]
        else:
            self.virtual_server_group= None
            for virtual_group in self.slb_info["VServerGroups"]["VServerGroup"]:
                if virtual_group["GroupName"] == self.group_name:
                    self.virtual_server_group = virtual_group
                    break
            if self.virtual_server_group is None:
                self.slb_manager_info.exit_code = 6
                self.slb_manager_info.exit_message = "你輸入的虛擬服務器組,不在特定的負載均衡下,請檢查"
            else:
                self.virtual_group_id = self.virtual_server_group["GroupId"]
                self.backend_servers = self.virtual_server_group["BackendServers"]["BackendServer"]

        # self.backend_servers =  response_json["LoadBalancers"]["LoadBalancer"][0]["VServerGroups"]["VServerGroup"][0]["BackendServers"]["BackendServer"]

    def set_weight_for_default_group(self, slb_name, ecs_name, weight):
        # set
        self.slb_name = slb_name
        self.ecs_name = ecs_name
        self.weight = weight
        self.is_default_group = True
        if self.slb_manager_info.exit_code == 0:
            self.pre_check()
        if self.slb_manager_info.exit_code == 0:
            self.get_slb_id()
        if self.slb_manager_info.exit_code == 0:
            self.get_ecs_id()

        if self.slb_manager_info.exit_code == 0:
            self.get_slb_info()

        if self.slb_manager_info.exit_code == 0:
            self.set_weight_for_ecs()

        if self.slb_manager_info.exit_code == 0:
            self.set_weight_for_default_group_backend_servers()
        print(self.slb_manager_info)
        return self.slb_manager_info.exit_code

    def set_weight_for_virtual_group(self, slb_name, group_name, ecs_name, weight):
        # set
        self.slb_name = slb_name
        self.ecs_name = ecs_name
        self.group_name = group_name
        self.weight = weight
        self.is_default_group = False
        if self.slb_manager_info.exit_code == 0:
            self.pre_check()
        if self.slb_manager_info.exit_code == 0:
            self.get_slb_id()
        if self.slb_manager_info.exit_code == 0:
            self.get_ecs_id()
        if self.slb_manager_info.exit_code == 0:
            self.get_slb_info()
        if self.slb_manager_info.exit_code == 0:
            self.set_weight_for_ecs()
        if self.slb_manager_info.exit_code == 0:
            self.set_weight_for_virtual_group_backend_servers()
        print(self.slb_manager_info)
        return self.slb_manager_info.exit_code


def main():

    """
    python3 slb_manager.py <you_slb_name> <you_group_name> <you_ecs_name> <you_ecs_weight>
    """
    print(sys.argv)
    slb_name = sys.argv[1]
    group_name = sys.argv[2]
    ecs_name = sys.argv[3]
    weight = int(sys.argv[4])
    slb_config_file = r'c:\\slbconfig'
    region_id = 'cn-beijing'
    manager = SlbManager(slb_config_file=slb_config_file, region_id=region_id)
    ret =0
    if group_name == "default":
        ret =manager.set_weight_for_default_group(slb_name, ecs_name, weight)
    else:
        ret =manager.set_weight_for_virtual_group(slb_name, group_name, ecs_name, weight)
    sys.exit(ret)

if __name__ == "__main__":
    main()
    # manager = SlbManager(slb_config_file=r'c:\\slbconfig',region_id='cn-beijing')
    # manager.set_weight_for_default_group('lb_tmp','aliyun_test03',10)
    # manager.set_weight_for_virtual_group('lb_tmp','test2','aliyun_test02',0)

注意事項

  1. 腳本是支持默認服務器組和虛擬服務器的, 如果接受的第三個參數為default,表示設置的默認后端服務器的權重, 如果為其他的,表示設置虛擬服務器組,且組名為你傳遞過來的值,所有使用此腳本你的虛擬服務器組不能設置叫default的組名。
  2. 可以根據退出碼來判定設置結果情況。
  3. 輸出的結果信息里面有修改前的權重值,可以使用bash命令來提取這個腳本的輸出來獲取。
  4. 你提供的ecs名字在ecs在你所有的ec的名字中是唯一的
  5. 你提供的slb名字在你自己的slb的所有名字中是唯一的。

腳本使用

第一步: ram創建一個賬號, 並授予該賬號的slb所有權限,ecs所有權限,並為該用戶生成ak,sk。

第二步: 創建一個文件寫入ak,sk信息。

內容如下

{
      "slb_ak":"xxxxxxxxxxxxxx",
      "slb_sk":"xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

第三步: 

修改腳本的 slb_config_file的路徑為你的aksk文件路徑,修改region-id默認值。

第四步: 創建一個按量付費的負載均衡測試下。

使用樣例

C:\Users\Administrator\Anaconda3\python.exe E:/haoweilai/Devops/scripts/slb_manager.py lb_tmp3 test23 aliyun_test02 13
['E:/haoweilai/Devops/scripts/slb_manager.py', 'lb_tmp3', 'test23', 'aliyun_test02', '13']
{'exit_code': 3, 'exit_message': '根據負載均衡名字獲取到的總個數不為1 ,請確認負載的名字,真實獲取的個數為0', 'extra_message': {}}

C:\Users\Administrator\Anaconda3\python.exe E:/haoweilai/Devops/scripts/slb_manager.py lb_tmp test23 aliyun_test02 14
['E:/haoweilai/Devops/scripts/slb_manager.py', 'lb_tmp', 'test23', 'aliyun_test02', '14']
{'exit_code': 0, 'exit_message': '', 'extra_message': {'old_weight': 100}}

C:\Users\Administrator\Anaconda3\python.exe E:/haoweilai/Devops/scripts/slb_manager.py lb_tmp default aliyun_test02 50
['E:/haoweilai/Devops/scripts/slb_manager.py', 'lb_tmp', 'default', 'aliyun_test02', '50']
{'exit_code': 0, 'exit_message': '', 'extra_message': {'old_weight': 100}}

參考

阿里雲官方在線調試:  https://api.aliyun.com/

阿里雲python sdk地址: https://developer.aliyun.com/tools/sdk?#/python

負載均衡產品api參考: https://help.aliyun.com/document_detail/27566.html?spm=a2c4g.11186623.6.703.5a986327GsPz8E

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM