properties:
- type: olm.kubeversion
value:
version: "1.16.0"
Operator Lifecycle Manager (OLM) 管理运行中的 Operator 的依赖项解析和升级生命周期。在许多方面,OLM 面临的问题与其他系统或语言包管理器(如 `yum` 和 `rpm`)类似。
但是,OLM 有一种类似系统通常没有的约束:因为 Operator 始终运行,所以 OLM 尝试确保您永远不会留下无法相互协作的 Operator 集。
因此,OLM 绝不能创建以下场景
安装需要无法提供的 API 的 Operator 集
以破坏依赖它的另一个 Operator 的方式更新 Operator
这可以通过两种类型的数据实现
属性 |
构成 Operator 在依赖项解析器中的公共接口的关于 Operator 的类型化元数据。示例包括 Operator 提供的 API 的组/版本/种类 (GVK) 和 Operator 的语义版本 (semver)。 |
约束或依赖项 |
Operator 的要求,这些要求应由可能已安装或可能尚未安装在目标集群上的其他 Operator 满足。它们充当对所有可用 Operator 的查询或过滤器,并在依赖项解析和安装期间约束选择。示例包括要求集群上提供特定 API 或期望安装具有特定版本的特定 Operator。 |
OLM 将这些属性和约束转换为布尔公式系统,并将其传递给 SAT 求解器(一个建立布尔可满足性的程序),该程序负责确定应安装哪些 Operator。
目录中的所有 Operator 都有以下属性
olm.package
包含包的名称和 Operator 的版本
olm.gvk
来自集群服务版本 (CSV) 的每个提供的 API 的单个属性
操作符作者还可以通过在 Operator 包的 `metadata/` 目录中包含 `properties.yaml` 文件来直接声明其他属性。
properties:
- type: olm.kubeversion
value:
version: "1.16.0"
操作符作者可以在 Operator 包的 `metadata/` 目录中的 `properties.yaml` 文件中声明任意属性。这些属性被转换为地图数据结构,在运行时用作 Operator Lifecycle Manager (OLM) 解析器的输入。
这些属性对于解析器是不透明的,因为它不理解这些属性,但它可以根据这些属性评估通用约束,以确定在给定属性列表的情况下是否可以满足这些约束。
properties:
- property:
type: color
value: red
- property:
type: shape
value: square
- property:
type: olm.gvk
value:
group: olm.coreos.io
version: v1alpha1
kind: myresource
此结构可用于为通用约束构建通用表达式语言 (CEL) 表达式。
Operator 的依赖项列在包的 `metadata/` 文件夹中的 `dependencies.yaml` 文件中。此文件是可选的,目前仅用于指定显式 Operator 版本依赖项。
依赖项列表为每个项目包含一个 `type` 字段,以指定这是什么类型的依赖项。支持以下类型的 Operator 依赖项
olm.package
此类型表示对特定 Operator 版本的依赖关系。依赖信息必须包括包名和包的语义版本(semver)格式的版本。例如,您可以指定精确版本,例如0.5.2
,或版本范围,例如>0.5.1
。
olm.gvk
使用此类型,作者可以指定具有组/版本/种类 (GVK) 信息的依赖项,类似于 CSV 中现有的基于 CRD 和 API 的用法。这是为了让 Operator 作者能够将所有依赖项(API 或显式版本)集中到同一位置。
olm.constraint
此类型声明对任意 Operator 属性的通用约束。
在下面的示例中,为 Prometheus Operator 和 etcd CRD 指定了依赖项
dependencies.yaml
文件dependencies:
- type: olm.package
value:
packageName: prometheus
version: ">0.27.0"
- type: olm.gvk
value:
group: etcd.database.coreos.com
kind: EtcdCluster
version: v1beta2
一个olm.constraint
属性声明特定类型的依赖约束,区分非约束属性和约束属性。它的value
字段是一个对象,包含一个failureMessage
字段,其中包含约束消息的字符串表示。如果运行时无法满足约束,则此消息将作为信息性注释显示给用户。
以下键表示可用的约束类型
gvk
其值和解释与olm.gvk
类型相同的类型
package
其值和解释与olm.package
类型相同的类型
cel
Operator 生命周期管理器 (OLM) 解析器在运行时对任意 bundle 属性和集群信息进行评估的通用表达式语言 (CEL) 表达式
all
、any
、not
分别表示合取、析取和否定约束,包含一个或多个具体约束,例如gvk
或嵌套的复合约束
cel
约束类型支持通用表达式语言 (CEL)作为表达式语言。cel
结构体具有一个rule
字段,该字段包含在运行时针对 Operator 属性进行评估以确定 Operator 是否满足约束的 CEL 表达式字符串。
cel
约束type: olm.constraint
value:
failureMessage: 'require to have "certified"'
cel:
rule: 'properties.exists(p, p.type == "certified")'
CEL 语法支持广泛的逻辑运算符,例如AND
和OR
。因此,单个 CEL 表达式可以具有针对多个条件的多个规则,这些规则通过这些逻辑运算符链接在一起。这些规则针对来自 bundle 或任何给定源的多个不同属性的数据集进行评估,并将输出解决为满足单个约束内所有这些规则的单个 bundle 或 Operator。
cel
约束type: olm.constraint
value:
failureMessage: 'require to have "certified" and "stable" properties'
cel:
rule: 'properties.exists(p, p.type == "certified") && properties.exists(p, p.type == "stable")'
复合约束类型按照其逻辑定义进行评估。
以下是一个包含两个包和一个 GVK 的合取约束 (all
) 的示例。也就是说,已安装的 bundle 必须全部满足这些约束。
all
约束schema: olm.bundle
name: red.v1.0.0
properties:
- type: olm.constraint
value:
failureMessage: All are required for Red because...
all:
constraints:
- failureMessage: Package blue is needed for...
package:
name: blue
versionRange: '>=1.0.0'
- failureMessage: GVK Green/v1 is needed for...
gvk:
group: greens.example.com
version: v1
kind: Green
以下是一个包含同一 GVK 的三个版本的析取约束 (any
) 的示例。也就是说,已安装的 bundle 必须至少满足其中一个约束。
any
约束schema: olm.bundle
name: red.v1.0.0
properties:
- type: olm.constraint
value:
failureMessage: Any are required for Red because...
any:
constraints:
- gvk:
group: blues.example.com
version: v1beta1
kind: Blue
- gvk:
group: blues.example.com
version: v1beta2
kind: Blue
- gvk:
group: blues.example.com
version: v1
kind: Blue
以下是一个包含 GVK 的一个版本的否定约束 (not
) 的示例。也就是说,任何 bundle 都不能在结果集中提供此 GVK。
not
约束schema: olm.bundle
name: red.v1.0.0
properties:
- type: olm.constraint
value:
all:
constraints:
- failureMessage: Package blue is needed for...
package:
name: blue
versionRange: '>=1.0.0'
- failureMessage: Cannot be required for Red because...
not:
constraints:
- gvk:
group: greens.example.com
version: v1alpha1
kind: greens
在not
约束上下文中,否定语义可能显得不清楚。为了澄清,否定实际上是在指示解析器删除结果集中包含特定 GVK、特定版本的包或满足某些子复合约束的任何可能的解决方案。
作为推论,not
复合约束应该只在all
或any
约束中使用,因为在不首先选择可能的依赖项集合的情况下进行否定是没有意义的。
嵌套复合约束(包含至少一个子复合约束以及零个或多个简单约束)自下而上地进行评估,遵循前面描述的每种约束类型的过程。
以下是一个合取的析取示例,其中一个、另一个或两者都可以满足约束。
schema: olm.bundle
name: red.v1.0.0
properties:
- type: olm.constraint
value:
failureMessage: Required for Red because...
any:
constraints:
- all:
constraints:
- package:
name: blue
versionRange: '>=1.0.0'
- gvk:
group: blues.example.com
version: v1
kind: Blue
- all:
constraints:
- package:
name: blue
versionRange: '<1.0.0'
- gvk:
group: blues.example.com
version: v1beta1
kind: Blue
|
可能有很多选项同样满足 Operator 的依赖关系。Operator 生命周期管理器 (OLM) 中的依赖关系解析器确定哪个选项最符合请求的 Operator 的要求。作为 Operator 作者或用户,了解这些选择的做出方式非常重要,以便依赖关系解析清晰明了。
在 Red Hat OpenShift Service on AWS 集群上,OLM 读取目录源以了解哪些 Operator 可用于安装。
CatalogSource
对象apiVersion: "operators.coreos.com/v1alpha1"
kind: "CatalogSource"
metadata:
name: "my-operators"
namespace: "operators"
spec:
sourceType: grpc
grpcPodConfig:
securityContextConfig: <security_mode> (1)
image: example.com/my/operator-index:v1
displayName: "My Operators"
priority: 100
1 | 指定legacy 或restricted 的值。如果未设置此字段,则默认值为legacy 。在未来的 Red Hat OpenShift Service on AWS 版本中,计划将默认值设置为restricted 。如果您的目录无法使用restricted 权限运行,建议您手动将此字段设置为legacy 。 |
CatalogSource
对象具有一个priority
字段,解析器使用该字段来了解如何优先选择依赖项的选项。
有两条规则控制目录偏好
优先级较高的目录中的选项优先于优先级较低的目录中的选项。
与被依赖项位于同一目录中的选项优先于任何其他目录中的选项。
目录中的 Operator 包是用户可以在 Red Hat OpenShift Service on AWS 集群中订阅的更新通道的集合。通道可用于为次要版本 (1.2
、1.3
) 或发布频率 (stable
、fast
) 提供特定的更新流。
依赖项很可能由同一包中但不同通道中的 Operator 满足。例如,Operator 的版本1.2
可能同时存在于stable
和fast
通道中。
每个包都有一个默认通道,它总是优先于非默认通道。如果默认通道中的任何选项都不能满足依赖关系,则会按照通道名称的字典顺序考虑剩余通道中的选项。
在一个通道内,几乎总是有多种选项可以满足依赖关系。例如,一个包和通道中的多个Operator提供相同的API集。
当用户创建订阅时,他们会指定要接收更新的通道。这会立即将搜索范围缩小到该通道。但在通道内,许多Operator都可能满足依赖关系。
在一个通道内,更新图中位置越高的较新的Operator优先。如果通道的头部满足依赖关系,则会首先尝试它。
除了包依赖项提供的约束之外,OLM还包含其他约束,以表示所需的使用者状态并强制执行解析不变式。
如果自定义资源定义 (CRD) 由单个集群服务版本 (CSV) 拥有,则OLM会立即升级它。如果CRD由多个CSV拥有,则当它满足以下所有向后兼容条件时,才会升级CRD。
当前CRD中的所有现有服务版本都存在于新的CRD中。
与CRD的服务版本关联的所有现有实例或自定义资源在针对新CRD的验证模式进行验证时都是有效的。
在指定依赖项时,应考虑一些最佳实践。
Operator可以随时添加或删除API;始终对Operator所需的任何API指定olm.gvk
依赖项。例外情况是,如果您指定了olm.package
约束。
Kubernetes关于API更改的文档描述了允许对Kubernetes风格的Operator进行哪些更改。这些版本控制约定允许Operator更新API而无需更改API版本,只要API向后兼容即可。
对于Operator依赖项,这意味着仅知道依赖项的API版本可能不足以确保依赖Operator按预期工作。
例如
TestOperator v1.0.0 提供MyObject
资源的v1alpha1 API版本。
TestOperator v1.0.1 向MyObject
添加了一个新字段spec.newfield
,但仍然是v1alpha1。
您的Operator可能需要能够将spec.newfield
写入MyObject
资源。仅靠olm.gvk
约束不足以让OLM确定您需要TestOperator v1.0.1而不是TestOperator v1.0.0。
如果提前知道提供API的特定Operator,则尽可能指定额外的olm.package
约束以设置最小值。
因为Operator提供集群范围的资源(如API服务和CRD),所以指定依赖项的小窗口的Operator可能会不必要地限制其他依赖项使用者的更新。
尽可能不要设置最大版本。或者,设置一个非常宽的语义范围以防止与其他Operator发生冲突。例如,>1.0.0 <2.0.0
。
与传统的包管理器不同,Operator作者在OLM中通过通道明确地编码更新是安全的。如果现有订阅有可用的更新,则假定Operator作者表示它可以从以前的版本更新。为依赖项设置最大版本会通过不必要地将其截断在特定上限来覆盖作者的更新流。
集群管理员无法覆盖Operator作者设置的依赖项。 |
但是,如果必须避免已知的冲突,则可以并且应该设置最大版本。可以使用版本范围语法省略特定版本,例如> 1.0.0 !1.2.1
。
Kubernetes文档:更改API
在指定依赖项时,应考虑一些注意事项。
目前没有方法可以指定约束之间的AND关系。换句话说,无法指定一个Operator依赖于另一个既提供给定API又具有版本>1.1.0
的Operator。
这意味着,当指定如下依赖项时
dependencies:
- type: olm.package
value:
packageName: etcd
version: ">3.1.0"
- type: olm.gvk
value:
group: etcd.database.coreos.com
kind: EtcdCluster
version: v1beta2
OLM可能使用两个Operator来满足此依赖项:一个提供EtcdCluster,另一个版本为>3.1.0
。这是否会发生,或者是否选择满足两个约束的Operator,取决于访问潜在选项的顺序。依赖项偏好和排序选项是明确定义的,可以进行推理,但为了谨慎起见,Operator应该坚持使用一种或另一种机制。
OLM在命名空间范围内执行依赖项解析。如果在一个命名空间中更新Operator会影响另一个命名空间中的Operator,反之亦然,则可能会导致更新死锁。
在以下示例中,提供者是指“拥有”CRD或API服务的Operator。
A和B是API(CRD)
A的提供者依赖于B。
B的提供者有订阅。
B的提供者更新为提供C,但弃用B。
这将导致
B不再有提供者。
A不再工作。
这是OLM通过其升级策略阻止的一种情况。
A和B是API
A的提供者需要B。
B的提供者需要A。
A的提供者更新为(提供A2,需要B2)并弃用A。
B的提供者更新为(提供B2,需要A2)并弃用B。
如果OLM尝试更新A而不同时更新B,反之亦然,则它将无法升级到Operator的新版本,即使可以找到新的兼容集。
这是OLM通过其升级策略阻止的另一种情况。