KubeBlocks for Oracle 容器化之路

引言
Oracle Data Guard
Oracle Data Guard (简称 DG) 是 Oracle 提供的一种高可用性和灾难恢复解决方案。它提供一整套服务,用于维护、管理和监控一个或多个备用数据库,使 Oracle 数据库能够抵御灾难和数据损坏。DG 将这些备用数据库作为生产数据库的副本进行维护。当生产数据库因计划内或计划外中断而不可用时,DG 可将任一备用数据库切换至生产角色,从而最大限度地减少中断导致的停机时间。
KubeBlocks
KubeBlocks 是一款支持多引擎管理的开源 Operator,通过统一的代码和 API 集成在 K8s 上运行并管理多种数据库引擎,只需编写 KubeBlocks 的 Addon 即可为其添加新引擎。KubeBlocks 的核心是一个 K8s Operator,定义了一组 CR 来抽象各类数据库引擎的通用属性,并利用这些抽象来管理引擎的生命周期及日常运维操作。
容器化现状与挑战
Oracle 官方在容器化方向已经做出了一些努力,提供了从 11g 到 23ai free 版本的镜像,同时还开源了官方的 Oracle Database Operator。然而其在 K8s 上的部署和管理仍然存在一些局限性:
功能支持不完善:相较于传统物理机环境,Oracle 在容器化环境中支持的功能有限,例如备份恢复、日志管理,配置变更、监控告警等功能支持并不完善。
运维复杂度高:缺乏统一的运维工具和管理界面,使得运维人员需要在多个工具之间切换,大量运维工作需要手动完成,增加了运维的复杂度。
版本支持有限:目前官方提供的镜像版本有限,且许多 Feature 都只针对新版本进行开发和测试验证,对仍有大量用户使用的老版本支持不足。
以 Oracle 12c 版本为例,尽管其在传统环境中的部署和运维已经相当成熟,但迁移到容器化环境中仍需克服诸多问题:
集群拓扑:DG 集群拓扑相对复杂,涉及到 Oracle 和 Observer 多个节点之间的通信和数据同步,这在容器化环境中需要特别注意网络配置和持久化存储。
多副本管理:DG 集群中通常包含一主多备多个数据库副本,副本间的数据同步,启动顺序,角色切换等各个环节都会影响集群的正常服务,在容器化环境中需要确保这些副本能够正确运行至关重要。
配置管理:传统环境中,Oracle 会通过感知物理机的资源来调整配置,而在容器化环境中,老版本 Oracle 可能无法感知容器的资源限制,导致配置不合理。
故障转移:容器化环境中,故障转移的策略和传统环境有所不同,需要确保在容器可能发生故障的各个场景下,能够快速、准确地进行故障转移,保证服务的连续性。
针对上述现状与挑战,本文将依托 KubeBlocks 提供的能力,展示 KubeBlocks 如何解决这些使用上的痛点,并探讨 Oracle 数据库容器化过程中的一些细节,理解 KubeBlocks 以及 Addon 的设计思路和实现机制。
部署与运维示例
首先用一个实际操作示例,本文会展示创建一个 Oracle 12c DG 集群以及一些运维操作的过程,示例集群架构如下:

创建集群
使用 kubectl apply 如下的 Cluster yaml 即可创建一个一主两备加上两个 Observer 节点的集群:
可以看到上述 Cluster 中,指定了这个集群的组成部分以及一些相关定义,相信即使是之前没有了解过 KubeBlocks 的读者也能通过 API 字面表述对创建的这个集群的有一个较为直观的印象(后文会对部分关键 API 字段做出详细解析)。在应用后一个完整的 Oracle 12c DG 集群就被创建出来了,查看集群和 pod 的状态:


可以发现,observer 相关的 pod 没有角色,而 oracle 相关的 pod 被设置成 primary 或者 secondary。角色在 KubeBlocks 管理的有状态集群中非常重要,其不仅代表数据库实例之间的复制关系,也代表着 KubeBlocks 对这种关系的一种抽象,这种关系会直接影响 KubeBlocks 在各类运维操作中的行为预期。
配置变更
使用 sqlplus 查看 Oracle 参数open_cursors
,发现值为 300

使用 kubectl apply 应用如下 OpsRequest 的 yaml:
再次查看参数open_cursors
,发现值成功改为 301

Fast-Start Failover
Oracle 的 Fast-Start Failover 特性允许在主库故障的情况下自动故障转移到备库,以便快速可靠地恢复业务。通过删除 pod 模拟节点故障,查看 Oracle 备节点是否自动提升为主节点。例如删除当前主节点 my-oracle-oracle-0,几秒后,my-oracle-oracle-1 角色变为 primay,而 my-oracle-oracle-0 以 secondary 的角色重新加入集群。

在这个过程中,KubeBlocks 会持续保持对 Oracle 的角色探测,以保证服务集群状态快速恢复并正常对外服务。
除此之外,KubeBlocks 还为支持的数据库借助 Chaos Mesh 设计多种不同的异常场景,以验证数据库的高可用性,具体可参见:通过 Chaos Mesh 验证 KubeBlocks Addon 可用性的实践。
备份恢复
备份是保障数据的关键。在 KubeBlocks 中,通过预先定义的备份方法,只需应用如下 yaml,即可创建一个全量备份:
这将会调用 Oracle 的 rman 工具对当前集群进行全量备份,并将得到的备份上传到指定的存储中。
查看备份如下:

得到这个完整的备份后,可基于该备份恢复一个全新的集群,同样只需一个简单的 yaml:
查看恢复集群的状态:

这样就可以完成备份恢复操作,同时还可以定义备份的频率,时间等策略。
其他运维操作
接入 KubeBlocks 后,Oracle Addon 还天然支持了很多其他的运维操作。除上述介绍的自动故障转移、配置变更和备份恢复之外,还支持以下运维操作:
Observer 水平扩容,可以增加或减少 Observer 节点的数量
垂直扩容
存储扩容
手动主备切换(switchover)
集群重启、停止和删除
小版本升级
监控(配置 Prometheus exporter 采集指标)
Oracle Addon 实现
这样一个完整的 Addon 是如何实现的呢?下面将会详细介绍部分 API,帮助理解原理以及设计思路,读者可以结合这部分与运维示例一起阅读,更详细的 API 解读可以直接查看 KubeBlocks 源码中的 API 注释部分。
KubeBlocks 与 Addon 机制
KubeBlocks 通过 Addon 机制,可以方便地扩展其功能,支持多种数据库和中间件。详细文档可以参考:KubeBlocks Addon文档
Oracle Addon
KubeBlocks 提供了一组抽象的 API,用于定义和管理数据库实例。Oracle Addon 则是基于这些 API,为 Oracle DG 集群提供了一套完整的解决方案。
集群管理
Oracle Addon 主要通过 3 个 CR 来定义集群纬度的生命周期管理和运维:
ComponentDefinition:简称 CMPD,用于定义数据库集群中一个基本组成部分。在 KubeBlocks 管理的数据库集群中,通常会把集群中的各个基本组件称为 Component。例如在 Oracle DG 集群中,就可以分为 Oracle 和 Observer 两个基本组件,因此需要借助两个 CMPD 来定义这两个组件。
ComponentVersion:简称 CMPV,用于定义 Component 的具体版本,例如 Oracle-12c 和 Oracle-19c 等。
ClusterDefinition:简称 CD,用于定义数据库集群的拓扑结构和组件之间的关系。比如在 Oracle DG 集群中,单机集群只需要 Oracle 一个组件,而主备集群则需要 Oracle 和 Observer 两个组件,因此需要借助 CD 来定义集群的拓扑结构。
在上述 3 个 CR 中,最重要也是最复杂的 CR 是 CMPD,就像使用乐高积木搭建模型一样,只要有了基本的积木(Component),就可以搭建出各种复杂的模型(Cluster)。
Oracle 的 CMPD 主要包括以下几个部分:
roles:定义了 Oracle 的角色,例如主库(Primary)和备库(Secondary)以及角色对应的读写能力。
service:定义了 Oracle 的对外提供服务的方式,可以通过 roles 区分只读服务和读写服务,实现读写分离。
systemAccounts:定义了 Oracle 的系统账户和初始密码,在 systemAccounts 中,可以自定义密码的生成策略,包括长度,复杂度等,Kubeblocks 会将生成的账号密码存入到 Secret 中,供 Oracle 引用。
scripts:指定脚本的 ConfigMap,KubeBlocks 会将其挂载到容器中的指定目录。
vars: 用于引用一些跟实例相关的动态资源和信息,例如 systemAccounts 中定义的账号
ORACLE_SYS_USER
,密码ORACLE_SYS_PASSWORD
,以及整个集群中 Oracle 所有副本的连接串ALL_ORACLE_FQDN
。基于上述 vars,就可以完成 Oracle 的 TNS 以及监听器等相关配置。lifecycleActions:定义一些生命周期管理相关的动作,Oracle 实现了三个 Action:
roleProbe:用于探测副本角色
postProvision:用于在实例初始化完成后执行一些自定义脚本,例如 Oracle 主备实例都创建完成以后执行 DG Broker 的配置。
switchover:用于执行主备切换操作。
runtime:定义容器运行时相关的配置,包括三个容器:
oracle-init-container:完成 Oracle 的数据目录的权限设置
oracle:Oracle 服务运行容器
exporter:用于采集数据库的监控指标
除上述显式定义的容器外,KubeBlocks 还会为每个 Pod 注入两个 sidecar 容器,即 lorry:用于执行 roleProbe 等部分 lifecycleActions;config-manager:用于管理配置文件和执行配置变更。
在完成上述核心配置以及一些相关配置后,一个完整的 Oracle 组件就定义完成了。对于 Observer 组件,同样按照上述方式定义即可。在两个组件都定义完成后,就可以通过 CD 完成整个集群的完整拓扑。
DG 配置
在 Oracle Addon 中如何完成 DG 集群中主备节点间的配置呢。其中,节点自身初始化相关的逻辑都在 Oracle 的启动脚本中完成。一开始会先根据集群的规格,配置等信息执行一些通用的初始化操作,例如调整根据实例规格调整内核参数,设置监听,配置 TNS 等。接着会根据节点的角色执行不同的操作: 如果是主节点,会使用 DBCA 工具创建数据库,而如果是备节点,则会使用 RMAN 工具从主节点恢复数据库。
在主备节点都设置完成后,则会依托前文提到的 postProvision 这个 lifecycleAction 来完成主备节点间的 DG Broker 配置,创建并启用 DG Broker 的 Configuration,此时 Oracle 这个 Component 就已经搭建完成了。
最后 KubeBlocks 会根据在 CD 中配置的 Order 创建 Observer 这个 Component,为集群配置 Fast-Start Failover(FSFO),整个集群才算创建完成。
此时集群就具备了高可用性,当主节点发生故障时,Observer 会发现异常并触发 Failover,将备节点提升为主节点,从而保证业务的连续性。
参数配置
KubeBlocks 为了方便对各种数据库的参数进行管理,定义了参数配置相关的 API:
参数模板:定义一个参数模板, 这个模板中可以定义具体的参数数值,也可以根据 Go Template 和 KubeBlocks 提供的内置函数配置参数的计算规则,从而根据实例规格动态计算出最适合的参数值,
ConfigConstraint:即参数的约束,参数的约束主要包含三部分:
支持的配置文件格式:例如 yaml, toml, ini 等。
参数的类型和取值范围: KubeBlocks 使用 CUE 文件来描述参数的类型和取值范围。
参数的生效范围:参数可以被划分为动态参数、静态参数和不可变参数。动态参数可以被修改并立即生效,静态参数需要重启实例才能生效,不可变参数一旦设置就不能被修改。
Oracle 主要使用 pfile 和 spfile 来配置数据库参数,为了方便用户进行配置,Oracle Addon 将 pfile 中的部分参数设置到 KubeBlocks 的参数模板中,在实例启动后,会根据这个动态渲染出的 pfile 再生成 spfile。
备份恢复
备份恢复是数据库运维中的重要环节,KubeBlocks 为各种数据库提供了灵活的备份相关 API 以实现不同的备份恢复机制,包括全量备份、增量备份、基于时间点恢复等。Addon 只需实现以下两个 API:
BackupPolicyTemplate:即备份策略的模板,用于定义指定组件的备份策略,创建数据库集群时会根据该模板生成集群的备份策略。包括备份方法,默认备份调度周期,默认的备份目标。
ActionSet:定义不同数据库使用的具体备份方法,可以在这个 API 中实现实际的备份行为。
以 Oracle Addon 中实现的全量备份为例,定义了一个名为oracle-rman
的 ActionSet,该 ActionSet 的 backupType 为Full
,表示这是一个全量备份。接着定义了一个名为oracle-backup-policy-template
的 BackupPolicyTemplate,该模板指定了使用oracle-rman
ActionSet 进行全量备份,并通过 Cron 表达式设置了默认的备份调度周期。借助这些定义,KubeBlocks 能够自动化地执行备份,并将这些备份上传到指定的存储位置,这些目的存储位置可以是本地存储,也可以是云存储服务,如 AWS S3 等。
总结展望
在 K8s 环境中想要稳定高效地运行 Oracle 集群不是一件简单的事,但是 KubeBlocks 为其提供了一条见解且行之有效的路径。本文详细介绍了基于 KubeBlocks 这个 Operator 支持 Oracle Addon 的细节,并介绍了其支持的功能和优势,目前,KubBlocks for Oracle 已经上线 KubeBlocks 企业版,欢迎感兴趣的读者申请体验。
之后我们会持续优化迭代 KubBlocks for Oracle,以支持更多功能并提升稳定性,同时还会增加支持的 Oracle 版本,使 KubBlocks for Oracle 成为更多企业级用户的不二之选。
评论