All Products
Search
Document Center

Bind SLB instances to container groups

Last Updated: Aug 14, 2019

This example uses the Elastic Container Instance (ECI) API.

Steps:

    1. Create a container group including a container, such as a NGINX container that uses the default port 80. Then, bind a public Server Load Balancer (SLB) instance to the container group to provide external users with the NGINX service.
    1. Query the ENI ID in the container group.
    1. Create an SLB instance and specify the instance type. By default, a shared SLB instance will be created, which cannot be bound to an ENI. Then, run the SLB instance.
    1. Create a TCP listener.
    1. Add a backend server to the SLB instance and set the server type to ENI. The default type is ECS.
    1. Start the TCP listener.
    1. View the health of the SLB instance.
  1. # -*- coding: utf-8 -*-
  2. #! /usr/bin/python
  3. import httplib
  4. import json
  5. import urllib
  6. import uuid
  7. import time
  8. import hmac
  9. from hashlib import sha1
  10. import base64
  11. import sys
  12. HOST = 'eci.aliyuncs.com'
  13. HOST_SLB = 'slb.aliyuncs.com'
  14. PORT = 80
  15. AK_ID = 'xx'
  16. AK_SECRET = 'xx'
  17. def generateParams(param):
  18. parameters = {}
  19. for k in param:
  20. parameters[k] = param[k]
  21. def call(params):
  22. timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
  23. parameters = {
  24. 'Format': 'json',
  25. 'Version': '2018-08-08',
  26. 'Product': 'Eci',
  27. 'AccessKeyId': AK_ID,
  28. 'SignatureVersion': '1.0',
  29. 'SignatureMethod': 'HMAC-SHA1',
  30. 'SignatureNonce': str(uuid.uuid1()),
  31. 'Timestamp': timestamp,
  32. }
  33. for k in params:
  34. parameters[k] = params[k]
  35. signature = sign(AK_SECRET, parameters)
  36. parameters['Signature'] = signature
  37. url = "/?" + urllib.urlencode(parameters)
  38. #print url
  39. connection = httplib.HTTPConnection(HOST, PORT, 30)
  40. connection.connect()
  41. header = {
  42. 'Content-type': 'application/x-www-form-urlencoded',
  43. "Cache-Control": "no-cache",
  44. "Connection": "Keep-Alive",
  45. }
  46. connection.request('POST', url, body='', headers=header)
  47. response = connection.getresponse()
  48. result = response.read()
  49. if response.status == 200:
  50. return result
  51. else:
  52. print response.status
  53. print result
  54. exit(-1)
  55. def call_slb(params):
  56. timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
  57. parameters = {
  58. 'Format': 'json',
  59. 'Version': '2014-05-15',
  60. 'AccessKeyId': AK_ID,
  61. 'SignatureVersion': '1.0',
  62. 'SignatureMethod': 'HMAC-SHA1',
  63. 'SignatureNonce': str(uuid.uuid1()),
  64. 'Timestamp': timestamp,
  65. }
  66. for k in params:
  67. parameters[k] = params[k]
  68. signature = sign(AK_SECRET, parameters)
  69. parameters['Signature'] = signature
  70. url = "/?" + urllib.urlencode(parameters)
  71. #print url
  72. connection = httplib.HTTPConnection(HOST_SLB, PORT, 30)
  73. connection.connect()
  74. header = {
  75. 'Content-type': 'application/x-www-form-urlencoded',
  76. "Cache-Control": "no-cache",
  77. "Connection": "Keep-Alive",
  78. }
  79. connection.request('POST', url, body='', headers=header)
  80. response = connection.getresponse()
  81. result = response.read()
  82. if response.status == 200:
  83. return result
  84. else:
  85. print response.status
  86. print result
  87. exit(-1)
  88. def sign(accessKeySecret, parameters):
  89. sortedParameters = sorted(parameters.items(), key=lambda parameters: parameters[0])
  90. canonicalizedQueryString = ''
  91. for (k, v) in sortedParameters:
  92. canonicalizedQueryString += '&' + percent_encode(k) + '=' + percent_encode(v)
  93. stringToSign = 'POST&%2F&' + percent_encode(canonicalizedQueryString[1:])
  94. h = hmac.new(accessKeySecret + "&", stringToSign, sha1)
  95. signature = base64.encodestring(h.digest()).strip()
  96. return signature
  97. def percent_encode(encodeStr):
  98. encodeStr = str(encodeStr)
  99. res = urllib.quote(encodeStr.decode('UTF-8').encode('utf8'), '')
  100. res = res.replace('+', '%20')
  101. res = res.replace('*', '%2A')
  102. res = res.replace('%7E', '~')
  103. return res
  104. def CreateContainerGroup():
  105. params = {
  106. 'Action': 'CreateContainerGroup',
  107. 'RegionId': 'cn-hangzhou',
  108. 'ZoneId': 'cn-hangzhou-g',
  109. 'SecurityGroupId': 'sg-bp11zjwu3eumpw32memr',
  110. 'VSwitchId': 'vsw-bp1a6dake404nwul5yoec',
  111. #'EipInstanceId':'eip-bp150letqu75gqbhy2cq9',
  112. 'ContainerGroupName':'test-container-group',
  113. 'RestartPolicy':'Always',
  114. #'Cpu': 0.5,
  115. 'Memory': 1,
  116. 'Container.1.Image': 'nginx',
  117. 'Container.1.Name': 'nginx',
  118. 'Container.1.Cpu': 0.25,
  119. 'Container.1.Memory': 0.5,
  120. 'Container.1.ImagePullPolicy': 'Always',
  121. }
  122. ret = call(params)
  123. print ret
  124. return json.loads(ret)['ContainerGroupId']
  125. def DescribeContainerGroup(containerGroupId):
  126. print json.dumps(containerGroupId)
  127. params = {
  128. 'Action': 'DescribeContainerGroups',
  129. 'RegionId': 'cn-hangzhou',
  130. 'ContainerGroupIds': json.dumps(containerGroupId),
  131. #'Status':'running',
  132. }
  133. ret = call(params)
  134. return ret
  135. def DescribeENI(containerGroupId):
  136. params = {
  137. 'Action': 'DescribeContainerGroups',
  138. 'RegionId': 'cn-hangzhou',
  139. 'ContainerGroupIds': json.dumps(containerGroupId),
  140. }
  141. response = call(params)
  142. response_json = json.loads(response)
  143. return response_json['ContainerGroups'][0]['EniInstanceId']
  144. def CreateLoadBalancer():
  145. params = {
  146. 'Action': 'CreateLoadBalancer',
  147. 'RegionId': 'cn-hangzhou',
  148. 'MasterZoneId': 'cn-hangzhou-g',
  149. # You must specify the SLB instance type. Otherwise, a shared instance will be created, which cannot be bound to the ENI.
  150. 'LoadBalancerSpec': 'slb.s1.small',
  151. }
  152. ret = call_slb(params)
  153. print ret
  154. return json.loads(ret)['LoadBalancerId']
  155. def SetLoadBalancerStatus(slb_name):
  156. params = {
  157. 'Action': 'SetLoadBalancerStatus',
  158. 'RegionId': 'cn-hangzhou',
  159. 'LoadBalancerStatus': 'active',
  160. 'LoadBalancerId': slb_name
  161. }
  162. ret = call_slb(params)
  163. print ret
  164. def CreateLoadBalancerHTTPListener(slb_name):
  165. params = {
  166. 'Action': 'CreateLoadBalancerHTTPListener',
  167. 'RegionId': 'cn-hangzhou',
  168. 'HealthCheck': 'on',
  169. 'ListenerPort': '80',
  170. 'StickySession': 'off',
  171. 'LoadBalancerId': slb_name,
  172. }
  173. ret = call_slb(params)
  174. print ret
  175. def CreateLoadBalancerTCPListener(slb_name):
  176. params = {
  177. 'Action': 'CreateLoadBalancerTCPListener',
  178. 'RegionId': 'cn-hangzhou',
  179. 'Bandwidth': '-1',
  180. 'ListenerPort': '80',
  181. 'LoadBalancerId': slb_name,
  182. 'BackendServerPort': '80',
  183. }
  184. ret = call_slb(params)
  185. print ret
  186. def StartLoadBalancerListener(slb_name):
  187. params = {
  188. 'Action': 'StartLoadBalancerListener',
  189. 'RegionId': 'cn-hangzhou',
  190. 'ListenerPort': '80',
  191. 'LoadBalancerId': slb_name,
  192. }
  193. ret = call_slb(params)
  194. print ret
  195. def AddBackendServers(eni_name, slb_name):
  196. backendServer = [{'ServerId':eni_name,'Weight':'100','Type':'eni'}]
  197. params = {
  198. 'Action': 'AddBackendServers',
  199. 'LoadBalancerId': slb_name,
  200. 'BackendServers': json.dumps(backendServer),
  201. }
  202. ret = call_slb(params)
  203. print ret
  204. def DescribeHealthStatus(slb_name):
  205. params = {
  206. 'Action': 'DescribeHealthStatus',
  207. 'RegionId': 'cn-hangzhou',
  208. 'ListenerPort': '80',
  209. 'LoadBalancerId': slb_name,
  210. }
  211. ret = call_slb(params)
  212. print ret
  213. if __name__ == '__main__':
  214. start = time.time()
  215. eci_name = CreateContainerGroup()
  216. print eci_name
  217. #eci_name = sys.argv[1]
  218. #print json.dumps(json.loads(DescribeContainerGroup([eci_name])), sort_keys=True, indent=4, separators=(', ', ': '))
  219. #wait eci started and eni status becomes available
  220. time.sleep(60)
  221. eni_name = DescribeENI([eci_name])
  222. print eni_name
  223. slb_name = CreateLoadBalancer()
  224. print "create loadbalancer success"
  225. print slb_name
  226. SetLoadBalancerStatus(slb_name)
  227. print "acitve loadbalancer success"
  228. #CreateLoadBalancerHTTPListener()
  229. #slb_name = 'lb-bp134nun9rb5s75c0qx09'
  230. #eni_name = 'eni-bp106nozdtcsf69tw05x'
  231. CreateLoadBalancerTCPListener(slb_name)
  232. print "create loadbalancer tcp listener success"
  233. AddBackendServers(eni_name, slb_name)
  234. print "add backendservers success"
  235. StartLoadBalancerListener(slb_name)
  236. print "start loadbalancer success"
  237. #wait slb listener start completely
  238. time.sleep(60)
  239. DescribeHealthStatus(slb_name)
  240. elapsed = (time.time() - start)
  241. print "Time used: %f" % elapsed

The response to the preceding request is as follows:

  1. {"ContainerGroupId":"eci-bp1h2ttatlv113w95klf","RequestId":"FAE9D0EA-EFE3-4E86-BF38-E56A9FA655AF"}
  2. eci-bp1h2ttatlv113w95klf
  3. eni-bp11vjc9gmm7qrjokv3z
  4. {"NetworkType":"classic","LoadBalancerName":"auto_named_slb","Address":"47.110.117.231","ResourceGroupId":"rg-acfmzyjxiiwddfy","RequestId":"DBBEFC62-2FD1-4749-A2C9-1AE683D2F798","AddressIPVersion":"ipv4","LoadBalancerId":"lb-bp1tseya0253zyjuvikkp","VSwitchId":"","VpcId":""}
  5. create loadbalancer success
  6. lb-bp1tseya0253zyjuvikkp
  7. {"RequestId":"20C30B48-75BC-472A-9542-82EB0783DACF"}
  8. acitve loadbalancer success
  9. {"RequestId":"057781AC-BAE3-4451-869E-819B5ACBBABE"}
  10. create loadbalancer tcp listener success
  11. {"BackendServers":{"BackendServer":[{"ServerId":"eni-bp11vjc9gmm7qrjokv3z","Weight":100,"Type":"eni","VpcId":"vpc-bp1smg2dl8y0za4hongzd"}]},"RequestId":"5C3AF0D3-86CC-428C-9DE2-0D14361F8FCF","LoadBalancerId":"lb-bp1tseya0253zyjuvikkp"}
  12. add backendservers success
  13. {"RequestId":"05CC4273-56E4-45A5-BBBF-EA0EB9782464"}
  14. start loadbalancer success
  15. {"BackendServers":{"BackendServer":[{"ServerHealthStatus":"normal","ServerId":"eni-bp11vjc9gmm7qrjokv3z","Port":80,"ListenerPort":80}]},"RequestId":"77E3E79D-4617-4007-89C0-4BABDC00FFE8"}
  16. Time used: 127.062913

Enter the public IP address of the SLB instance in the address bar of your web browser.

  1. 47.110.117.231

The NGINX page is displayed. You can create multiple container groups, and add multiple backend servers to the SLB instance and set weights for the servers to implement load balancing.

Possible issues:

  1. The AddBackendServers operation does not support the specified ENI status.

{“RequestId”:”80AE78B1-2961-418A-A951-DA0BC293B677”,”HostId”:”slb.aliyuncs.com”,”Code”:”BackendServer.InvalidEniStatus”,”Message”:”The specified ENI status is not supported.”}

This is because the ENI is not ready. Therefore, wait until it is ready.

  1. The AddBackendServers operation does not support the server type of ENI.

{“RequestId”:”66BBDFFB-4E8F-4C65-8F7C-59C43AAA9B42”,”HostId”:”slb.aliyuncs.com”,”Code”:”LBNotSupportENI”,”Message”:”The loadbalancer does not support backend servers of eni type.”}

This is because the SLB instance is a shared instance, which cannot be bound to the ENI. To prevent this error, you must specify another instance type when creating the SLB instance, as described in the preceding step.

  1. 'LoadBalancerSpec': 'slb.s1.small'