puppet-cinder模块介绍

  1. 基础知识-快速了解keystone
  2. 先睹为快-一言不和,立马动手?
  3. 核心代码讲解-如何管理cinder服务
  4. 小结
  5. 动手练习-光看不练假把式

本节作者:周维宇

建议阅读时间 2小时

基础知识

cinder概述

  • 它是一个资源管理系统,负责向虚拟机提供持久块存储资源(云硬盘)。
  • 主要核心是对卷的管理,允许对卷,卷的类型,卷的快照进行处理
  • 它把不同的后端存储进行封装,向外提供统一的API。
  • 它不是新开发的块设备存储系统,而是使用插件的方式结合不同后端存储的驱动提供块存储服务。

cinder架构

puppet-cinder - 图1

上图环境是根据本章的实验环境绘制

主要组件介绍
  • cinder-api:主要服务接口, 负责接受和处理外界的API请求,并将请求放入消息队列,交由其他组件执行。
  • cinder-scheduer: 根据预定的策略选择合适的cinder-volume节点来处理用户的请求,如果用户请求中执行的具体的存储节点则不需要cinder-scheduler介入。
  • cinder-volume: 该服务运行在存储节点,通过driver负责实际的卷管理工作。
  • cinder-backup: 备份cinder卷到其他存储(swift,ceph等)。
实验环境说明
  • cinder-api/mariadb/rabbitmq部署在控制节点,cinder-volume/ceph-monitor/ceph-osd部署在存储节点(你也可以把所有服务部署在同一节点)
  • 部署了两个cinder-volume,一个使用ceph作为存储后端,一个使用lvm作为存储后端
  • 本实验环境依赖前面章节部署的mariadb/keystone/ceph/rabbitmq

先睹为快

在讲解cinder模块之前让我们先使用puppet把我们的实验环境部署起来,请根据你的具体环境修改learn_cinder.pp

编写learn_cinder.pp

  1. class { 'cinder':
  2. database_connection => 'mysql://cinder:secret_block_password@openstack-controller.example.com/cinder',
  3. rabbit_password => 'secret_rpc_password_for_blocks',
  4. rabbit_host => 'openstack-controller.example.com',
  5. verbose => true,
  6. }
  7. class { 'cinder::api':
  8. keystone_password => $keystone_password,
  9. keystone_enabled => $keystone_enabled,
  10. keystone_user => $keystone_user,
  11. keystone_auth_host => $keystone_auth_host,
  12. keystone_auth_port => $keystone_auth_port,
  13. keystone_auth_protocol => $keystone_auth_protocol,
  14. service_port => $keystone_service_port,
  15. package_ensure => $cinder_api_package_ensure,
  16. bind_host => $cinder_bind_host,
  17. enabled => $cinder_api_enabled,
  18. }
  19. class { 'cinder::scheduler': }
  20. class { 'cinder::volume': }
  21. cinder::backend::rbd {'rbd-images':
  22. rbd_pool => 'images',
  23. rbd_user => 'images',
  24. }
  25. cinder_type {'ceph':
  26. ensure => present,
  27. properties => ['volume_backend_name=rbd-images'],
  28. }
  29. class { 'cinder::backends':
  30. enabled_backends => ['iscsi1', 'iscsi2', 'rbd-images']
  31. }

在终端执行以下命令:

  1. puppet apply -v learn_cinder.pp

ok,恭喜你,已经有了一个使用ceph作为后端的cinder服务,敢紧来试试吧

  1. source openrc
  2. openstack volume create test_cinder --size 1 --type ceph

你已经创建了一个1G大小的cinder卷

核心代码讲解

Class cinder

class cinder非常简单主要做了两件核心工作

  • 安装cinder基础包
  • 配置cinder.conf中的核心参数

软件包管理

这里有一个非常有用的参数是$package_ensure,我们可以指定软件包的版本,或者将其标记为总是安装最新版本,我们将会在最佳实践部分去介绍它。

  1. package { 'cinder':
  2. ensure => $package_ensure,
  3. name => $::cinder::params::package_name,
  4. tag => ['openstack', 'cinder-package'],
  5. require => Anchor['cinder-start'],
  6. }

cinder核心参数管理

class cinder里管理了大量的配置参数,比如db,rpc,az设置等相关参数,这里不一一列举。
这里只一个代码片段为例来解释cinder_config的用法。和前面介绍的keystone_config类似cinder_config是一个自定义的resource type,其源码路径位于:

lib/puppet/type/cinder_config.rb 定义

lib/puppet/provider/cinder_config/ini_setting.rb 实现

在这里我们关注如何使用,在Advanced Puppet一书中我们将讲解如何编写custom resource type。
cinder_config有多种使用方法:

对指定参数赋值:

  1. cinder_config { 'section_name/option_name': value => option_value}

对指定参数赋值,并设置为加密:

  1. cinder_config { 'section_name/option_name': value => option_value secret => true}

我们知道puppet agent的所有输出默认都会被syslog打到系统日志/var/log/messages中,那么有心人只要用grep就能从中搜到许多敏感信息,例如:admin_token, user_password, keystone_db_password等等。只要设置了secret为true后,那么就不会把该参数的相关日志打到系统日志中。
OK,讲解就到这里,我们来看代码。

  1. cinder_config {
  2. 'DEFAULT/enable_v1_api': value => $enable_v1_api;
  3. 'DEFAULT/enable_v2_api': value => $enable_v2_api;
  4. 'DEFAULT/enable_v3_api': value => $enable_v3_api;
  5. }

Class cinder::api

class cinder::api 主要配置和管理cinder的api服务

管理服务

cinder可以作为一个服务启动,也可以启动在apache下

  1. if $service_name == $::cinder::params::api_service {
  2. service { 'cinder-api':
  3. ensure => $ensure,
  4. name => $::cinder::params::api_service,
  5. enable => $enabled,
  6. hasstatus => true,
  7. require => Package['cinder'],
  8. tag => 'cinder-service',
  9. }
  10. } elsif $service_name == 'httpd' {
  11. include ::apache::params
  12. service { 'cinder-api':
  13. ensure => 'stopped',
  14. name => $::cinder::params::api_service,
  15. enable => false,
  16. tag => ['cinder-service'],
  17. }
服务检查

调用cinder list命令来确确认cinder服务是否ready

  1. if $validate {
  2. $defaults = {
  3. 'cinder-api' => {
  4. 'command' => "cinder --os-auth-url ${auth_uri} --os-tenant-name ${keystone_tenant} --os-username ${keystone_user} --os-password ${keystone_password} list",
  5. }
  6. }
  7. $validation_options_hash = merge ($defaults, $validation_options)
  8. create_resources('openstacklib::service_validation', $validation_options_hash, {'subscribe' => 'Service[cinder-api]'})
  9. }

Class cinder::scheduler

这个class没什么好讲的,无非是装包,改配置,启服务三板斧

Class cinder::volume

同上

Class cinder::backup

同上

Define cinder::backend::backend_name

后端的定义由很多define组成,我们举例我们用到的cinder::backend::rbd,比较值得注意的是用define来实现后端定义,因为在cinder中可能有多个同一类型的后端,比如一个cinder配置两个ceph作为cinder存储后端,这时候用class实现显然是不合适的
主要也是调用cinder_config 来修改cinder.conf文件

  1. cinder_config {
  2. "${name}/volume_backend_name": value => $volume_backend_name;
  3. "${name}/volume_driver": value => 'cinder.volume.drivers.rbd.RBDDriver';
  4. "${name}/rbd_ceph_conf": value => $rbd_ceph_conf;
  5. "${name}/rbd_user": value => $rbd_user;
  6. "${name}/rbd_pool": value => $rbd_pool;
  7. "${name}/rbd_max_clone_depth": value => $rbd_max_clone_depth;
  8. "${name}/rbd_flatten_volume_from_snapshot": value => $rbd_flatten_volume_from_snapshot;
  9. "${name}/rbd_secret_uuid": value => $rbd_secret_uuid;
  10. "${name}/rados_connect_timeout": value => $rados_connect_timeout;
  11. "${name}/rados_connection_interval": value => $rados_connection_interval;
  12. "${name}/rados_connection_retries": value => $rados_connection_retries;
  13. "${name}/rbd_store_chunk_size": value => $rbd_store_chunk_size;
  14. }

Class cinder::backends

由于cinder支持多后端,这个类主要用来管理开启哪些存储后端

调用cinder_config来修改cinder.conf

  1. class cinder::backends (
  2. $enabled_backends = undef,
  3. ) {
  4. # Maybe this could be extented to dynamicly find the enabled names
  5. cinder_config {
  6. 'DEFAULT/enabled_backends': value => join($enabled_backends, ',');
  7. }
  8. }

Define cinder::type

cinder开启多后端后,如何确定要将卷创建到哪个后端呢,这就要有type来决定.

  1. define cinder::type (
  2. $set_key = undef,
  3. $set_value = undef,
  4. # DEPRECATED PARAMETERS
  5. $os_password = undef,
  6. $os_tenant_name = undef,
  7. $os_username = undef,
  8. $os_auth_url = undef,
  9. $os_region_name = undef,
  10. ) {
  11. if $os_password or $os_region_name or $os_tenant_name or $os_username or $os_auth_url {
  12. warning('Parameters $os_password/$os_region_name/$os_tenant_name/$os_username/$os_auth_url are not longer required')
  13. warning('Auth creds will be used from env or /root/openrc file or cinder.conf')
  14. }
  15. if ($set_value and $set_key) {
  16. if is_array($set_value) {
  17. $value = join($set_value, ',')
  18. } else {
  19. $value = $set_value
  20. }
  21. cinder_type { $name:
  22. ensure => present,
  23. properties => ["${set_key}=${value}"],
  24. }
  25. } else {
  26. cinder_type { $name:
  27. ensure => present,
  28. }
  29. }
  30. }

这个关键的是cinder_type,其源码路径为

lib/puppet/type/cinder_type.rb

lib/puppet/provider/cinder_type/openstack.rb

小结

ok,核心代码的解析就到这里,后面的像cinder::quota,cinder::policy,cinder::logging等配置就不在一一解析,留给读者课后去学习.总之puppet-cinder除了多后端配置和其他模块略有不同之外,其余部分都十分相似,是一个比较容易学习的模块.

动手练习

1.在另外一个节点部署一个cinder-volume,并使用lvm作存储后端。

2.创建一个新的volume-type lvm,将该type的卷存储到lvm后端。

3.创建一个type为lvm的卷,并挂载到虚机。