降低IT成本:OpenStack自动回收与镜像最佳实践

技术背景

本文所介绍的解决方案应用于 OpenStack 云管理平台,使用 Python 编程语言实现必要的功能,利用邮件服务器和 Web 服务器完成用户自服务,作为自动回收机制的补充。

自动回收的价值

提高 IT 资源的利用率

通过自动回收 OpenStack 中的实例和镜像,避免存在和积累闲置的实例和镜像,使得 IT 资源(CPU、内存、存储、网络等)保持有效的使用状态,最大程度地提高 IT 资源利用率,保护用户的 IT 投资。

提高 Cloud 上的系统性能

对于一个特定的 Cloud 平台,它的最大负载性能是有限的,而闲置的实例和镜像仍会占用部分这有限的性能,这在一定程度上会影响同一平台上其它系统的性能。以存储 I/O 性能为例,越是少量的系统的进行并发读写,对其中单个系统而言所拥有的性能越是良好。

节省 IT 成本

启用自动回收可以避免用户在 IT 投资上的无谓的浪费,无须盲目地增加投资而一样可以达到负载的需求。

如何实现自动回收

自动回收的条件和前提

  • 使用 OpenStack 云管理平台
  • 可以利用一个现有的邮件服务器
  • OpenStack 用户需要有电子邮件地址信息
  • OpenStack 数据库中记录有对实例和镜像的最后修改时间,对此值的修改不应影响其它任何功能。

自动回收机制的设计

自动回收通过 web service 实现检测实例和镜像的状态,完成与相关用户的交互,最终达到回收的作用,工作原理如图1所示。

图 1. 自动回收工作原理图

降低IT成本:OpenStack自动回收与镜像最佳实践

本解决方案中通过 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 平台上自动回收实例及镜像的功能即可实现。

应用的增强与扩展

相关推荐