main.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import os
  2. import sys
  3. import logging
  4. import asyncio
  5. from typing import List
  6. from concurrent.futures import ThreadPoolExecutor
  7. from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
  8. from alibabacloud_alb20200616.client import Client as Alb20200616Client
  9. from alibabacloud_tea_openapi import models as open_api_models
  10. from alibabacloud_ecs20140526 import models as ecs_20140526_models
  11. from alibabacloud_alb20200616 import models as alb_20200616_models
  12. from alibabacloud_tea_util import models as util_models
  13. from alibabacloud_tea_util.client import Client as UtilClient
  14. import config
  15. import utils
  16. class Sample:
  17. def __init__(self):
  18. pass
  19. @staticmethod
  20. def create_ecs_client() -> Ecs20140526Client:
  21. config = open_api_models.Config( # 创建Config对象,用于配置访问凭证
  22. access_key_id=config.ALIBABA_CLOUD_ACCESS_KEY_ID, # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_ID参数
  23. access_key_secret=config.ALIBABA_CLOUD_ACCESS_KEY_SECRET # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_SECRET参数
  24. )
  25. config.endpoint = 'ecs-cn-hangzhou.aliyuncs.com' # 设置ECS服务的访问地址
  26. return Ecs20140526Client(config) # 返回配置好的ECS客户端对象
  27. @staticmethod
  28. def create_alb_client() -> Alb20200616Client:
  29. config = open_api_models.Config( # 创建Config对象,用于配置访问凭证
  30. access_key_id=config.ALIBABA_CLOUD_ACCESS_KEY_ID, # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_ID参数
  31. access_key_secret=config.ALIBABA_CLOUD_ACCESS_KEY_SECRET # 从config中获取ALIBABA_CLOUD_ACCESS_KEY_SECRET参数
  32. )
  33. config.endpoint = 'alb.cn-hangzhou.aliyuncs.com' # 设置ALB服务的访问地址
  34. return Alb20200616Client(config) # 返回配置好的ALB客户端对象
  35. @staticmethod
  36. def create_ecs_instance(ecs_client: Ecs20140526Client, amount: int) -> List[str]:
  37. instance_ids = []
  38. for i in range(amount):
  39. request = ecs_20140526_models.CreateInstanceRequest( # 创建ECS实例请求
  40. size=config.instance_config['size'], # 实例大小
  41. category=config.instance_config['category'], # 实例类型
  42. region_id=config.instance_config['region_id'], # 地域ID
  43. image_id=config.instance_config['image_id'], # 镜像ID
  44. instance_type=config.instance_config['instance_type'], # 实例类型
  45. security_group_id=config.instance_config['security_group_id'], # 安全组ID
  46. v_switch_id=config.instance_config['v_switch_id'], # 虚拟交换机ID
  47. instance_name=f"{config.instance_config['instance_name']}-{i+1}", # 实例名称
  48. unique_suffix=config.instance_config['unique_suffix'], # 是否使用唯一后缀
  49. password_inherit=config.instance_config['password_inherit'], # 是否继承密码
  50. zone_id=config.instance_config['zone_id'], # 可用区ID
  51. key_pair_name=config.instance_config['key_pair_name'] # 密钥对名称
  52. )
  53. response = ecs_client.create_instance(request) # 调用ECS客户端的创建实例方法
  54. instance_id = response.body.instance_id # 获取创建的实例ID
  55. instance_ids.append(instance_id) # 将实例ID添加到列表中
  56. logging.info(f"Created ECS instance with ID: {instance_id}") # 记录日志
  57. return instance_ids # 返回实例ID列表
  58. @staticmethod
  59. async def start_services_and_health_check(create_client: Ecs20140526Client, slb_client: Alb20200616Client, ess_instance_ids: List[str]):
  60. try:
  61. await utils.send_file_to_ecs(client=create_client, instance_id_list=ess_instance_ids, **config.start_sh) # 发送启动脚本到机器上
  62. logging.info(f"send start shell file finished, instances: {ess_instance_ids}")
  63. start_sh_param = "latest"
  64. server_start_sh = os.path.join(config.start_sh['target_dir'], config.start_sh['name'])
  65. server_start_commend = f"sh {server_start_sh} {start_sh_param}"
  66. await utils.run_command(client=create_client, instance_ids=ess_instance_ids, command=server_start_commend) # 启动服务
  67. global health_instances
  68. health_instances = []
  69. max_wait_time = 180
  70. loop = asyncio.get_running_loop()
  71. max_workers = 10 # 设置最大线程数
  72. executor = ThreadPoolExecutor(max_workers=max_workers)
  73. tasks = [
  74. loop.run_in_executor(executor, utils.health_check, *args) for args in
  75. [(slb_client, instance_id, max_wait_time) for instance_id in ess_instance_ids]
  76. ]
  77. await asyncio.wait(tasks) # 异步探活
  78. logging.info(f"health instances count: {len(health_instances)}, {health_instances}")
  79. if len(health_instances) > 0: # 如果有机器探活成功
  80. time.sleep(20)
  81. Sample.mount_alb_to_instance(slb_client, ess_instance_ids) # 将机器挂载到ALB服务器组中
  82. except Exception as e:
  83. logging.error(f"An error occurred: {e}")
  84. sys.exit(1) # 退出程序并返回错误状态码
  85. @staticmethod
  86. def mount_alb_to_instance(client: Alb20200616Client, instance_ids: List[str]) -> None:
  87. try:
  88. servers = [alb_20200616_models.AddServersToServerGroupRequestServers( # 创建要添加的服务器列表
  89. server_id=instance_id,
  90. server_type=config.alb_config['server_type'],
  91. weight=config.alb_config['weight']
  92. ) for instance_id in instance_ids]
  93. add_servers_to_server_group_request = alb_20200616_models.AddServersToServerGroupRequest( # 创建添加服务器到服务器组的请求
  94. server_group_id=config.alb_config['server_group_id'], # 服务器组ID
  95. servers=servers # 服务器列表
  96. )
  97. runtime = util_models.RuntimeOptions() # 创建运行时选项
  98. client.add_servers_to_server_group_with_options(add_servers_to_server_group_request, runtime) # 将机器挂载到ALB服务器组中
  99. except Exception as e:
  100. logging.error(f"An error occurred: {e}")
  101. sys.exit(1) # 退出程序并返回错误状态码
  102. @staticmethod
  103. def main(args: List[str]) -> None:
  104. try:
  105. ecs_client = Sample.create_ecs_client() # 创建ECS客户端
  106. alb_client = Sample.create_alb_client() # 创建ALB客户端
  107. amount = int(args[0]) if len(args) > 0 else 1 # 从命令行参数获取amount值,如果没有传入则默认为1
  108. instance_ids = Sample.create_ecs_instance(ecs_client, amount) # 创建ECS实例并获取实例ID列表
  109. asyncio.run(Sample.start_services_and_health_check(ecs_client, alb_client, instance_ids)) # 使用asyncio运行启动服务和异步探活
  110. except Exception as e:
  111. logging.error(f"An error occurred: {e}")
  112. sys.exit(1) # 退出程序并返回错误状态码
  113. if __name__ == '__main__':
  114. Sample.main(sys.argv[1:]) # 调用main方法,传递命令行参数