OpenStack-RPC-server的构建(一)

本文剖析了OpenStack中Nova Scheduler服务的启动流程,重点分析了RPC-server的构建过程,特别是如何通过systemd加载服务及nova-scheduler命令的执行细节。

        我们主要分析Transport为rabbit方式的RPC-server构建,当我们执行如下命令时:

[root@junmulti-user.target.wants(keystone_admin)]# rabbitmqctl list_consumers

Listingconsumers ...

alarm_notifier  <rabbit@jun.1.594.0>    1      true    0       []

alarm_notifier.jun      <rabbit@jun.1.594.0>    2      true    0       []

alarm_notifier_fanout_bcc5514c42a24c78928bf08dc4bc844e  <rabbit@jun.1.594.0>    3      true    0       []

cert    <rabbit@jun.1.882.0>    1      true    0       []

cert.jun        <rabbit@jun.1.882.0>    2      true    0       []

cert_fanout_8c23d4a227af4488a5ee22249422a5e8    <rabbit@jun.1.882.0>    3      true    0       []

……….

reply_32583cb2867d476db776e2d4d2093606  <rabbit@jun.1.2635.0>   1      true    0       []

reply_9b28643406614d8280db511872854dbb  <rabbit@jun.1.2907.0>   1      true    0       []

reply_eb5af11fd3aa42dda88eea22446d3fc1  <rabbit@jun.1.2769.0>   1       true   0       []

scheduler       <rabbit@jun.1.899.0>    1      true    0       []

scheduler.jun   <rabbit@jun.1.899.0>    2      true    0       []

scheduler_fanout_eb88ae2d696c40538615fb8e7af84f2f       <rabbit@jun.1.899.0>    3      true    0       []

        我们可以利用linux的systemd技术,在linux系统启动时,加载OpenStack组件服务,从而形成RPC的consumer。所以我们可以从systemd的相关文件找到OpenStack组件服务的启动入口,在这里我们主要关注OpenStack组件服务中RPC-server的构建过程,且以Nova-scheduler组件为例进行分析。

[root@jun~(keystone_admin)]# cat/etc/systemd/system/multi-user.target.wants/openstack-nova-scheduler.service

[Unit]

Description=OpenStackNova Scheduler Server

After=syslog.targetnetwork.target

 

[Service]

Type=notify

NotifyAccess=all

TimeoutStartSec=0

Restart=always

User=nova

ExecStart=/usr/bin/nova-scheduler

 

[Install]

WantedBy=multi-user.target

        Systemd通过执行/usr/bin/nova-scheduler命令来启动Nova-scheduler组件,那么/usr/bin/nova-scheduler做了什么呢?我们继续往下分析。

[root@jun~(keystone_admin)]# cat /usr/bin/nova-scheduler

#!/usr/bin/python

#PBR Generated from u'console_scripts'

 

importsys

fromnova.cmd.scheduler import main

 

if__name__ == "__main__":

    sys.exit(main())

        原来这个文件执行/usr/lib/python2.7/site-packages/nova/cmd/scheduler.py中的main函数。如下所示:

"""Starterscript for Nova Scheduler."""

…….

CONF= cfg.CONF

CONF.import_opt('scheduler_topic','nova.scheduler.rpcapi')

 

defmain():

    config.parse_args(sys.argv)

    logging.setup(CONF, "nova")

    utils.monkey_patch()

    objects.register_all()

 

    gmr.TextGuruMeditation.setup_autorun(version)

 

    server =service.Service.create(binary='nova-scheduler',

                                   topic=CONF.scheduler_topic)

    service.serve(server)

    service.wait()

        其中,红色标记中的内容与RPC-server的创建有关,所以我们重点关注红色部分的函数调用内容。

1. config.parse_args(sys.argv)

defparse_args(argv, default_config_files=None):

   log.set_defaults(_DEFAULT_LOGGING_CONTEXT_FORMAT, _DEFAULT_LOG_LEVELS)

    log.register_options(CONF)

    options.set_defaults(CONF,connection=_DEFAULT_SQL_CONNECTION,

                        sqlite_db='nova.sqlite')

    rpc.set_defaults(control_exchange='nova')

    debugger.register_cli_opts()

    CONF(argv[1:],

         project='nova',

         version=version.version_string(),

         default_config_files=default_config_files)

    rpc.init(CONF)

        由于control_exchange的默认值为:’openstack’,所以通过set_defaults函数修改为:’nova’。因此随后的get_transport函数中获得的control_exchange的值为:’nova’。

rpc.init(CONF)代码如下:

definit(conf):

    global TRANSPORT, NOTIFIER

    exmods = get_allowed_exmods()

    TRANSPORT = messaging.get_transport(conf,

                                       allowed_remote_exmods=exmods,

                                       aliases=TRANSPORT_ALIASES)

    serializer =RequestContextSerializer(JsonPayloadSerializer())

    NOTIFIER = messaging.Notifier(TRANSPORT,serializer=serializer)

A. get_transport方法通过从用户配置文件中搜集到与transport相关的配置文件来构造且返回一个Transport对象。如下所示:

defget_transport(conf, url=None, allowed_remote_exmods=None, aliases=None):

    """A factory method forTransport objects.

 

    This method will construct a Transportobject from transport configuration

    gleaned from the user's configuration and,optionally, a transport URL.

 

    If a transport URL is supplied as aparameter, any transport configuration

    contained in it takes precedence. If notransport URL is supplied, but

    there is a transport URL supplied in theuser's configuration then that

    URL will take the place of the URLparameter. In both cases, any

    configuration not supplied in the transportURL may be taken from

    individual configuration parameters in theuser's configuration.

 

    An example transport URL might be::

 

        rabbit://me:passwd@host:5672/virtual_host

 

    and can either be passed as a string or aTransportURL object.

 

    :param conf: the user configuration

    :type conf: cfg.ConfigOpts

    :param url: a transport URL

    :type url: str or TransportURL

    :param allowed_remote_exmods: a list ofmodules which a client using this

                                  transportwill deserialize remote exceptions

                                  from

    :type allowed_remote_exmods: list

    :param aliases: A map of transport alias totransport name

    :type aliases: dict

    """

    allowed_remote_exmods =allowed_remote_exmods or []

    conf.register_opts(_transport_opts)

 

    if not isinstance(url, TransportURL):

        url = url or conf.transport_url

        parsed = TransportURL.parse(conf, url,aliases)

        if not parsed.transport:

            raise InvalidTransportURL(url, 'Noscheme specified in "%s"' % url)

        url = parsed

 

    kwargs = dict(default_exchange=conf.control_exchange,

                  allowed_remote_exmods=allowed_remote_exmods)

 

    try:

        mgr =driver.DriverManager('oslo.messaging.drivers',

                                  url.transport.split('+')[0],

                                  invoke_on_load=True,

                                  invoke_args=[conf, url],

                                  invoke_kwds=kwargs)

    except RuntimeError as ex:

        raise DriverLoadFailure(url.transport,ex)

 

    return Transport(mgr.driver)

        这里get_transport方法将_transport_opts对象register到conf对象中,而_transport_opts对象中的control_exchange属性在上面的set_defaults方法中设置为:’nova’,不是默认值:’openstack’。

        driver.DriverManager是stevedore组件中的方法,stevedore组件可以在运行时发现和载入所谓的”插件”,它在Setuptools的entrypoints基础上,构造一层抽象层,使开发者可以更加容易地在运行时发现和载入插件。

        在这里我们利用oslo_messaging中的entry points来发现和载入插件。在我的OpenStack环境中(kilo版本),entry points文件为:/usr/lib/python2.7/site-packages/oslo.messaging-1.8.2-py2.7.egg-info/entry_points.txt。

[oslo.messaging.zmq.matchmaker]

local= oslo_messaging._drivers.matchmaker:MatchMakerLocalhost

ring= oslo_messaging._drivers.matchmaker_ring:MatchMakerRing

redis= oslo_messaging._drivers.matchmaker_redis:MatchMakerRedis

 

[oslo.config.opts]

oslo.messaging= oslo_messaging.opts:list_opts

 

[oslo.messaging.notify.drivers]

log= oslo_messaging.notify._impl_log:LogDriver

messagingv2= oslo_messaging.notify._impl_messaging:MessagingV2Driver

noop= oslo_messaging.notify._impl_noop:NoOpDriver

routing= oslo_messaging.notify._impl_routing:RoutingDriver

test= oslo_messaging.notify._impl_test:TestDriver

messaging= oslo_messaging.notify._impl_messaging:MessagingDriver

 

[console_scripts]

oslo-messaging-zmq-receiver= oslo_messaging._cmd.zmq_receiver:main

 

[oslo.messaging.drivers]

qpid= oslo_messaging._drivers.impl_qpid:QpidDriver

amqp= oslo_messaging._drivers.protocols.amqp.driver:ProtonDriver

kombu= oslo_messaging._drivers.impl_rabbit:RabbitDriver

rabbit =oslo_messaging._drivers.impl_rabbit:RabbitDriver

fake= oslo_messaging._drivers.impl_fake:FakeDriver

zmq= oslo_messaging._drivers.impl_zmq:ZmqDriver

 

[oslo.messaging.executors]

aioeventlet= oslo_messaging._executors.impl_aioeventlet:AsyncioEventletExecutor

threading= oslo_messaging._executors.impl_thread:ThreadExecutor

blocking= oslo_messaging._executors.impl_blocking:BlockingExecutor

eventlet= oslo_messaging._executors.impl_eventlet:EventletExecutor

        其中[*]中的内容为entry points的namespace名称,它下面的内容为插件相关内容,如oslo.messaging.drivers即为namespace名称,其中它下面包括6个插件。其中每个插件都符合”名字 = 模块:可导入对象”。上述driver.DriverManager方法的第一个参数:” oslo.messaging.drivers”即为namespace名称。第二个参数为插件名,其中该场景下使用的是rabbit插件,即:rabbit =oslo_messaging._drivers.impl_rabbit:RabbitDriver。然后利用mgr.driver(即oslo_messaging._drivers.impl_rabbit.RabbitDriver)去构造Transport对象。

B.NOTIFIER = messaging.Notifier(TRANSPORT, serializer=serializer)创建一个Notifier对象通过TRANSPORT发送通知消息。通知消息遵循如下的格式:

{'message_id':six.text_type(uuid.uuid4()),  #消息id号

 'publisher_id': 'compute.host1',                       #发送者id

 'timestamp': timeutils.utcnow(),                      #时间戳

 'priority': 'WARN',                                              #通知优先级

 'event_type': 'compute.create_instance',        #通知类型

 'payload': {'instance_id': 12, ... }                        #通知内容

}

        可以在不同的优先级别上发送通知,这些优先级包括sample,critical,error,warn,info,debug和audit等。

        总结:本篇文章从linux的systemd入手,找到Nova-scheduler的启动流程,然后主要分析/usr/lib/python2.7/site-packages/nova/cmd/scheduler.py中的main函数的config.parse_args(sys.argv)初始化过程。即创建一个Notify对象,该对象通过某种transport(这里是rabbit)发送通知消息。其中

server =service.Service.create(binary='nova-scheduler',

                                   topic=CONF.scheduler_topic)

    service.serve(server)

    service.wait()

        对于这三行代码,我们将在后面进行详细分析。

### 安装 OpenStack Nova 组件 可以通过 `yum` 命令来安装 OpenStack Nova 的相关组件,具体命令如下: ```bash yum -y install openstack-nova-api openstack-nova-conductor openstack-nova-scheduler openstack-nova-novncproxy ``` 此命令将会自动下载并安装所需的依赖项以及指定的服务组件[^1]。 --- ### 配置 OpenStack Nova 服务 完成安装后,需要对这些服务进行必要的配置。以下是主要步骤说明: #### 修改主配置文件 编辑 `/etc/nova/nova.conf` 文件以调整调度器的行为。例如,为了实现定期扫描计算节点的功能,可以在 `[scheduler]` 节下添加以下参数: ```ini [scheduler] discover_hosts_in_cells_interval = 300 ``` 这表示每隔 300 秒(即 5 分钟)扫描次计算节点中的主机状态[^4]。 保存更改后重启 API 服务以使新配置生效: ```bash systemctl restart openstack-nova-api.service ``` --- ### 启动与设置开机自启 安装完成后,需手动启动各个 Nova 相关服务,并将其设为随系统启动而运行: ```bash systemctl start openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy systemctl enable openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy ``` 以上操作确保了所有核心服务正常运行并能够在下次系统启动时自动加载[^2]。 --- ### 创建管理接口端点 如果尚未创建 Nova 的管理员服务端点,则可通过以下命令完成初始化工作: ```bash openstack endpoint create --region RegionOne nova admin http://<control_node_ip>:8774/v2.1 ``` 其中 `<control_node_ip>` 应替换为实际的控制器节点 IP 地址。成功执行该命令后,将返回包含字段及其对应值的结果表单,确认端点已正确注册到 Keystone 中[^3]。 --- ### 总结 综上所述,通过 Yum 源安装 OpenStack Nova 组件的过程涉及以下几个方面: 1. 使用 `yum` 工具批量安装所需软件包; 2. 编辑配置文件优化功能选项; 3. 手动激活各子服务并将它们加入系统的引导序列; 4. 注册相应的访问入口至身份验证框架内。 按照上述指导即可顺利完成基础环境搭建任务。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值