升级

Cinder 旨在提供尽可能减少停机时间的升级。

这应该同时适用于数据平面和控制平面。由于 Cinder 不会干扰数据平面,因此其升级不应影响虚拟机正在访问的任何卷。

在升级期间保持控制平面运行更加困难。本文档的目标是提供此类升级的准备工作和详细步骤。

概念

在阅读升级过程部分之前,你需要了解以下关键概念

RPC 版本固定

通过仔细的 RPC 版本控制,较新的服务能够与旧的服务进行通信(反之亦然)。版本使用在 services 表中报告的信息自动检测。如果在服务启动时收到 CappedVersionUnknownServiceTooOld 异常,你可能在该表中存在一些旧的孤立记录。

优雅的服务关闭

许多 cinder 服务都是 Python 进程,监听 AMQP 队列上的消息。当操作员向进程发送 SIGTERM 信号时,它会停止从队列获取新的工作,完成任何未完成的工作,然后终止。在此过程中,消息可以保留在队列中,以便 Python 进程重新启动时使用。这为我们提供了一种使用旧代码关闭服务,并使用新代码启动服务,从而最大限度地减少影响的方法。

注意

等待长时间运行的操作完成(例如,缓慢的卷复制操作)可能需要一段时间。

注意

这使用 RabbitMQ 消息传递后端进行了测试,并且可能因其他后端而异。

数据库升级

Cinder 使用两种类型的数据库升级

  • 模式迁移

  • 数据迁移

模式迁移定义在 cinder/db/migrations/versions 中。它们是转换我们的数据库结构的例程,应该具有累加性,并且能够在服务代码升级之前应用于正在运行的系统。

数据迁移禁止在模式迁移脚本中使用,而是定义在 cinder/db/api.py 中。将它们分开是为了使 DB 模式迁移更容易执行。相反,迁移由后台进程以不会中断正在运行的服务的方式执行(如果你正在执行冷升级,也可以在关闭服务的情况下执行在线数据迁移)。可以使用 cinder-manage db online_data_migrations 工具来实现此目的。在升级 N 到 N+1 之前,你需要在此后台运行此工具,直到它告诉你不再需要任何迁移为止。请注意,在完成 N 的在线数据迁移之前,你将无法应用 N+1 的模式迁移。

有关作为功能或错误修复的一部分开发自己的模式或数据迁移的信息,请参阅 数据库迁移

注意

我们偶尔会收到关于升级过程中由于使用的数据库软件版本过旧而导致数据库问题的报告(例如,参见 Bug #1968746)。

升级在 gate 中使用与任何支持该版本的 Linux 发行版打包的 mysql 或 mariadb 版本进行测试。因此,如果你使用的是旧版本的 mysql 或 mariadb,你可能需要在升级之前进行额外的研究,以确保你不会遇到由于我们使用数据库版本不支持的新功能而导致的问题。

为了帮助你,OpenStack 技术委员会在 基于发布的运行时 页面上维护着每个版本支持的 Linux 发行版的列表。

API 负载均衡器排空

在升级 API 节点时,你可以使负载均衡器仅将新连接发送到较新的 API 节点,从而实现 API 节点的无缝更新。

DB 清理已删除的行

当前,资源在数据库中被软删除,以便用户能够跟踪在生产环境中创建和销毁的实例。但是,大多数人都有数据保留策略,例如 30 天或 90 天,在此之后他们希望删除这些条目。不删除这些条目会影响 DB 性能,因为索引会变得非常大,并且数据迁移需要更长的时间,因为有更多的数据需要迁移。为了使修剪更容易,有一个 cinder-manage db purge <age_in_days> 命令,可以永久删除超过指定年龄的记录。

版本化对象回溯

RPC 固定确保新服务可以与旧服务的 method signatures 进行通信。但是,许多参数都是对象,可能对旧服务来说太新了。Cinder 确保在发送之前将对象回溯到它固定的版本。

最小停机时间升级过程

规划您的升级

  • 阅读并确保你理解下一个版本的发行说明。

  • 备份你的数据库。Cinder 不支持数据库降级。因此,在升级失败的情况下,从备份恢复数据库是唯一的选择。

  • 为了避免依赖地狱,建议将你的 Cinder 服务分别部署在容器或 Python venvs 中。

    注意

    Cinder 基于在 DB 的 services 表中报告的内容来检测版本。在升级之前,请确保你没有在那里有任何孤立的旧记录,因为这些记录可能会阻止启动较新的服务。你可以使用 cinder-manage service remove <binary> <host> 命令清理它们。

请注意,有一个假设是只能在连续版本之间执行实时升级。这意味着你不能直接从 N 升级到 N+2,你需要先升级到 N+1。

假设的服务升级顺序是 cinder-schedulercinder-volumecinder-backup,最后是 cinder-api

滚动升级过程

为了减少停机时间,可以以滚动方式升级服务。这意味着一次升级几个服务。为了最大限度地减少停机时间,你需要具有 HA Cinder 部署,这样当一个服务升级时,你将保持其他服务实例运行。

维护窗口之前

  • 首先,你应该执行所需的 DB 模式迁移。为了在不中断现有安装的情况下实现这一点,请在新 venv 或容器中安装新的 Cinder 代码,然后运行 DB sync (cinder-manage db sync)。这些模式更改操作应该对性能影响最小或没有影响,并且不应导致任何操作失败。

  • 此时,数据库中可能存在新的列和表。这些 DB 模式更改以一种允许 N 和 N+1 版本都对同一模式执行操作的方式完成。

维护窗口期间

  1. 第一个服务是 cinder-scheduler。它通过消息队列进行负载均衡,因此你只需要担心的是使用 SIGTERM 信号优雅地关闭它,以确保它在关闭之前完成所有正在处理的请求。然后你应该升级代码并重新启动该服务。

  2. 对所有 cinder-scheduler 服务重复第一步。

  3. 然后你继续升级 cinder-volume 服务。这里的问题是,由于 cinder-volume 服务的 Active/Passive 特性,你无法同时运行多个 cinder-volume 管理单个卷后端。这意味着在某个时刻你将没有 cinder-volume 部署,并且你希望这种中断尽可能短。

    注意

    只要它不超过服务心跳超时,这里的停机时间就是不破坏性的。如果你不超过该限制,那么 cinder-schedulers 将不会注意到 cinder-volume 消失,并且消息队列将负责排队任何 RPC 消息,直到 cinder-volume 恢复为止。

    为了确保实现这一点,你可以通过调整 cinder.conf 中的 service_down_time 值来延长超时,或者在另一个节点上准备升级的 cinder-volume,并在关闭旧服务后立即启动新服务,从而进行快速切换。

    另外请注意,在 A/P HA 配置中,你需要确保主 cinder-volume 和辅助 cinder-volume 具有相同的 hostname 设置(你可以使用 host 选项在 cinder.conf 中覆盖它),以便它们都监听相同的消息队列并接受相同的消息。

  4. 对所有 cinder-volume 服务重复第三步。

  5. 现在我们应该继续进行(可选的)cinder-backup 服务。你应该以与 cinder-scheduler 相同的方式升级它们。

    注意

    备份操作耗时,因此在不中断正在进行中的请求的情况下关闭 c-bak 服务可能需要时间。禁用该服务(使用 cinder service-disable 命令)可能很有用,这样它就不会接受新的请求,并等待合理的时间,直到所有正在进行中的作业完成。然后你可以继续升级。要确保备份服务完成了所有正在进行中的请求,你可以检查服务日志。

    注意

    直到 Liberty,cinder-backup 与 cinder-volume 服务紧密耦合,需要在同一物理节点上共存。从 Mitaka 版本开始,情况不再如此。如果你仍然保持这种耦合,那么 cinder-backup 的升级策略应该更类似于 cinder-volume 的升级方式。

  6. cinder-api 服务应该最后进行。在 HA 部署中,你通常在负载均衡器(例如 HAProxy)后面运行它们,因此你需要将一个服务实例从负载均衡器中移除,关闭它,升级代码和依赖项,然后启动该服务。然后你可以将其重新插入负载均衡器。

    注意

    你可能希望启动另一个旧的 c-api 实例来处理负载,同时你正在升级你的原始服务。

  7. 然后你应该对所有 cinder-api 服务重复步骤 6。

维护窗口之后

  • 一旦所有服务都运行了新代码,请在 DB 中双重检查,确保 services 表中没有旧的孤立记录(Cinder 不会在服务消失或服务 hostname 更改时删除记录,因此你需要手动处理;你可以通过查看记录的更新时间来区分死记录)。Cinder 基于此进行 RPC 版本检测,因此过时的记录可能会阻止你继续前进。

  • 现在所有服务都已升级,我们需要发送 SIGHUP 信号,以便所有服务清除任何缓存的服务版本数据。当新服务启动时,它会自动检测要使用的服务 RPC 协议的版本,并将任何通信降级到该版本。请注意,cinder-api 服务不处理 SIGHUP,因此需要重新启动它。最好将 cinder-api 服务作为最后的服务重新启动,这样可以确保 API 在用户请求新功能时快速失败(新功能可能在 RPC 消息回溯到最低公共分母时失败)。其余服务的顺序无关紧要。

  • 现在所有服务都已升级,该系统能够使用最新版本的 RPC 协议并访问新版本的全部功能。

  • 此时,你还必须确保更新配置,以停止使用任何已弃用的功能或选项,并执行任何必要的工作以过渡到替代功能。所有已弃用的选项都应在一个周期内得到支持,但在执行下一次升级之前应将其删除。

  • 从 Ocata 开始,你还需要运行 cinder-manage db online_data_migrations 命令,以确保应用数据迁移。该工具允许你使用 --max_count 选项限制一次执行的迁移数量,从而限制数据迁移的影响。如果使用此选项,即使其他迁移生成错误(这可能是由于迁移之间的依赖关系),如果任何迁移都成功,则退出状态将为 1。应在退出状态为 1 时重新运行该命令。如果不再可能进行进一步的迁移,则如果仍有一些迁移生成错误,则退出状态将为 2,这需要干预才能解决。只有在退出状态为 0 时,该命令才应被认为已成功完成。在开始升级到下一个版本之前,你需要完成所有迁移(例如,你需要完成 Ocata 的数据迁移才能继续升级到 Pike;在完成 Ocata 的数据迁移之前,你将无法执行 Pike 的 DB 模式迁移)。