OpenStack计费项目Cloudkitty系列详解
OpenStack计费项目Cloudkitty简介以及社区最新动态大家都知道云计算是一种按需付费的服务模式,OpenStack前期在计量方面走了些弯路,现在ceilometer,gnocchi,aodh,panko项目的稳步并进总算峰回路转。然而目前来看OpenStack的计费项目Cloudkitty并未柳暗花明,希望借助本文向大家介绍cloudkitty的架构,用户使用指导,开发
OpenStack计费项目
Cloudkitty简介以及社区最新动态
大家都知道云计算是一种按需付费的服务模式,OpenStack前期在计量方面走了些弯路,现在ceilometer,gnocchi,aodh,panko项目的稳步并进总算峰回路转。然而目前来看OpenStack的计费项目Cloudkitty并未柳暗花明,希望借助本文向大家介绍cloudkitty的架构,用户使用指导,开发以及社区方面的最新动态,吸引更多方面的关注,使用和社区参与。
前言
Cloudkitty主要依赖于遥测相关的项目,包括ceilometer和gnocchi,甚至是将要使用panko;计费策略和hashmap计费模型是其核心;模块插件化是其设计灵魂;接下来的三个部分内容将带您逐步探索。
第一部分:Cloudkitty架构详解
本部分为理论架构篇,将会详细介绍当前cloudkitty的整体架构,包括计费服务的对象获取(Tenant Fetcher),计费数据源的收集(Collector),计费引擎(Rating)的实现,计费费用数据的存储(Storage);另外将重点介绍hashmap计费模型。
一 计费服务对象Tenant Fetcher
Tenant Fetcher是用来获取合法的计费服务对象,即cloudkitty要知道需要对谁的资源进行计费。当前具体实现了从csv文件中获取和keystone中获取两种方式,分别对应FakeFetcher类和KeystoneFetcher类,均实现了父类的get_tenants抽象方法。所以只要继承基类BaseFetcher实现get_tenants方法,并配置tenant_fetcher后端,就能处理xls文件完成从Excel文档中获取需要计费的租户信息。
keystone是默认的获取计费租户的方式,同时支持V2和V3版本。具体逻辑是检查cloudkitty用户是否在某个tenant内并拥有rating角色。所以在使用cloudkitty时,一般对于想要计费的租户需要执行命令’keystone user-role-add --user cloudkitty --role rating --tenant demo’,将cloudkitty用户加入租户并赋予rating角色。
二 计费源数据收集Collector和统一化Transformer
单纯从计费角度来看,计费源主要有两类,一类是静态资源,比如虚拟机实例,镜像,云硬盘,浮动IP;一类是动态资源,比如网络流量。对于静态资源一旦被创建,那么它的单价就固定,只需根据其生命周期按时间长短计费即可;对于动态资源需要统计计量情况进行计算费用。这就意味着计费的数据源应该包括event和measurement两部分,但当前cloudkitty在计费数据收集方面没有加入事件分析能力。
这一步除了计费源数据的收集,还有一个十分重要的工作就是把这些数据转化为统一格式输入给计费引擎。Cloudkitty中的transformer模块将针对不同collector的不同类型的服务数据进行格式统一。这里需要特别说明的是transformer过程一般情况下分为两个阶段:第一个阶段是将资源数据通过对应的CeilometerTransformer或者GnocchiTransformer进行转换。第二阶段是使用CloudKittyFormatTransfor
collector和transformer模块分别有多种实现,collector实现了ceilometer,fake,gnocchi和 meta四种方式,transformer实现了CeilometerTransformer,GnocchiTransformer以及通用的CloudKittyFormatTransfor
每种collector的实现最终都会通过retrieve函数将归一化的数据发送给计费引擎。对于ceilometer和fake,这个retrieve函数会根据不同的服务调用get_compute,get_image,get_volume,get_network_bw_in,get_network_bw_out,get_network_floating,这六个方法就分别对应着cloudkitty的计费服务compute,image,volume,network.bw.in,network.bw.out,network.floating。而每个方法获得相关服务数据后会做transformer处理返回给计费引擎,最终计费引擎根据计费模型计算出具体费用再将费用数据存储起来便完成了整个计费流程。对于gnocchi,它的retrieve函数则有所不同,gnocchi直接使用自己的metric.get_measures和resource.search方法获得相关资源数据。这恰恰也体现了cloudkitty collector模块的插件化,并且实现上非常灵活,意味着如果想为CloudStack,Eucalyptus,OpenNebula等IaaS平台添加collector插件也是件愉快而轻松的事。
三 计费引擎Rating
Orchestrator类是cloudkitty计费引擎的具体实现,支持多线程,支持多种计费模型同时运行,并能指定优先级。在计费策略上cloudkitty采用的是周期轮询计费的方式,默认是每一小时对云环境中所需计费的资源进行费用核算,并将费用数据持久化存储起来。还有一个大周期是当月内,如果rated_data_frames表中的数据是空的时候,每次启动cloudkitty-processor就会重新计算当月内每小时的费用(这对调试cloudkitty也很有帮助)。
Cloudkitty当前的计费模型有三个,分别是noop,hashmap和pyscripts。noop模型为空,仅作为测试用;hashmap是当前cloudkitty实用价值最高,最容易使用,最接近实际案例的计费模型,后文将单独做详细介绍;pyscripts计费模型提供了使用python代码定制计费的接口,用户可以直接将含有计费逻辑的python脚本上传给cloudkitty实现定制化的计费,所以pyscripts计费模型使用门槛较高。
计费模型的设计和实现相对比较复杂,首先计费模型要具有enabled和priority属性并能设置,借助stevedore作为插件注册到cloudkitty.rating.processors命名空间内;其次要实现抽象方法process执行具体的费用计算逻辑;最后还需要借助pecan提供对外使用的Rest API接口。但是hashmap计费模型目前能完成绝大部分实际场景需求的计费工作,后文将对它做详细介绍。关于大家关心的按秒计费,需要加入event分析后才比较容易实现,这块内容将在第三部分提到,也是我接下来的主要计划。
四 费用数据的存储Storage
前面提到cloudkitty的计费引擎是周期性计算资源费用的,而这个周期可以根据实际情况修改,只要能在一个计费周期内完成所有资源的费用计算即可。对应一项资源的服务默认在一个小时的计费周期下,一个月内就会有720条的费用数据生成,如果将计费周期调得更小,云环境中的需要计费的资源更多,那么将会对费用数据的存储带来挑战,它会直接影响到数据的使用效果,因此费用数据的存储也是一个重要的环节。
Cloudkitty的storage目前支持sqlalchemy和gnocchi_hybrid两种方式存放费用数据,因为它们都是通过插件方式实现的,所以具体采用哪种可以通过配置文件指定,再通过get_storage方法获得具体storage实例,十分灵活方便。
Storage的具体实现过程包括:(1)通过抽象方法get_time_frame从存储后端中的数据来确定下一个时间范围。(2)通过append方法将费用数据记入提交缓存,期间可能会通过get_tenants函数和_dispatch函数做预处理或加工。(3)通过commit函数将费用数据写入到后端存储持久化。这个过程会做_pre_commit,_commit,_post_commit一系列的工作确保数据被可靠地存储。(4)对外提供get_total方法,返回费用情况。
sqlalchemy和gnocchi_hybrid的数据格式或者说表的结构都包括begin,end,unit,qty,res_type,rate,tenant_id和对资源描述相关的字段。实际上两种后端存储都是基于SQL实现的,所以随着时间的推移和云环境中需要计费资源的增加,费用数据的增加同样会出现之前类似ceilometer用SQL存储measurement数据带来性能瓶颈的问题。所以将费用数据存储在gnocchi中是必须的,详见https://review.openstack.org/#/c/319425/。
五 hashmap计费模型
Hashmap计费模型是cloudkitty的核心,其数据结构如下图所示,接着是hashmap计费模型中的几个元素及核心概念。
Hashmap Group:一个Group表示一组计费规则,例如你可以创建多个计费规则,将它们分成两组来分别为instance和volume计费,避免计费规则混乱。
Hashmap Service:一个Service将计费规则映射到具体的数据collector,例如compute,volume,image,network.bw.in,network.bw.out,network.floating。
Hashmap Field:一个Field通常是指某个资源元数据metadata字典中的一个字段。例如对于instance,可以指定Field为flavor,availability_zone等;对于volume可以指定Field为volume_type,availability_zone和status等。既可以为Field指定mapping类型的计费规则也能指定Threshold类型的计费规则。
Hashmap Mapping: 一个Mapping是指某个最终的计费规则,mapping这类计费规则可以为某个服务指定价格,也可以为Field指定价格。例如你可以指定compute服务的基础价格Flat=10$,这会适用于所有的云主机;同时你也能具体指定flavor name,value=m1.tiny,Rate=1.2,则flavor为m1.tiny的云主机价格就为10$*1.2=12$,value=m1.medium,Flat=20$,则flavor为m1.medium的云主机价格就是20$。再例如指定volume的基础单价为2$,选定Field为volume_type,SATA类型打九五折value=sata,Rate=0.95,则sata盘的单价就是2$*0.95=1.9$;SAS为标准云硬盘不打折,则不用设定,单价依然为2$;SSD为高速硬盘应加价0.2倍value=ssd,Rate=1.2,则ssd盘的单价就是2$*1.2=2.4$。
Hashmap Threshold:Threshold是另外一种最终计费规则,threshold这类计费规则更适用于基于level的Rate价格。例如云硬盘基础单价为2$(可用mapping设定),如果用户购买超过50GB,可以打九折Level=50,Rate=0.9,此时单价为2$*0.9=1.8$;超过100GB打八折Level=100,Rate=0.8,此时单价为2$*0.8=1.6$。
通过以上介绍和具体举例,说明hashmap计费模型具有较广泛的使用范围,能满足实际需求中较复杂的计费场景。总结一下hashmap计费模型,它可以直接为资源或者服务设定价格(Flat或者Rate);也能根据资源的Field设定mapping和threshold类型的价格(Flat或者Rate);还能根据资源某字段的Level设定价格(Rate为主)。
第二部分:动手实践
本部分为动手实践篇,主要包括部署和使用cloudkitty。在部署方面分别采用devstack部署,package方式部署和源码开发环境搭建三种方式来满足不同用户和开发者的需求。通过本部分介绍,大家将会对cloudkitty有感性认识,并且能使开发者快速融入。
一 使用devstack部署
(1)准备
[root@zhangguoqing-dev ~]# git clone https://review.openstack.org/openstack-dev/devstack
使用tools/create-stack-user.sh脚本创建stack用户,并切su到stack的用户空间
[stack@zhangguoqing-dev ~]$ cd devstack && cp samples/local.conf ./local.conf
(2)修改配置文件local.conf使用trystack源,参考如下:
[[local|localrc]]
GIT_BASE=http://git.trystack.cn
NOVNC_REPO=http://git.trystack.cn/kanaka/noVNC.git
SPICE_REPO=http://git.trystack.cn/git/spice/spice-html5.git
HOST_IP=172.16.40.152
ADMIN_PASSWORD=password
DATABASE_PASSWORD=password
RABBIT_PASSWORD=password
SERVICE_PASSWORD=password
LOGFILE=$DEST/logs/stack.sh.log
LOGDAYS=2
SWIFT_HASH=66a3d6b56c1f479c8b4e70ab
SWIFT_REPLICAS=1
SWIFT_DATA_DIR=$DEST/data
enable_service horizon
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer.git
enable_plugin cloudkitty https://git.openstack.org/openstack/cloudkitty.git
enable_service ck-api ck-proc
(3)执行部署
[stack@zhangguoqing-dev devstack]$ ./stack.sh
二 Package方式部署(for mitaka)
(1)准备openstack mitaka源并安装相应的packages
# yum install centos-release-openstack-mitaka
# yum upgrade
# yum install openstack-cloudkitty-api openstack-cloudkitty-processor python-cloudkittyclient
(2)准备cloudkitty运行所依赖的环境
创建cloudkitty数据库
MariaDB [(none)]> CREATE DATABASE cloudkitty;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'localhost' IDENTIFIED BY 'password';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'%' IDENTIFIED BY 'password';
在keystone中创建相应的用户和endpoint
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-create --name cloudkitty --pass password
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role admin --tenant services
[root@zhangguoqing-dev ~(keystone_admin)]# keystone service-create --name cloudKitty --type rating --description "OpenStack Rating Service"
[root@zhangguoqing-dev ~(keystone_admin)]# keystone endpoint-create --service-id
--internalurl http://172.16.40.152:8889 \
--region RegionOne
新建rating角色,并对demo租户进行计费
[root@zhangguoqing-dev ~(keystone_admin)]# keystone role-create --name rating
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role rating --tenant demo
(3)配置/etc/cloudkitty/cloudkitty.conf,参考如下
[DEFAULT]
debug = True
log_dir = /var/log/cloudkitty
[collect]
period = 3600
services = compute,image,volume,network.bw.in,network.bw.out,network.floating
[database]
connection=mysql+pymysql://cloudkitty:password@172.16.40.152/cloudkitty
[keystone_authtoken]
auth_uri = http://172.16.40.152:5000/v2.0
identity_uri=http://172.16.40.152:35357
admin_password=password
admin_user=cloudkitty
admin_tenant_name=services
[auth]
auth_type = password
auth_url = http://172.16.40.152:5000
username = cloudkitty
user_domain_id = default
password = password
project_domain_id = default
project_name = services
[keystone_fetcher]
auth_section = auth
[ceilometer_collector]
auth_section = auth
[oslo_messaging_rabbit]
amqp_durable_queues=False
rabbit_hosts=172.16.40.152:5672
rabbit_userid = guest
rabbit_password = guest
[storage]
backend = sqlalchemy
[tenant_fetcher]
backend = keystone
(4)初始化和开启服务
初始化数据库
初始化后端存储
# systemctl enable openstack-cloudkitty-api openstack-cloudkitty-processor
# systemctl start openstack-cloudkitty-api openstack-cloudkitty-processor
(5)源码安装cloudkitty-dashboard
Mitaka版本通过命令yum search all cloudkitty没有发现cloudkitty-dashboard的安装包,现在从源码安装cloudkitty的dashboard。
获取源码并安装
# git clone https://git.openstack.org/openstack/cloudkitty-dashboard
# cd cloudkitty-dashboard
# git checkout -b stable/mitaka origin/stable/mitaka
# python setup.py install
在horizon中开启cloudkitty-dashboard
# PY_PACKAGES_PATH=`pip --version | cut -d' ' -f4`
# ln -sf $PY_PACKAGES_PATH/cloudkittydashboard/enabled/_[0-9]*.py \
/usr/share/openstack-dashboard/openstack_dashboard/enabled/
# systemctl restart httpd
(6)界面预览
三 开发环境搭建
如果觉得使用devstack开发是件麻烦的事,那么本节将带您搭建一个hand-in的cloudkitty开发环境(cloudkitty + cloudkitty-dashboard + python-cloudkittyclient)。
(1)准备开发环境和配置文件
# mkdir ~/cloudkitty-dev && cd ~/cloudkitty-dev
# git clone https://git.openstack.org/openstack/cloudkitty
# git clone https://git.openstack.org/openstack/cloudkitty-dashboard
# git clone https://git.openstack.org/openstack/python-cloudkittyclient
# git clone https://git.openstack.org/openstack/horizon
# cd cloudkitty/
# mkdir -p /etc/cloudkitty
# cp etc/cloudkitty/api_paste.ini /etc/cloudkitty/
# cp etc/cloudkitty/policy.json /etc/cloudkitty/
# tox -e genconfig
# cp etc/cloudkitty/cloudkitty.conf.sample /etc/cloudkitty/cloudkitty.conf
(2)准备cloudkitty运行所依赖的环境
创建cloudkitty数据库
MariaDB [(none)]> CREATE DATABASE cloudkitty;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'localhost' IDENTIFIED BY 'password';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'%' IDENTIFIED BY 'password';
在keystone中创建相应的用户和endpoint
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-create --name cloudkitty --pass password
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role admin --tenant services
[root@zhangguoqing-dev ~(keystone_admin)]# keystone service-create --name cloudKitty --type rating --description "OpenStack Rating Service"
[root@zhangguoqing-dev ~(keystone_admin)]# keystone endpoint-create --service-id
--internalurl http://172.16.40.152:8889 \
--region RegionOne
新建rating角色,并对demo租户进行计费
[root@zhangguoqing-dev ~(keystone_admin)]# keystone role-create --name rating
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role rating --tenant demo
(3)修改配置文件/etc/cloudkitty/cloudkitty.conf,参考如下
[DEFAULT]
debug = True
log_dir = /var/log/cloudkitty
[collect]
period = 3600
services = compute,image,volume,network.bw.in,network.bw.out,network.floating
[database]
connection=mysql+pymysql://cloudkitty:password@172.16.40.152/cloudkitty
[keystone_authtoken]
auth_uri = http://172.16.40.152:5000/v2.0
identity_uri=http://172.16.40.152:35357
admin_password=password
admin_user=cloudkitty
admin_tenant_name=services
[auth]
auth_type = password
auth_url = http://172.16.40.152:5000
username = cloudkitty
user_domain_id = default
password = password
project_domain_id = default
project_name = services
[keystone_fetcher]
auth_section = auth
[ceilometer_collector]
auth_section = auth
[oslo_messaging_rabbit]
amqp_durable_queues=False
rabbit_hosts=172.16.40.152:5672
rabbit_userid = guest
rabbit_password = guest
[storage]
backend = sqlalchemy
[tenant_fetcher]
backend = keystone
(4)初始化和开启服务
通过tox生成虚拟环境
# cd ~/cloudkitty-dev/cloudkitty/
# tox -e venv -- pip install pymysql
初始化数据库和后端存储
# tox -e venv -- cloudkitty-dbsync upgrade
# tox -e venv -- cloudkitty-storage-init
开启ck-api和ck-proc服务
# tox -e venv -- cloudkitty-api --config-file=/etc/cloudkitty/cloudkitty.conf
# tox -e venv -- cloudkitty-processor --config-file=/etc/cloudkitty/cloudkitty.conf
在虚拟环境中安装和使用python-cloudkittyclient
# tox -e venv -- pip install -e ../python-cloudkittyclient/
# source .tox/venv/bin/activate
(venv) # cloudkitty --help
(5)安装cloudkitty-dashboard的开发环境
创建horizon虚拟环境并把cloudkittydashboard作为模块安装进去
# cd ~/cloudkitty-dev/horizon/
# tox -e venv -- pip install -e ../cloudkitty-dashboard/
将cloudkitty-dashboard的插件文件链接到Horizon的enabled目录下面
# ln -sf
openstack_dashboard/enabled/
开启Django HTTP server,在浏览器输入IP:9000即可访问cloudkitty-dashboard相关的页面
# cp openstack_dashboard/local/local_settings.py.example
openstack_dashboard/local/local_settings.py
# tox -e venv -- python manage.py runserver 0.0.0.0:9000
四 使用演示
(1)演示场景描述
采用hashmap计费模型进行演示,计费场景设定(为了演示的方便,请忽略价格、Threshold Level等数据与真实情况的差别)的具体数据展示在下面的说明和表格中:
1.
2.
3.
4.
5.
Service | Fields | Service Mappings | Service Thresholds | Groups |
compute (flavor) | Flat 1$ Flat 2$ Flat 3$ | | | instance_flavor |
volume | | Level:1GB Level:2GB | volume_thresholds | |
network.bw.in | | flat 2$ | | network_inout |
network.bw.out | | flat 2$ | | network_inout |
network.floating | | flat 2$ | | network_inout |
注:可以尝试实现既按云硬盘类型和又按云硬盘大小分级计费规则
(2)使用admin用户,完成上述计价规则的设定
开启hashmap计费模块
创建相应的服务compute,volume,network.bw.in,network.bw.out,network.floating和instance_flavor,volume_thresholds,network_inout计费组。
根据flavor对云主机定价
根据size对云硬盘定价
对network.* 定价(network.bw.in,network.bw.out,network.floating均相同)
(3)用户demo查看当月费用情况
第三部分:社区动态
IRC : #cloudkitty on freenode
Meeting weekly: Monday at 2PM #openstack-meeting-3 (北京时间每周一晚上十点)
一 进行时
1 当前计费数据存储的后端实现了sqlalchemy和 gnocchi_hybrid两种方式,实质上都是依赖于SQL数据库。为了避免类似ceilometer计量数据存储的问题,cloudkitty的计费数据存储也将实现gnocchi原生支持。
Added native gnocchi storage driver
2 实现根据租户和用户查询费用情况的API
Get total price by tenant_id and user_id
3 对当前项目RPC机制进行代码优化
Improve the rpc module
4 对认证模块进行升级,采用keystoneauth1模块,简化配置
Migrate from keystoneclient to keystoneauth
Use keystoneauth1 to service credentials
5 devstack插件方式部署
Fix and enhance devstack plugin
6 文档更新,方便用户和吸引更多开发者加入
Update install from mitaka packages
Update the install and configure section
二 BP规划
1 实现cloudkitty-api的wsgi支持,方便云环境对计费服务的负载均衡和高可用。
https://blueprints.launchpad.net/cloudkitty/+spec/wsgi-support
2 越来越多的云主机会从云硬盘启动,那么云硬盘快照的计费支持会更强烈。
https://blueprints.launchpad.net/cloudkitty/+spec/rating-volume-snapshot
3 需要获得更准确的更多维度的计费情况,以支持billing。
https://blueprints.launchpad.net/cloudkitty/+spec/price-groupby-fields
4 使colleting和reporting支持本地时钟。
https://blueprints.launchpad.net/cloudkitty/+spec/local-time-zone-support
5取消SQL Schema Downgrade的操作。
https://blueprints.launchpad.net/cloudkitty/+spec/remove-schema-downgrades
6 集成cloudkitty到kolla中。
https://blueprints.launchpad.net/kolla/+spec/cloudkitty
三 作者展望
1 cloudkitty-dashboard的展示信息应该更直观,更易于操作。例如:
Adjust the reporting page
Show group_name rather than group_id
Show threshold's level in group details page
2 实现按秒计费。cloudkitty需要加上事件分析能力才能使计费更精确(达到秒级计费)和商用化。例如一台云主机在一个计费周期内:被stop的时间段内应该计费为0;rebuild更新了flavor,前后时间段内应该按不同的单价计费;被delete后应该停止计费;云硬盘被resize前后应该按不同的大小进行计费等等。我计划依然使用插件方式实现event分析模块,并且Panko有望首先用到cloudkitty项目中。
3 多维度计费能力的支持。比如网络方面要能对带宽,流量,floatingip数量,昼夜时间段四个维度的计费。
4 计费引擎cloudkitty-processor应该被优化,当前周期性计费方式在计费项目多到在一个计费周期内无法计算完成时并不适用。
6 cloudkitty,cloudkitty-dashboard,python-cloudkittyclient需要补充大量的单元测试,使项目更稳健。
7 希望cloudkitty能被广泛地使用起来,无论是在私有云还是公有云环境中,将使用的情况和碰到的问题反馈到社区才能快速地推进cloudkitty走向成熟。
参考:
Wiki: https://wiki.openstack.org/wiki/CloudKitty
Github: https://github.com/openstack/cloudkitty
Launchpad: https://launchpad.net/cloudkitty
Documentation: http://docs.openstack.org/developer/cloudkitty/
Stevedore:http://docs.openstack.org/developer/stevedore/
Pecan:https://pecan.readthedocs.io/en/latest/
本文转载自新浪微博,仅方便自己阅读
OpenStack计费项目
Cloudkitty简介以及社区最新动态
大家都知道云计算是一种按需付费的服务模式,OpenStack前期在计量方面走了些弯路,现在ceilometer,gnocchi,aodh,panko项目的稳步并进总算峰回路转。然而目前来看OpenStack的计费项目Cloudkitty并未柳暗花明,希望借助本文向大家介绍cloudkitty的架构,用户使用指导,开发以及社区方面的最新动态,吸引更多方面的关注,使用和社区参与。
前言
Cloudkitty主要依赖于遥测相关的项目,包括ceilometer和gnocchi,甚至是将要使用panko;计费策略和hashmap计费模型是其核心;模块插件化是其设计灵魂;接下来的三个部分内容将带您逐步探索。
第一部分:Cloudkitty架构详解
本部分为理论架构篇,将会详细介绍当前cloudkitty的整体架构,包括计费服务的对象获取(Tenant Fetcher),计费数据源的收集(Collector),计费引擎(Rating)的实现,计费费用数据的存储(Storage);另外将重点介绍hashmap计费模型。
一 计费服务对象Tenant Fetcher
Tenant Fetcher是用来获取合法的计费服务对象,即cloudkitty要知道需要对谁的资源进行计费。当前具体实现了从csv文件中获取和keystone中获取两种方式,分别对应FakeFetcher类和KeystoneFetcher类,均实现了父类的get_tenants抽象方法。所以只要继承基类BaseFetcher实现get_tenants方法,并配置tenant_fetcher后端,就能处理xls文件完成从Excel文档中获取需要计费的租户信息。
keystone是默认的获取计费租户的方式,同时支持V2和V3版本。具体逻辑是检查cloudkitty用户是否在某个tenant内并拥有rating角色。所以在使用cloudkitty时,一般对于想要计费的租户需要执行命令’keystone user-role-add --user cloudkitty --role rating --tenant demo’,将cloudkitty用户加入租户并赋予rating角色。
二 计费源数据收集Collector和统一化Transformer
单纯从计费角度来看,计费源主要有两类,一类是静态资源,比如虚拟机实例,镜像,云硬盘,浮动IP;一类是动态资源,比如网络流量。对于静态资源一旦被创建,那么它的单价就固定,只需根据其生命周期按时间长短计费即可;对于动态资源需要统计计量情况进行计算费用。这就意味着计费的数据源应该包括event和measurement两部分,但当前cloudkitty在计费数据收集方面没有加入事件分析能力。
这一步除了计费源数据的收集,还有一个十分重要的工作就是把这些数据转化为统一格式输入给计费引擎。Cloudkitty中的transformer模块将针对不同collector的不同类型的服务数据进行格式统一。这里需要特别说明的是transformer过程一般情况下分为两个阶段:第一个阶段是将资源数据通过对应的CeilometerTransformer或者GnocchiTransformer进行转换。第二阶段是使用CloudKittyFormatTransfor
collector和transformer模块分别有多种实现,collector实现了ceilometer,fake,gnocchi和 meta四种方式,transformer实现了CeilometerTransformer,GnocchiTransformer以及通用的CloudKittyFormatTransfor
每种collector的实现最终都会通过retrieve函数将归一化的数据发送给计费引擎。对于ceilometer和fake,这个retrieve函数会根据不同的服务调用get_compute,get_image,get_volume,get_network_bw_in,get_network_bw_out,get_network_floating,这六个方法就分别对应着cloudkitty的计费服务compute,image,volume,network.bw.in,network.bw.out,network.floating。而每个方法获得相关服务数据后会做transformer处理返回给计费引擎,最终计费引擎根据计费模型计算出具体费用再将费用数据存储起来便完成了整个计费流程。对于gnocchi,它的retrieve函数则有所不同,gnocchi直接使用自己的metric.get_measures和resource.search方法获得相关资源数据。这恰恰也体现了cloudkitty collector模块的插件化,并且实现上非常灵活,意味着如果想为CloudStack,Eucalyptus,OpenNebula等IaaS平台添加collector插件也是件愉快而轻松的事。
三 计费引擎Rating
Orchestrator类是cloudkitty计费引擎的具体实现,支持多线程,支持多种计费模型同时运行,并能指定优先级。在计费策略上cloudkitty采用的是周期轮询计费的方式,默认是每一小时对云环境中所需计费的资源进行费用核算,并将费用数据持久化存储起来。还有一个大周期是当月内,如果rated_data_frames表中的数据是空的时候,每次启动cloudkitty-processor就会重新计算当月内每小时的费用(这对调试cloudkitty也很有帮助)。
Cloudkitty当前的计费模型有三个,分别是noop,hashmap和pyscripts。noop模型为空,仅作为测试用;hashmap是当前cloudkitty实用价值最高,最容易使用,最接近实际案例的计费模型,后文将单独做详细介绍;pyscripts计费模型提供了使用python代码定制计费的接口,用户可以直接将含有计费逻辑的python脚本上传给cloudkitty实现定制化的计费,所以pyscripts计费模型使用门槛较高。
计费模型的设计和实现相对比较复杂,首先计费模型要具有enabled和priority属性并能设置,借助stevedore作为插件注册到cloudkitty.rating.processors命名空间内;其次要实现抽象方法process执行具体的费用计算逻辑;最后还需要借助pecan提供对外使用的Rest API接口。但是hashmap计费模型目前能完成绝大部分实际场景需求的计费工作,后文将对它做详细介绍。关于大家关心的按秒计费,需要加入event分析后才比较容易实现,这块内容将在第三部分提到,也是我接下来的主要计划。
四 费用数据的存储Storage
前面提到cloudkitty的计费引擎是周期性计算资源费用的,而这个周期可以根据实际情况修改,只要能在一个计费周期内完成所有资源的费用计算即可。对应一项资源的服务默认在一个小时的计费周期下,一个月内就会有720条的费用数据生成,如果将计费周期调得更小,云环境中的需要计费的资源更多,那么将会对费用数据的存储带来挑战,它会直接影响到数据的使用效果,因此费用数据的存储也是一个重要的环节。
Cloudkitty的storage目前支持sqlalchemy和gnocchi_hybrid两种方式存放费用数据,因为它们都是通过插件方式实现的,所以具体采用哪种可以通过配置文件指定,再通过get_storage方法获得具体storage实例,十分灵活方便。
Storage的具体实现过程包括:(1)通过抽象方法get_time_frame从存储后端中的数据来确定下一个时间范围。(2)通过append方法将费用数据记入提交缓存,期间可能会通过get_tenants函数和_dispatch函数做预处理或加工。(3)通过commit函数将费用数据写入到后端存储持久化。这个过程会做_pre_commit,_commit,_post_commit一系列的工作确保数据被可靠地存储。(4)对外提供get_total方法,返回费用情况。
sqlalchemy和gnocchi_hybrid的数据格式或者说表的结构都包括begin,end,unit,qty,res_type,rate,tenant_id和对资源描述相关的字段。实际上两种后端存储都是基于SQL实现的,所以随着时间的推移和云环境中需要计费资源的增加,费用数据的增加同样会出现之前类似ceilometer用SQL存储measurement数据带来性能瓶颈的问题。所以将费用数据存储在gnocchi中是必须的,详见https://review.openstack.org/#/c/319425/。
五 hashmap计费模型
Hashmap计费模型是cloudkitty的核心,其数据结构如下图所示,接着是hashmap计费模型中的几个元素及核心概念。
Hashmap Group:一个Group表示一组计费规则,例如你可以创建多个计费规则,将它们分成两组来分别为instance和volume计费,避免计费规则混乱。
Hashmap Service:一个Service将计费规则映射到具体的数据collector,例如compute,volume,image,network.bw.in,network.bw.out,network.floating。
Hashmap Field:一个Field通常是指某个资源元数据metadata字典中的一个字段。例如对于instance,可以指定Field为flavor,availability_zone等;对于volume可以指定Field为volume_type,availability_zone和status等。既可以为Field指定mapping类型的计费规则也能指定Threshold类型的计费规则。
Hashmap Mapping: 一个Mapping是指某个最终的计费规则,mapping这类计费规则可以为某个服务指定价格,也可以为Field指定价格。例如你可以指定compute服务的基础价格Flat=10$,这会适用于所有的云主机;同时你也能具体指定flavor name,value=m1.tiny,Rate=1.2,则flavor为m1.tiny的云主机价格就为10$*1.2=12$,value=m1.medium,Flat=20$,则flavor为m1.medium的云主机价格就是20$。再例如指定volume的基础单价为2$,选定Field为volume_type,SATA类型打九五折value=sata,Rate=0.95,则sata盘的单价就是2$*0.95=1.9$;SAS为标准云硬盘不打折,则不用设定,单价依然为2$;SSD为高速硬盘应加价0.2倍value=ssd,Rate=1.2,则ssd盘的单价就是2$*1.2=2.4$。
Hashmap Threshold:Threshold是另外一种最终计费规则,threshold这类计费规则更适用于基于level的Rate价格。例如云硬盘基础单价为2$(可用mapping设定),如果用户购买超过50GB,可以打九折Level=50,Rate=0.9,此时单价为2$*0.9=1.8$;超过100GB打八折Level=100,Rate=0.8,此时单价为2$*0.8=1.6$。
通过以上介绍和具体举例,说明hashmap计费模型具有较广泛的使用范围,能满足实际需求中较复杂的计费场景。总结一下hashmap计费模型,它可以直接为资源或者服务设定价格(Flat或者Rate);也能根据资源的Field设定mapping和threshold类型的价格(Flat或者Rate);还能根据资源某字段的Level设定价格(Rate为主)。
第二部分:动手实践
本部分为动手实践篇,主要包括部署和使用cloudkitty。在部署方面分别采用devstack部署,package方式部署和源码开发环境搭建三种方式来满足不同用户和开发者的需求。通过本部分介绍,大家将会对cloudkitty有感性认识,并且能使开发者快速融入。
一 使用devstack部署
(1)准备
[root@zhangguoqing-dev ~]# git clone https://review.openstack.org/openstack-dev/devstack
使用tools/create-stack-user.sh脚本创建stack用户,并切su到stack的用户空间
[stack@zhangguoqing-dev ~]$ cd devstack && cp samples/local.conf ./local.conf
(2)修改配置文件local.conf使用trystack源,参考如下:
[[local|localrc]]
GIT_BASE=http://git.trystack.cn
NOVNC_REPO=http://git.trystack.cn/kanaka/noVNC.git
SPICE_REPO=http://git.trystack.cn/git/spice/spice-html5.git
HOST_IP=172.16.40.152
ADMIN_PASSWORD=password
DATABASE_PASSWORD=password
RABBIT_PASSWORD=password
SERVICE_PASSWORD=password
LOGFILE=$DEST/logs/stack.sh.log
LOGDAYS=2
SWIFT_HASH=66a3d6b56c1f479c8b4e70ab
SWIFT_REPLICAS=1
SWIFT_DATA_DIR=$DEST/data
enable_service horizon
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer.git
enable_plugin cloudkitty https://git.openstack.org/openstack/cloudkitty.git
enable_service ck-api ck-proc
(3)执行部署
[stack@zhangguoqing-dev devstack]$ ./stack.sh
二 Package方式部署(for mitaka)
(1)准备openstack mitaka源并安装相应的packages
# yum install centos-release-openstack-mitaka
# yum upgrade
# yum install openstack-cloudkitty-api openstack-cloudkitty-processor python-cloudkittyclient
(2)准备cloudkitty运行所依赖的环境
创建cloudkitty数据库
MariaDB [(none)]> CREATE DATABASE cloudkitty;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'localhost' IDENTIFIED BY 'password';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'%' IDENTIFIED BY 'password';
在keystone中创建相应的用户和endpoint
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-create --name cloudkitty --pass password
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role admin --tenant services
[root@zhangguoqing-dev ~(keystone_admin)]# keystone service-create --name cloudKitty --type rating --description "OpenStack Rating Service"
[root@zhangguoqing-dev ~(keystone_admin)]# keystone endpoint-create --service-id
--internalurl http://172.16.40.152:8889 \
--region RegionOne
新建rating角色,并对demo租户进行计费
[root@zhangguoqing-dev ~(keystone_admin)]# keystone role-create --name rating
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role rating --tenant demo
(3)配置/etc/cloudkitty/cloudkitty.conf,参考如下
[DEFAULT]
debug = True
log_dir = /var/log/cloudkitty
[collect]
period = 3600
services = compute,image,volume,network.bw.in,network.bw.out,network.floating
[database]
connection=mysql+pymysql://cloudkitty:password@172.16.40.152/cloudkitty
[keystone_authtoken]
auth_uri = http://172.16.40.152:5000/v2.0
identity_uri=http://172.16.40.152:35357
admin_password=password
admin_user=cloudkitty
admin_tenant_name=services
[auth]
auth_type = password
auth_url = http://172.16.40.152:5000
username = cloudkitty
user_domain_id = default
password = password
project_domain_id = default
project_name = services
[keystone_fetcher]
auth_section = auth
[ceilometer_collector]
auth_section = auth
[oslo_messaging_rabbit]
amqp_durable_queues=False
rabbit_hosts=172.16.40.152:5672
rabbit_userid = guest
rabbit_password = guest
[storage]
backend = sqlalchemy
[tenant_fetcher]
backend = keystone
(4)初始化和开启服务
初始化数据库
初始化后端存储
# systemctl enable openstack-cloudkitty-api openstack-cloudkitty-processor
# systemctl start openstack-cloudkitty-api openstack-cloudkitty-processor
(5)源码安装cloudkitty-dashboard
Mitaka版本通过命令yum search all cloudkitty没有发现cloudkitty-dashboard的安装包,现在从源码安装cloudkitty的dashboard。
获取源码并安装
# git clone https://git.openstack.org/openstack/cloudkitty-dashboard
# cd cloudkitty-dashboard
# git checkout -b stable/mitaka origin/stable/mitaka
# python setup.py install
在horizon中开启cloudkitty-dashboard
# PY_PACKAGES_PATH=`pip --version | cut -d' ' -f4`
# ln -sf $PY_PACKAGES_PATH/cloudkittydashboard/enabled/_[0-9]*.py \
/usr/share/openstack-dashboard/openstack_dashboard/enabled/
# systemctl restart httpd
(6)界面预览
三 开发环境搭建
如果觉得使用devstack开发是件麻烦的事,那么本节将带您搭建一个hand-in的cloudkitty开发环境(cloudkitty + cloudkitty-dashboard + python-cloudkittyclient)。
(1)准备开发环境和配置文件
# mkdir ~/cloudkitty-dev && cd ~/cloudkitty-dev
# git clone https://git.openstack.org/openstack/cloudkitty
# git clone https://git.openstack.org/openstack/cloudkitty-dashboard
# git clone https://git.openstack.org/openstack/python-cloudkittyclient
# git clone https://git.openstack.org/openstack/horizon
# cd cloudkitty/
# mkdir -p /etc/cloudkitty
# cp etc/cloudkitty/api_paste.ini /etc/cloudkitty/
# cp etc/cloudkitty/policy.json /etc/cloudkitty/
# tox -e genconfig
# cp etc/cloudkitty/cloudkitty.conf.sample /etc/cloudkitty/cloudkitty.conf
(2)准备cloudkitty运行所依赖的环境
创建cloudkitty数据库
MariaDB [(none)]> CREATE DATABASE cloudkitty;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'localhost' IDENTIFIED BY 'password';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON cloudkitty.* TO 'cloudkitty'@'%' IDENTIFIED BY 'password';
在keystone中创建相应的用户和endpoint
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-create --name cloudkitty --pass password
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role admin --tenant services
[root@zhangguoqing-dev ~(keystone_admin)]# keystone service-create --name cloudKitty --type rating --description "OpenStack Rating Service"
[root@zhangguoqing-dev ~(keystone_admin)]# keystone endpoint-create --service-id
--internalurl http://172.16.40.152:8889 \
--region RegionOne
新建rating角色,并对demo租户进行计费
[root@zhangguoqing-dev ~(keystone_admin)]# keystone role-create --name rating
[root@zhangguoqing-dev ~(keystone_admin)]# keystone user-role-add --user cloudkitty --role rating --tenant demo
(3)修改配置文件/etc/cloudkitty/cloudkitty.conf,参考如下
[DEFAULT]
debug = True
log_dir = /var/log/cloudkitty
[collect]
period = 3600
services = compute,image,volume,network.bw.in,network.bw.out,network.floating
[database]
connection=mysql+pymysql://cloudkitty:password@172.16.40.152/cloudkitty
[keystone_authtoken]
auth_uri = http://172.16.40.152:5000/v2.0
identity_uri=http://172.16.40.152:35357
admin_password=password
admin_user=cloudkitty
admin_tenant_name=services
[auth]
auth_type = password
auth_url = http://172.16.40.152:5000
username = cloudkitty
user_domain_id = default
password = password
project_domain_id = default
project_name = services
[keystone_fetcher]
auth_section = auth
[ceilometer_collector]
auth_section = auth
[oslo_messaging_rabbit]
amqp_durable_queues=False
rabbit_hosts=172.16.40.152:5672
rabbit_userid = guest
rabbit_password = guest
[storage]
backend = sqlalchemy
[tenant_fetcher]
backend = keystone
(4)初始化和开启服务
通过tox生成虚拟环境
# cd ~/cloudkitty-dev/cloudkitty/
# tox -e venv -- pip install pymysql
初始化数据库和后端存储
# tox -e venv -- cloudkitty-dbsync upgrade
# tox -e venv -- cloudkitty-storage-init
开启ck-api和ck-proc服务
# tox -e venv -- cloudkitty-api --config-file=/etc/cloudkitty/cloudkitty.conf
# tox -e venv -- cloudkitty-processor --config-file=/etc/cloudkitty/cloudkitty.conf
在虚拟环境中安装和使用python-cloudkittyclient
# tox -e venv -- pip install -e ../python-cloudkittyclient/
# source .tox/venv/bin/activate
(venv) # cloudkitty --help
(5)安装cloudkitty-dashboard的开发环境
创建horizon虚拟环境并把cloudkittydashboard作为模块安装进去
# cd ~/cloudkitty-dev/horizon/
# tox -e venv -- pip install -e ../cloudkitty-dashboard/
将cloudkitty-dashboard的插件文件链接到Horizon的enabled目录下面
# ln -sf
openstack_dashboard/enabled/
开启Django HTTP server,在浏览器输入IP:9000即可访问cloudkitty-dashboard相关的页面
# cp openstack_dashboard/local/local_settings.py.example
openstack_dashboard/local/local_settings.py
# tox -e venv -- python manage.py runserver 0.0.0.0:9000
四 使用演示
(1)演示场景描述
采用hashmap计费模型进行演示,计费场景设定(为了演示的方便,请忽略价格、Threshold Level等数据与真实情况的差别)的具体数据展示在下面的说明和表格中:
1.
2.
3.
4.
5.
Service | Fields | Service Mappings | Service Thresholds | Groups |
compute (flavor) | Flat 1$ Flat 2$ Flat 3$ | | | instance_flavor |
volume | | Level:1GB Level:2GB | volume_thresholds | |
network.bw.in | | flat 2$ | | network_inout |
network.bw.out | | flat 2$ | | network_inout |
network.floating | | flat 2$ | | network_inout |
注:可以尝试实现既按云硬盘类型和又按云硬盘大小分级计费规则
(2)使用admin用户,完成上述计价规则的设定
开启hashmap计费模块
创建相应的服务compute,volume,network.bw.in,network.bw.out,network.floating和instance_flavor,volume_thresholds,network_inout计费组。
根据flavor对云主机定价
根据size对云硬盘定价
对network.* 定价(network.bw.in,network.bw.out,network.floating均相同)
(3)用户demo查看当月费用情况
第三部分:社区动态
IRC : #cloudkitty on freenode
Meeting weekly: Monday at 2PM #openstack-meeting-3 (北京时间每周一晚上十点)
一 进行时
1 当前计费数据存储的后端实现了sqlalchemy和 gnocchi_hybrid两种方式,实质上都是依赖于SQL数据库。为了避免类似ceilometer计量数据存储的问题,cloudkitty的计费数据存储也将实现gnocchi原生支持。
Added native gnocchi storage driver
2 实现根据租户和用户查询费用情况的API
Get total price by tenant_id and user_id
3 对当前项目RPC机制进行代码优化
Improve the rpc module
4 对认证模块进行升级,采用keystoneauth1模块,简化配置
Migrate from keystoneclient to keystoneauth
Use keystoneauth1 to service credentials
5 devstack插件方式部署
Fix and enhance devstack plugin
6 文档更新,方便用户和吸引更多开发者加入
Update install from mitaka packages
Update the install and configure section
二 BP规划
1 实现cloudkitty-api的wsgi支持,方便云环境对计费服务的负载均衡和高可用。
https://blueprints.launchpad.net/cloudkitty/+spec/wsgi-support
2 越来越多的云主机会从云硬盘启动,那么云硬盘快照的计费支持会更强烈。
https://blueprints.launchpad.net/cloudkitty/+spec/rating-volume-snapshot
3 需要获得更准确的更多维度的计费情况,以支持billing。
https://blueprints.launchpad.net/cloudkitty/+spec/price-groupby-fields
4 使colleting和reporting支持本地时钟。
https://blueprints.launchpad.net/cloudkitty/+spec/local-time-zone-support
5取消SQL Schema Downgrade的操作。
https://blueprints.launchpad.net/cloudkitty/+spec/remove-schema-downgrades
6 集成cloudkitty到kolla中。
https://blueprints.launchpad.net/kolla/+spec/cloudkitty
三 作者展望
1 cloudkitty-dashboard的展示信息应该更直观,更易于操作。例如:
Adjust the reporting page
Show group_name rather than group_id
Show threshold's level in group details page
2 实现按秒计费。cloudkitty需要加上事件分析能力才能使计费更精确(达到秒级计费)和商用化。例如一台云主机在一个计费周期内:被stop的时间段内应该计费为0;rebuild更新了flavor,前后时间段内应该按不同的单价计费;被delete后应该停止计费;云硬盘被resize前后应该按不同的大小进行计费等等。我计划依然使用插件方式实现event分析模块,并且Panko有望首先用到cloudkitty项目中。
3 多维度计费能力的支持。比如网络方面要能对带宽,流量,floatingip数量,昼夜时间段四个维度的计费。
4 计费引擎cloudkitty-processor应该被优化,当前周期性计费方式在计费项目多到在一个计费周期内无法计算完成时并不适用。
6 cloudkitty,cloudkitty-dashboard,python-cloudkittyclient需要补充大量的单元测试,使项目更稳健。
7 希望cloudkitty能被广泛地使用起来,无论是在私有云还是公有云环境中,将使用的情况和碰到的问题反馈到社区才能快速地推进cloudkitty走向成熟。
参考:
Wiki: https://wiki.openstack.org/wiki/CloudKitty
Github: https://github.com/openstack/cloudkitty
Launchpad: https://launchpad.net/cloudkitty
Documentation: http://docs.openstack.org/developer/cloudkitty/
Stevedore:http://docs.openstack.org/developer/stevedore/
Pecan:https://pecan.readthedocs.io/en/latest/
本文转载自新浪微博:
http://blog.sina.com.cn/s/blog_6de3aa8a0102wfwu.html
更多推荐
所有评论(0)