xuekailun 5 hónapja
commit
6d0cb16b46
3 módosított fájl, 210 hozzáadás és 0 törlés
  1. 43 0
      config.py
  2. 128 0
      main.py
  3. 39 0
      utils.py

+ 43 - 0
config.py

@@ -0,0 +1,43 @@
+import os
+import logging
+
+# 设置阿里云访问密钥的ID
+ALIBABA_CLOUD_ACCESS_KEY_ID = 'your_access_key_id'
+
+# 设置阿里云访问密钥的密钥
+ALIBABA_CLOUD_ACCESS_KEY_SECRET = 'your_access_key_secret'
+
+# ALB配置信息
+alb_config = {
+    'server_group_id': 'sgp-ec4gopoclruofsfmxu',  # 服务器组ID
+    'server_type': 'ecs',  # 服务器类型
+    'weight': 100  # 权重
+}
+
+# ECS实例配置信息
+instance_config = {
+    'size': '200',  # 实例大小
+    'category': 'cloud_efficiency',  # 实例类型
+    'region_id': 'cn-hangzhou',  # 地域ID
+    'image_id': 'centos_7_9',  # 镜像ID
+    'instance_type': 'ecs.c2.xlarge',  # 实例类型
+    'security_group_id': 'anquanzu',  # 安全组ID
+    'v_switch_id': 'vsjiaohuanji',  # 虚拟交换机ID
+    'instance_name': 'k8s-api-[1,2]',  # 实例名称
+    'unique_suffix': True,  # 是否使用唯一后缀
+    'password_inherit': True,  # 是否继承密码
+    'zone_id': 'cn-hangzhou-f',  # 可用区ID
+    'key_pair_name': 'miyaodui'  # 密钥对名称
+}
+
+# 读取启动脚本文件内容
+start_sh_dir = os.path.dirname(os.path.realpath(__file__))  # 获取当前文件所在目录
+start_sh_filename = 'start.sh'  # 启动脚本文件名
+with open(file=os.path.join(start_sh_dir, start_sh_filename), mode='r', encoding='utf-8') as rf:  # 打开启动脚本文件
+    file_content = rf.read()  # 读取文件内容
+    logging.info(f"start sh file content: {file_content}")  # 记录文件内容到日志
+start_sh = {
+    'target_dir': '/home/piao_server_sh',  # 目标目录
+    'name': start_sh_filename,  # 文件名
+    'content': file_content,  # 文件内容
+}

+ 128 - 0
main.py

@@ -0,0 +1,128 @@
+
+import os
+import sys
+import logging
+import asyncio
+from typing import List
+from concurrent.futures import ThreadPoolExecutor
+from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
+from alibabacloud_alb20200616.client import Client as Alb20200616Client
+from alibabacloud_tea_openapi import models as open_api_models
+from alibabacloud_ecs20140526 import models as ecs_20140526_models
+from alibabacloud_alb20200616 import models as alb_20200616_models
+from alibabacloud_tea_util import models as util_models
+from alibabacloud_tea_util.client import Client as UtilClient
+import config
+import utils
+
+class Sample:
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def create_ecs_client() -> Ecs20140526Client:
+        config = open_api_models.Config(  # 创建Config对象,用于配置访问凭证
+            access_key_id=config.ALIBABA_CLOUD_ACCESS_KEY_ID,  # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_ID参数
+            access_key_secret=config.ALIBABA_CLOUD_ACCESS_KEY_SECRET  # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_SECRET参数
+        )
+        config.endpoint = 'ecs-cn-hangzhou.aliyuncs.com'  # 设置ECS服务的访问地址
+        return Ecs20140526Client(config)  # 返回配置好的ECS客户端对象
+
+    @staticmethod
+    def create_alb_client() -> Alb20200616Client:
+        config = open_api_models.Config(  # 创建Config对象,用于配置访问凭证
+            access_key_id=config.ALIBABA_CLOUD_ACCESS_KEY_ID,  # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_ID参数
+            access_key_secret=config.ALIBABA_CLOUD_ACCESS_KEY_SECRET  # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_SECRET参数
+        )
+        config.endpoint = 'alb.cn-hangzhou.aliyuncs.com'  # 设置ALB服务的访问地址
+        return Alb20200616Client(config)  # 返回配置好的ALB客户端对象
+
+    @staticmethod
+    def create_ecs_instance(ecs_client: Ecs20140526Client, amount: int) -> List[str]:
+        instance_ids = []
+        for i in range(amount):
+            request = ecs_20140526_models.CreateInstanceRequest(  # 创建ECS实例请求
+                size=config.instance_config['size'],  # 实例大小
+                category=config.instance_config['category'],  # 实例类型
+                region_id=config.instance_config['region_id'],  # 地域ID
+                image_id=config.instance_config['image_id'],  # 镜像ID
+                instance_type=config.instance_config['instance_type'],  # 实例类型
+                security_group_id=config.instance_config['security_group_id'],  # 安全组ID
+                v_switch_id=config.instance_config['v_switch_id'],  # 虚拟交换机ID
+                instance_name=f"{config.instance_config['instance_name']}-{i+1}",  # 实例名称
+                unique_suffix=config.instance_config['unique_suffix'],  # 是否使用唯一后缀
+                password_inherit=config.instance_config['password_inherit'],  # 是否继承密码
+                zone_id=config.instance_config['zone_id'],  # 可用区ID
+                key_pair_name=config.instance_config['key_pair_name']  # 密钥对名称
+            )
+            response = ecs_client.create_instance(request)  # 调用ECS客户端的创建实例方法
+            instance_id = response.body.instance_id  # 获取创建的实例ID
+            instance_ids.append(instance_id)  # 将实例ID添加到列表中
+            logging.info(f"Created ECS instance with ID: {instance_id}")  # 记录日志
+        return instance_ids  # 返回实例ID列表
+
+    @staticmethod
+    async def start_services_and_health_check(create_client: Ecs20140526Client, slb_client: Alb20200616Client, ess_instance_ids: List[str]):
+        try:
+            await utils.send_file_to_ecs(client=create_client, instance_id_list=ess_instance_ids, **config.start_sh)  # 发送启动脚本到机器上
+            logging.info(f"send start shell file finished, instances: {ess_instance_ids}")
+
+            start_sh_param = "latest"
+            server_start_sh = os.path.join(config.start_sh['target_dir'], config.start_sh['name'])
+            server_start_commend = f"sh {server_start_sh} {start_sh_param}"
+            await utils.run_command(client=create_client, instance_ids=ess_instance_ids, command=server_start_commend)  # 启动服务
+
+            global health_instances
+            health_instances = []
+            max_wait_time = 180
+            loop = asyncio.get_running_loop()
+            max_workers = 10  # 设置最大线程数
+            executor = ThreadPoolExecutor(max_workers=max_workers)
+            tasks = [
+                loop.run_in_executor(executor, utils.health_check, *args) for args in
+                [(slb_client, instance_id, max_wait_time) for instance_id in ess_instance_ids]
+            ]
+            await asyncio.wait(tasks)  # 异步探活
+            logging.info(f"health instances count: {len(health_instances)}, {health_instances}")
+
+            if len(health_instances) > 0:  # 如果有机器探活成功
+                time.sleep(20)
+
+            Sample.mount_alb_to_instance(slb_client, ess_instance_ids)  # 将机器挂载到ALB服务器组中
+        except Exception as e:
+            logging.error(f"An error occurred: {e}")
+            sys.exit(1)  # 退出程序并返回错误状态码
+
+    @staticmethod
+    def mount_alb_to_instance(client: Alb20200616Client, instance_ids: List[str]) -> None:
+        try:
+            servers = [alb_20200616_models.AddServersToServerGroupRequestServers(  # 创建要添加的服务器列表
+                server_id=instance_id,
+                server_type=config.alb_config['server_type'],
+                weight=config.alb_config['weight']
+            ) for instance_id in instance_ids]
+            add_servers_to_server_group_request = alb_20200616_models.AddServersToServerGroupRequest(  # 创建添加服务器到服务器组的请求
+                server_group_id=config.alb_config['server_group_id'],  # 服务器组ID
+                servers=servers  # 服务器列表
+            )
+            runtime = util_models.RuntimeOptions()  # 创建运行时选项
+            client.add_servers_to_server_group_with_options(add_servers_to_server_group_request, runtime)  # 将机器挂载到ALB服务器组中
+        except Exception as e:
+            logging.error(f"An error occurred: {e}")
+            sys.exit(1)  # 退出程序并返回错误状态码
+
+    @staticmethod
+    def main(args: List[str]) -> None:
+        try:
+            ecs_client = Sample.create_ecs_client()  # 创建ECS客户端
+            alb_client = Sample.create_alb_client()  # 创建ALB客户端
+            amount = int(args[0]) if len(args) > 0 else 1  # 从命令行参数获取amount值,如果没有传入则默认为1
+            instance_ids = Sample.create_ecs_instance(ecs_client, amount)  # 创建ECS实例并获取实例ID列表
+
+            asyncio.run(Sample.start_services_and_health_check(ecs_client, alb_client, instance_ids))  # 使用asyncio运行启动服务和异步探活
+        except Exception as e:
+            logging.error(f"An error occurred: {e}")
+            sys.exit(1)  # 退出程序并返回错误状态码
+
+if __name__ == '__main__':
+    Sample.main(sys.argv[1:])  # 调用main方法,传递命令行参数

+ 39 - 0
utils.py

@@ -0,0 +1,39 @@
+
+import logging
+from typing import List
+from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
+from alibabacloud_ecs20140526 import models as ecs_20140526_models
+from alibabacloud_tea_util import models as util_models
+from alibabacloud_tea_util.client import Client as UtilClient
+import config
+
+
+# 发送文件到ECS实例
+def send_file_to_ecs(client: Ecs20140526Client, instance_id_list: List[str], target_dir: str, name: str, content: str) -> None:
+    for instance_id in instance_id_list:  # 遍历实例ID列表
+        describe_instance_attribute_request = ecs_20140526_models.DescribeInstanceAttributeRequest(  # 创建查询实例属性的请求
+            instance_id=instance_id  # 实例ID
+        )
+        runtime = util_models.RuntimeOptions()  # 创建运行时选项
+        response = client.describe_instance_attribute_with_options(describe_instance_attribute_request, runtime)  # 调用ECS客户端的查询实例属性方法
+        vpc_attributes = response.body.vpc_attributes  # 获取VPC属性
+        vpc_id = vpc_attributes.vpc_id  # 获取VPC ID
+        inner_ip_address = response.body.inner_ip_address  # 获取内网IP地址
+        ssh_client = UtilClient(vpc_id, inner_ip_address, 'root', config.ALIBABA_CLOUD_ACCESS_KEY_ID, config.ALIBABA_CLOUD_ACCESS_KEY_SECRET)  # 创建SSH客户端
+        ssh_client.upload_file(target_dir, name, content)  # 上传文件到实例
+        logging.info(f"File {name} sent to instance {instance_id}")  # 记录日志
+
+# 在ECS实例上执行命令
+def run_command(client: Ecs20140526Client, instance_ids: List[str], command: str) -> None:
+    for instance_id in instance_ids:  # 遍历实例ID列表
+        describe_instance_attribute_request = ecs_20140526_models.DescribeInstanceAttributeRequest(  # 创建查询实例属性的请求
+            instance_id=instance_id  # 实例ID
+        )
+        runtime = util_models.RuntimeOptions()  # 创建运行时选项
+        response = client.describe_instance_attribute_with_options(describe_instance_attribute_request, runtime)  # 调用ECS客户端的查询实例属性方法
+        vpc_attributes = response.body.vpc_attributes  # 获取VPC属性
+        vpc_id = vpc_attributes.vpc_id  # 获取VPC ID
+        inner_ip_address = response.body.inner_ip_address  # 获取内网IP地址
+        ssh_client = UtilClient(vpc_id, inner_ip_address, 'root', config.ALIBABA_CLOUD_ACCESS_KEY_ID, config.ALIBABA_CLOUD_ACCESS_KEY_SECRET)  # 创建SSH客户端
+        ssh_client.run_command(command)  # 在实例上执行命令
+        logging.info(f"Command '{command}' executed on instance {instance_id}")  # 记录日志