rov-server-update.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #!/bin/env python
  2. # coding=utf-8
  3. import logging
  4. import time
  5. import docker
  6. import sys
  7. import requests
  8. import json
  9. import queue
  10. import threading
  11. from aliyunsdkcore import client
  12. from aliyunsdkecs.request.v20140526.DescribeNetworkInterfacesRequest import DescribeNetworkInterfacesRequest
  13. from aliyunsdkcore.request import CommonRequest
  14. from aliyunsdkslb.request.v20140515.DescribeLoadBalancerAttributeRequest import DescribeLoadBalancerAttributeRequest
  15. from concurrent.futures import ThreadPoolExecutor
  16. logging.basicConfig(level=logging.INFO,
  17. format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
  18. datefmt='%a, %d %b %Y %H:%M:%S')
  19. # ##### 修改负载均衡权限
  20. AccessKey = 'LTAIuPbTPL3LDDKN'
  21. AccessSecret = 'ORcNedKwWuwVtcq4IRFtUDZgS0b1le'
  22. RegionId = 'cn-hangzhou'
  23. clt = client.AcsClient(AccessKey, AccessSecret, RegionId)
  24. slb_id_1 = 'lb-bp1werfophtsjzfr76njm'
  25. def getInstanceId(slb_id):
  26. """获取slb下所有服务器信息"""
  27. request = DescribeLoadBalancerAttributeRequest()
  28. request.set_accept_format('json')
  29. request.set_LoadBalancerId(slb_id)
  30. response = clt.do_action_with_exception(request)
  31. return json.loads(response)
  32. def setWeight(slb_id, instance_id, weight):
  33. """
  34. 设置slb权重
  35. :param slb_id: slb_id
  36. :param instance_id: 服务器id
  37. :param weight: 权重值
  38. :return: None
  39. """
  40. BackendServers = [{"ServerId": instance_id, "Weight": weight}]
  41. request = CommonRequest()
  42. request.set_accept_format('json')
  43. request.set_domain('slb.aliyuncs.com')
  44. request.set_version('2014-05-15')
  45. request.set_method('POST')
  46. request.set_action_name('SetBackendServers')
  47. request.add_query_param('BackendServers', BackendServers)
  48. request.add_query_param('LoadBalancerId', slb_id)
  49. try:
  50. response = clt.do_action_with_exception(request)
  51. except Exception as e:
  52. logging.error(e)
  53. def set_weight_for_more(slb_id, instance_id_list, weight):
  54. """
  55. 同时设置多台服务器的slb权重,权重一样
  56. :param slb_id: slb_id
  57. :param instance_id_list: 服务器id list
  58. :param weight: 权重值
  59. :return: None
  60. """
  61. BackendServers = [{"ServerId": instance_id, "Weight": weight} for instance_id in instance_id_list]
  62. request = CommonRequest()
  63. request.set_accept_format('json')
  64. request.set_domain('slb.aliyuncs.com')
  65. request.set_version('2014-05-15')
  66. request.set_method('POST')
  67. request.set_action_name('SetBackendServers')
  68. request.add_query_param('BackendServers', BackendServers)
  69. request.add_query_param('LoadBalancerId', slb_id)
  70. try:
  71. response = clt.do_action_with_exception(request)
  72. except Exception as e:
  73. logging.error(e)
  74. def getIpadd(instance_id):
  75. """获取实例IP地址"""
  76. request = DescribeNetworkInterfacesRequest()
  77. request.set_accept_format('json')
  78. request.set_InstanceId(instance_id)
  79. response = clt.do_action_with_exception(request)
  80. request_content = json.loads(response)
  81. IpAddr = request_content['NetworkInterfaceSets']['NetworkInterfaceSet'][0]['PrivateIpAddress']
  82. return IpAddr
  83. def checkHealth(ipadd):
  84. """健康检查"""
  85. while True:
  86. health_url = 'http://%s:5001/healthcheck' %(ipadd)
  87. header = {"Content-Type": "application/json"}
  88. try:
  89. health_code = requests.get(health_url).status_code
  90. except Exception as e:
  91. continue
  92. if health_code == 200:
  93. return False
  94. def setInstanceWeightProcess(instance_id):
  95. """服务更新完之后逐步修改服务器的权重值"""
  96. # 直接加载100会出现502。权重值每次增加20,每5s修改一次
  97. for i in range(1, 6):
  98. weight = i * 20
  99. setWeight(slb_id_1, instance_id, weight)
  100. time.sleep(1)
  101. def update():
  102. """更新服务"""
  103. time.sleep(10)
  104. global success_count, finished_instance_id_list
  105. apps = 'rov-server'
  106. version = sys.argv[1]
  107. registry = 'registry-vpc.cn-hangzhou.aliyuncs.com/stuuudy/rov-server:{}'.format(version)
  108. while not q2.empty():
  109. instance_id = q2.get()
  110. ipadd = getIpadd(instance_id)
  111. logging.info(f"服务器信息:{instance_id}/{ipadd}")
  112. client = docker.DockerClient(base_url=f'tcp://{ipadd}:2375', timeout=60)
  113. try:
  114. # 更新前移除旧的容器
  115. id = client.containers.get(apps)
  116. id.remove(force=True)
  117. except Exception as e:
  118. print("容器不存在或者无法删除当前容器")
  119. try:
  120. # 更新前删除旧的镜像
  121. images = client.images.list(all)
  122. for i in range(len(images)):
  123. if images[i]:
  124. client.images.remove(force=True, image=images[i].tags[0])
  125. time.sleep(2)
  126. # images = client.images.get(registry)
  127. # client.images.remove(force=True, image=registry)
  128. except Exception as e:
  129. print(e)
  130. print("镜像不存在,无法获取到镜像ID")
  131. sys.exit(0)
  132. try:
  133. # 登录镜像仓库
  134. client.login(username='stuuudys', password='Qingqu@2019', registry='registry-vpc.cn-hangzhou.aliyuncs.com')
  135. # 启动一个容器
  136. client.containers.run(registry, detach=True, cap_add='SYS_PTRACE', network_mode='host', name=apps,
  137. volumes={'/datalog/': {'bind': '/datalog/', 'mode': 'rw'}})
  138. checkHealth(ipadd)
  139. print(f"{ipadd}: 权重修改中......")
  140. # 修改权重
  141. setInstanceWeightProcess(instance_id)
  142. success_count = success_count + 1
  143. finished_instance_id_list.append(instance_id)
  144. print(f"更新进度: {success_count}/{total}")
  145. except Exception as e:
  146. raise e
  147. sys.exit() # 容器启动失败立即退出更新
  148. class MyThread(threading.Thread):
  149. def __init__(self, func):
  150. threading.Thread.__init__(self)
  151. self.func = func
  152. def run(self):
  153. self.func()
  154. def update_sever(instance_id):
  155. """更新服务"""
  156. # time.sleep(20)
  157. # print(slb_id_1, instance_id)
  158. # 设置slb权重为0
  159. setWeight(slb_id_1, instance_id, 0)
  160. # 等待10s,处理剩余请求
  161. time.sleep(10)
  162. apps = 'rov-server'
  163. version = sys.argv[1]
  164. registry = f'registry-vpc.cn-hangzhou.aliyuncs.com/stuuudy/rov-server:{version}'
  165. ipadd = getIpadd(instance_id)
  166. logging.info(f"服务器信息:{instance_id}/{ipadd}")
  167. client = docker.DockerClient(base_url=f'tcp://{ipadd}:2375', timeout=60)
  168. try:
  169. # 更新前移除旧的容器
  170. id = client.containers.get(apps)
  171. id.remove(force=True)
  172. except Exception as e:
  173. print("容器不存在或者无法删除当前容器")
  174. try:
  175. # 更新前删除旧的镜像
  176. images = client.images.list(all)
  177. for i in range(len(images)):
  178. if images[i]:
  179. client.images.remove(force=True, image=images[i].tags[0])
  180. time.sleep(2)
  181. # images = client.images.get(registry)
  182. # client.images.remove(force=True, image=registry)
  183. except Exception as e:
  184. print(e)
  185. print("镜像不存在,无法获取到镜像ID")
  186. sys.exit(0)
  187. try:
  188. # 登录镜像仓库
  189. client.login(username='stuuudys', password='Qingqu@2019', registry='registry-vpc.cn-hangzhou.aliyuncs.com')
  190. # 启动一个容器
  191. client.containers.run(registry, detach=True, cap_add='SYS_PTRACE', network_mode='host', name=apps,
  192. volumes={'/datalog/': {'bind': '/datalog/', 'mode': 'rw'}})
  193. checkHealth(ipadd)
  194. print(f"{ipadd}: 权重修改中......")
  195. # 修改权重
  196. setInstanceWeightProcess(instance_id)
  197. global finished_instance_id_list
  198. finished_instance_id_list.append(instance_id)
  199. except Exception as e:
  200. raise e
  201. sys.exit() # 容器启动失败立即退出更新
  202. if __name__ == '__main__':
  203. # 更新完成计数
  204. success_count = 0
  205. threads = []
  206. # 线程数
  207. thread_num = 2
  208. # 获取slb下所有服务器信息
  209. res = getInstanceId(slb_id_1)
  210. # slb下服务器总数
  211. total = len(res["BackendServers"]["BackendServer"])
  212. q1 = queue.Queue()
  213. q2 = queue.Queue()
  214. # 获取slb下所有服务器的 instance_id
  215. if res["BackendServers"]["BackendServer"]:
  216. for i in range((len(res["BackendServers"]["BackendServer"]))):
  217. instance_id = res["BackendServers"]["BackendServer"][i]["ServerId"]
  218. q1.put(instance_id)
  219. while not q1.empty():
  220. # 摘流量
  221. for i in range(thread_num):
  222. if q1.empty():
  223. break
  224. instance_id = q1.get()
  225. # 设置slb权重为0
  226. setWeight(slb_id_1, instance_id, 0)
  227. q2.put(instance_id)
  228. time.sleep(1)
  229. # 挂流量
  230. finished_instance_id_list = []
  231. for i in range(thread_num):
  232. # 开启线程
  233. thread = MyThread(update)
  234. thread.start()
  235. threads.append(thread)
  236. for thread in threads:
  237. thread.join()
  238. # 权重补充(一秒内同时请求两个服务器修改权重,可能会有一个失败)
  239. print(finished_instance_id_list)
  240. set_weight_for_more(slb_id=slb_id_1, instance_id_list=finished_instance_id_list, weight=100)
  241. # thread_pool = ThreadPoolExecutor(max_workers=thread_num)
  242. # 获取slb下所有服务器的 instance_id
  243. # if res["BackendServers"]["BackendServer"]:
  244. # for i in range((len(res["BackendServers"]["BackendServer"]))):
  245. # instance_id = res["BackendServers"]["BackendServer"][i]["ServerId"]
  246. # thread_pool.submit(update_sever, instance_id)
  247. # thread_pool.shutdown(wait=True)