降低IT成本:OpenStack自動回收與鏡像最佳實踐
技術背景
本文所介紹的解決方案應用于 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/