技术背景
本文所介绍的解决方案应用于 OpenStack 云管理平台,使用 Python 编程语言实现必要的功能,利用邮件服务器和 Web 服务器完成用户自服务,作为自动回收机制的补充。
自动回收的价值
提高 IT 资源的利用率
通过自动回收 OpenStack 中的实例和镜像,避免存在和积累闲置的实例和镜像,使得 IT 资源(CPU、内存、存储、网络等)保持有效的使用状态,最大程度地提高 IT 资源利用率,保护用户的 IT 投资。
提高 Cloud 上的系统性能
对于一个特定的 Cloud 平台,它的最大负载性能是有限的,而闲置的实例和镜像仍会占用部分这有限的性能,这在一定程度上会影响同一平台上其它系统的性能。以存储 I/O 性能为例,越是少量的系统的进行并发读写,对其中单个系统而言所拥有的性能越是良好。
节省 IT 成本
启用自动回收可以避免用户在 IT 投资上的无谓的浪费,无须盲目地增加投资而一样可以达到负载的需求。
如何实现自动回收
自动回收的条件和前提
- 使用 OpenStack 云管理平台
- 可以利用一个现有的邮件服务器
- OpenStack 用户需要有电子邮件地址信息
- OpenStack 数据库中记录有对实例和镜像的最后修改时间,对此值的修改不应影响其它任何功能。
自动回收机制的设计
自动回收通过 web service 实现检测实例和镜像的状态,完成与相关用户的交互,最终达到回收的作用,工作原理如图1所示。
图 1. 自动回收工作原理图
本解决方案中通过 Jenkins 每天触发并完成一次回收工作,实际应用中可根据需要采用不同的触发方式和频率。
在 OpenStack 的数据库中记录资源信息及所有者信息,因此可以准确地与资源对应的所有者通过电子邮件进行交互。
通 过比较资源的最后修改日期和当前日期,可以识别出将过期或已过期(周期可配置,详见清单1)的资源:对于已过期的资源,将执行自动清除并通知所有者;对于 将过期的资源,将提醒所有者进行延期或主动清除操作。操作方式仅需点击一次邮件中的链接。若直至最后一次通知,所有者仍未进行任何操作响应,意味着该资源 将正式过期并被自动清除。
自动回收的具体实现
首先,对于自动回收服务是可以根据不同的环境和需求进行配置的,如清单1所示。当自动回收服务(见下文中 Python 实现的 web service)启动时,将读取该配置使得回收工作能正常进行。
清单 1. 定义自动回收配置
- [SERVICE]
- port=set me
- [WHITELIST]
- users=set me or keep empty
- instances=set me or keep empty
- images=set me or keep empty
- [LIFETIME]
- keep_days=set me
- remind_days=set me
- [DATABASE]
- host=set me
- nova_user=set me
- nova_pwd=set me
- keystone_user=set me
- keystone_pwd=set me
- [CLOUD]
- OS_USERNAME=set me
- OS_PASSWORD=set me
- OS_TENANT_NAME=set me
- OS_AUTH_URL=set me
- [EMAIL]
- smtp_server=set me
- smtp_user=set me
- smtp_pwd=set me
[SERVICE]: 自动回收 web service 的相关配置
- Port: web service 的服务端口
[WHITELIST]: 白名单配置,用于避免某些资源被自动回收
- Users: 指定用户清单,他们的资源将被视为永不过期
- Instances: 指定实例清单,视为永不过期
- Images: 指定镜像清单,视为永不过期
[LIFETIME]: 资源的生命周期配置
- Keep_days: 资源可保持的时长,以天为单位
- Remind_days: 通知时间范围,以天为单位,指在资源生命周期最后一段时间内开始对所有者进行通知提醒
[DATABASE]: OpenStack 数据库的连接配置
- Host: 数据库服务器地址
- Nova_user: nova 数据库的用户名
- Nova_pwd: nova 数据库的用户密码
- Keystone_user: keystone 数据库的用户名
- Keystone_pwd: keystone 数据库的用户密码
[CLOUD]: OpenStack 云的管理帐号信息
- Os_auth_url: OpenStack 的授权验证服务地址
- Os_tenant_name: OpenStack 中需要进行管理的 tenant 名称
- Os_username: OpenStack 中用于管理以上 tenant 的用户名
- Os_password: OpenStack 中上述用户的密码
其次,通过运行简单的 Python 程序(见清单 2),即可启动一个 web server,也可以将该 web service 运行为 linux 系统服务(见清单 3)。
清单 2. 启动轻量 web 服务器
- if __name__ == '__main__':
- serveraddr = ('0.0.0.0', int(SERVICE_PORT))
- srvr = HTTPServer(serveraddr, RequestHandler)
- srvr.serve_forever()
清单 3. 创建 linux 系统服务
- function start()
- {
- echo "Starting OS_Recycle ..."
- daemon "python ${PY_FILE} ${CONFIG_FILE} >> ${LOG_FILE} 2>&1 &"
- sleep 2
- status
- }
在以上 web service 中,为所需要的功能实现 REST API,本解决方案中为优化用户体验,对资源的延期及回收操作同样采用 GET 响应。见清单 4。
清单 4. 定义 REST API 实现功能
- def do_GET(self):
- self._writeheaders()
- self.apiGET()
- def apiGET(self):
- path=self.path.split('/')
- if len(path) == 2 and path[1] == 'instances':
- self.wfile.write(json.dumps(self.getInstances()))
- ...
- def getInstances(self):
- #connect to nova database and keystone database to get data
- ...
- instJson=json.loads('[]')
- for inst in instances:
- for user in users:
- if user[0] == inst[1]:
- instJson.append(json.loads('{"created_at":"%s", "user_id":"%s",
- "hostname":"%s", "ip_address":"%s", "uuid":"%s",
- "user_name":"%s"}' %
- (inst[0], inst[1], inst[2], inst[4], inst[3], user[1])
- ))
- break
- return instJson
程序中对于资源及过期信息的查询操作,匀直接通过连接数据库查询实现,DB2 SQL 命令示例:
- novaSql = "SELECT char(a.created_at),a.user_id,a.hostname,a.uuid,cast(b.NETWORK_INFO as varchar(1000))
- from instances a left join INSTANCE_INFO_CACHES b on a.uuid=b.INSTANCE_UUID \
- where a.project_id = '%s' and a.deleted_at is null" % CLOUD_OS_TENANT_ID
对于资源的延期操作,即更新资源的最后修改时间为当前时间,意味着重置生命周期,DB2 SQL 命令示例:
- novaSql = "update instances set created_at=current timestamp where uuid='%s'" % uuid
而对于资源的清除操作,则需要通过调用 OpenStack 相关的 REST API 实现,见清单 5。
清单 5. 调用 OpenStack REST API 实现删除操作
- def deleteInstance(self,uuid):
- req_url = '%s/tokens' % CLOUD_OS_AUTH_URL
- resp, resp_body = httplib2.Http().request(req_url, 'POST',
- headers={'Accept':'application/json', 'Content-Type':'application/json'},
- body='{"auth": {"tenantName": "%s", "passwordCredentials": {"username": "%s", "password": "%s"}}}' %
- (CLOUD_OS_TENANT_NAME, CLOUD_OS_USERNAME, CLOUD_OS_PASSWORD)
- )
- if resp['status'] != '200':
- return False
- resp_json = json.loads(resp_body)
- token_id = resp_json['access']['token']['id']
- for service in resp_json['access']['serviceCatalog']:
- if service['name'] == 'nova':
- nova_admin_url = service['endpoints'][0]['adminURL']
- break
- if not nova_admin_url:
- return False
- resp, resp_body = httplib2.Http().request('%s/servers/%s' % (nova_admin_url, uuid), 'DELETE',
- headers={'Accept':'application/json', 'X-Auth-Project-Id':'%s' % CLOUD_OS_TENANT_NAME,
- 'X-Auth-Token':'%s' % token_id }
- )
- if resp['status'] != '204':
- return False
- return True
在资源将要过期或已被自动回收时,需要对所有者进行邮件通知,在邮件中提供必要的 link 供所有者进行操作。示例见清单 6。注意本程序中使用的是 SMTP,并且要求应用程序能够正常连接到指定的邮件服务器,而该邮件服务器亦能正常发送邮件到达资源所有者。
清单 6. 邮件通知资源所有者
- import smtplib
- from email.MIMEMultipart import MIMEMultipart
- from email.MIMEText import MIMEText
- ...
- SMTP_SERVER='set me'
- SMTP_USER='set me'
- SMTP_PWD='set me'
- msg = MIMEMultipart()
- msg["From"] = SMTP_USER
- msg["To"] = 'set me'
- msg["Subject"] = "set me"
- msg.attach(MIMEText("set me"))
- mailServer = smtplib.SMTP(SMTP_SERVER, timeout=20)
- mailServer.ehlo()
- mailServer.starttls()
- mailServer.login(SMTP_USER, SMTP_PWD)
- mailServer.sendmail(SMTP_USER, msg["To"], msg.as_string())
- mailServer.quit()
至此,OpenStack 平台上自动回收实例及镜像的功能即可实现。
应用的增强与扩展
上述应用的实现可满足大部分场景的需求,同时也存在可增强的几方面:
- 使用额外的数据库,用以跟 OpenStack 数据库同步资源信息,并记录生命周期,避免直接修改 OpenStack 的数据。
- 实现专用的邮件服务器,用于本应用与资源所有者的邮件交互,避免网络受限与安全风险。
- 包装成为 OpenStack 的可选功能,使得用户可以方便地启用该功能,而无需过多的手工配置。
- 基于上述实现及可增强的部分,自动回收可扩展到更多的应用场景:
- 可用于回收 OpenStack 中的其它类型的资源和数据,例如用户,flavor,网络等,而不仅限于实例与镜像
- 以相同的思路在平它系统平台中实现自动回收资源:即给资源配置生命周期,并跟踪资源的状态,在与所有者有自动交互的基础上实现自动回收。
原文链接:http://www.ibm.com/developerworks/cn/cloud/library/1509_hugq_openstackautocollect/