跳转到主要内容

"Kubernetes manifests for Operators"

项目描述

ops-lib-manifests

此库的原理

大多数Kubernetes项目使用manifest文件进行部署,这些文件推荐了部署参数,但这些manifest文件在哪些选项是必需的以及哪些选项是可变的方面并不一致。在某些情况下,项目的发行版使用不同的方式来指示需要替换。

例如,以下来自vsphere-cloud-controller-manager的引用向yaml的消费者表明,应在Secret对象中设置用户名和密码。

apiVersion: v1
kind: Secret
metadata:
  name: vsphere-cloud-secret
  labels:
    vsphere-cpi-infra: secret
    component: cloud-controller-manager
  namespace: kube-system
  # NOTE: this is just an example configuration, update with real values based on your environment
stringData:
  10.0.0.1.username: "<ENTER_YOUR_VCENTER_USERNAME>"
  10.0.0.1.password: "<ENTER_YOUR_VCENTER_PASSWORD>"
  1.2.3.4.username: "<ENTER_YOUR_VCENTER_USERNAME>"
  1.2.3.4.password: "<ENTER_YOUR_VCENTER_PASSWORD>"

自动化工具(如juju charm)需要读取这些yaml manifest文件,操作其内容,并在任何可配置数据更改时部署这些manifest文件。

支持多个版本

同样,发布引用清单文件的项目也将发布清单版本。一个 charm 可以将所有支持的清单文件加载到一个文件夹结构中,以便支持多个版本。这个库通过将 charm 存储上游清单文件保持不变的方式,支持这一要求,如下所示:

<base_path>
├── version                  - a file containing the default version
├── manifests                - a folder containing all the releases
│   ├── v1.1.10              - a folder matching a configurable version
│   │   ├── manifest-1.yaml  - any file with a `.yaml` file type
│   │   └── manifest-2.yaml
│   ├── v1.1.11
│   │   ├── manifest-1.yaml
│   │   └── manifest-2.yaml
│   │   └── manifest-3.yaml

关键文件层次结构要求

$base_path 单个 charm 可以支持多个清单发布
version 一个文本文件,指示当 'release' 配置未指定时,库应该将哪个清单版本作为默认版本
manifests 一个包含单个发布清单文件夹的文件夹
$release 一个包含特定发布 yaml 文件的文件夹

示例用法

一旦您的 charm 包含上述清单文件层次结构,您的 charm 需要定义库应对清单进行的变更。

from ops.manifests import Collector, Manifests, ManifestLabel, ConfigRegistry

class ExampleApp(Manifests):
    def __init__(self, charm, charm_config):
        manipulations = [
            ManifestLabel(self),
            ConfigRegistry(self),
            UpdateSecret(self),
        ]
        super().__init__("example", charm.model, "upstream/example", manipulations)
        self.charm_config = charm_config

    @property
    def config(self) -> Dict:
        """Returns config mapped from charm config and joined relations."""
        config = dict(**self.charm_config)

        for key, value in dict(**config).items():
            if value == "" or value is None:
                del config[key]  # blank out keys not currently set to something

        config["release"] = config.pop("example-release", None)
        return config

    def is_ready(self, obj, condition) -> bool:
        """Filter conditions by object and condition."""
        if (
            obj.kind == "Deployment" and
            obj.name == "MyDeployment" and
            condition.type == "Ignored"
        ):
            return None  # ignore this condition
        return super().is_ready(obj, condition)


class ExampleCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)

        # collection of ManifestImpls
        self.collector = Collector(ExampleApp(self, self.config))

        # Register actions callbacks
        self.framework.observe(self.on.list_versions_action, self._list_versions)
        
        # Register update status callbacks
        self.framework.observe(self.on.update_status, self._update_status)
    
    def _list_versions(self, event):
        self.collector.list_versions(event)

    def _update_status(self, _):
        unready = self.collector.unready
        if unready:
            self.unit.status = WaitingStatus(", ".join(unready))
        else:
            self.unit.status = ActiveStatus("Ready")
            self.unit.set_workload_version(self.collector.short_version)
            self.app.status = ActiveStatus(self.collector.long_version)
        

清单

这个类提供了以下功能

  1. 与 lightkube 集成以创建/读取/更新/删除集群中的资源
  2. 提供选择清单发布的方法
  3. 从特定于发布的已知文件层次结构中加载清单文件
  4. 操作特定发布的资源对象
  5. 提供已安装资源和预期资源之间的比较
  6. 提供可用发布的用户列表

创建清单实现

预期开发者创建一个 Manifest 实现 -- 一个派生类 -- 实现一个属性 -- config。这个属性为 Manifest 父类提供一些基本要求,并为每个定制的 Manipulation 提供上下文,以便在关系或配置数据上操作。

    @property
    def config(self) -> Dict:
        """Returns config mapped from charm config and joined relations."""

预期的 config 键映射

  • release
    • 可选的 str,用于标识要选择的清单版本。
    • 默认为 None,如果可用,将选择 default_release
    • 如果没有找到 default_release,则选择最新的发布。
  • image-registry
    • 可选的 str,将被 ConfigRegistry 操作使用。
    • 默认为 None,使用资源内置的注册位置。
    • 如果指定,将替换第一个 / 之前的文本内容。

集群 CRUD 方法

  • status()
    • 查询与当前发布关联的所有集群资源,这些资源具有 .status.conditions 属性。
  • installed_resources()
    • 查询与当前发布关联的所有已安装的集群资源。
  • labelled_resources()
    • 查询与 charm 和清单关联的一般安装的集群资源。
    • 这可以通过比较 resources 属性来查找不再必要的额外资源。
  • apply_manifests()
    • 将当前发布的所有资源应用到集群中。
    • 资源被强制应用,覆盖现有资源。
  • apply_resources(*resources)apply_resource(...)
    • 将列出的资源应用到集群中。
    • 资源被强制应用,覆盖现有资源。
  • delete_manifests(...)
    • 将从集群中删除所有当前发布的资源
    • 有关关键字参数,请参阅 delete_resources
  • delete_resources(...)
    • 从集群中删除指定资源集,并带有处理某些失败选项的选项。
  • delete_resource(...)
    • 当阅读清晰度要求仅删除一个资源时,是 delete_resources 的别名。

收集器

这个类为单个 charm 内的清单提供原生的集合操作。它提供了响应以下操作的方法:

  • action list-versions
  • action scrub-resources
  • action list-resources
  • action apply-missing-resources
  • 查询集体版本(短类型和长类型)
  • 列出具有非活动状态的资源

要集成到 ops charm 中,对于 charm 管理的每个已发布应用程序,创建一个新的 Manifests 实现,并将其实例添加到 Collector 中。

class AlternateApp(Manifests):
    def __init__(self, charm, charm_config):
        super().__init__("alternate", charm.model, "upstream/example")
        self.charm_config = charm_config


    @property
    def config(self) -> Dict:
        """Returns config mapped from charm config and joined relations."""
        config = dict(**self.charm_config)

        for key, value in dict(**config).items():
            if value == "" or value is None:
                del config[key]  # blank out keys not currently set to something

        config["release"] = config.pop("alternate-release", None)
        return config


class ExampleCharm(CharmBase):
    def __init__(self, *args):
        ...
        # collection of ManifestImpls
        self.collector = Collector(
            ExampleApp(self, self.config), 
            AlternateApp(self, self.config),
        )

操作

修补清单资源

一些资源已在清单中存在,只需更新。

内置补丁程序

  • ManifestLabel

    • 将以下内容添加到每个资源的 metadata.labels
      1. juju.io/application: manifests.app_name
      2. juju.io/manifest: manifests.name
      3. juju.io/manifest-version: <manifests.name>-<version>
  • 配置注册表

    • 从配置属性 Dict 中的 image-registry 配置项更新每个 PodDaemonSetDeploymentStatefulSet 的镜像注册表。
    • 如果魅力不想更改配置,请确保 image-registry 中不存在任何内容。
  • update_toleration

    • 不是官方补丁程序,但可以被自定义补丁程序用来调整 PodDaemonSetDeploymentStatefulSet 资源上的容忍度。

添加清单资源

某些资源不在发布清单中,必须添加。在应用其他 Patch 操作之前,添加 Addition 操作。

内置添加器

  • CreateNamespace - 使用清单的默认命名空间或传递给此类构造函数的参数创建命名空间资源。

减去清单资源

某些清单资源不再需要,必须删除。在应用其他 Patch 操作之前,添加 Subtraction 操作。

内置减除器

  • SubtractEq - 减去与作为参数传入的资源相等的清单资源。如果资源具有相同的类型、名称和命名空间,则认为它们是相等的。

自定义操作

当然内置的选项不足以满足需求,所以您的魅力可以通过定义新的对象来扩展其自己的操作,这些对象从 PatchAddition 继承。 .. _changelog

========= 更新日志

版本遵循 Semantic Versioning <https://semver.org/>_ (<major>.<minor>.<patch>)。

向后不兼容(破坏性)更改仅在主要版本中引入

ops-lib-manifest 1.2.0 (2024-02-14)

  • #31
    • Collector.conditions 属性返回一个映射,最终隐藏了与 Kubernetes 资源的所有条件相关的信息。对于每个资源,映射中只有一个条件。
    • 引入 Collector.all_conditions 属性,返回条件列表及其相关的清单和对象
    • 使用 all_conditions 属性检查未就绪状态
  • 允许清单通过覆盖 is_ready(..) 方法,通过覆盖来过滤它安装的对象的每个 condition 的就绪检查

ops-lib-manifest 1.1.4 (2024-01-10)

  • 只删除此魅力应用程序创建的资源
  • LP#2025283 - 审计库以确保秘密不会被泄露到日志中
  • 保持与 python 3.7 的兼容性

ops-lib-manifest 1.1.3 (2023-06-28)

问题已解决

  • LP#2025087
    • 解决从列表类型资源对象中读取每个项目时的问题

ops-lib-manifest 1.1.2 (2023-04-17)

问题已解决

  • LP#2006619
    • 解决尝试使用无法到达 API 端点的客户端时的状态问题

ops-lib-manifest 1.1.1 (2022-04-06)

问题已解决

  • LP#1999427
    • 解决从不可达的 API 端点加载 CRDs 时的问题

ops-lib-manifest 1.1.0 (2022-02-17)

特性

  • 支持 JobCronJobReplicationControllerReplicaSet 对象的镜像操作

ops-lib-manifest 1.0.0 (2022-12-14)

问题已解决

  • LP#1999427
    • 处理客户端的非 API 错误,这些错误表示为没有 JSON 内容的 http 错误响应。

破坏性更改

  • 不再在以下方法上引发 lightkube.core.exceptions.ApiError

    • Manifest.status
    • Manifest.installed_resources
    • Manifest.apply_manifest
    • Manifest.delete_manifest
    • Manifest.apply_resources
    • Manifest.delete_resources

    而是抛出一个更通用的异常 ManifestClientError

                               Apache License
                         Version 2.0, January 2004
                      https://apache.ac.cn/licenses/
    

    使用、复制和分发条款

    1. 定义。

      "许可" 指的是本文件第1条至第9条规定的使用、复制和分发条件。

      "许可方" 指的是版权所有者或经版权所有者授权的实体,该实体授予许可。

      "法人实体" 指的是行动实体以及控制该实体、受该实体控制或与该实体共同控制的全部其他实体的联合。在本定义中,“控制” 指的是:(i) 通过合同或其他方式直接或间接地影响该实体的方向或管理权,或(ii) 拥有50% (50%) 或以上的已发行股份,或(iii) 拥有该实体的利益所有权。

      "您" (或"您的") 指的是行使本许可授予的权限的个体或法人实体。

      "源代码" 指的是进行修改的首选形式,包括但不限于软件源代码、文档源代码和配置文件。

      "目标代码" 指的是从源代码机械转换或翻译而来的任何形式,包括但不限于编译后的目标代码、生成的文档和转换到其他媒体类型。

      "作品" 指的是在源代码或目标代码形式下,根据许可提供的作品,包括但在不限于包含在作品内或附在作品上的版权声明(以下附录提供了一个示例)。

      "衍生作品" 指的是任何在源代码或目标代码形式下,基于(或源自)作品并为其编辑修订、注释、扩展或其他修改代表整体原创作品的任何作品。在本许可中,“衍生作品” 不包括仍然与作品或其衍生作品的接口分离的作品,或者仅通过名称链接(或绑定)到作品及其衍生作品的接口的作品。

      "贡献" 指的是任何作品,包括作品的原始版本和对其或其衍生作品的任何修改或添加,该作品有意提交给许可方,以包含在作品中,由版权所有者或经版权所有者授权提交的个体或法人实体。在本定义中,“提交” 指的是发送给许可方或其代表的任何形式的电子、口头或书面通信,包括但不限于在许可方管理或在许可方代表下管理的电子邮件列表、源代码控制系统和问题跟踪系统中的通信,其目的是讨论和改进作品,但不包括版权所有者明确标记或以书面形式指定的“非贡献”的通信。

      "贡献者" 指的是许可方以及任何经许可方接收贡献并将其纳入作品的个体或法人实体。

    2. 授予版权许可。在遵守本许可条款和条件的情况下,每个贡献者在此授予您永久的、全球性的、非独占的、无偿的、免版税的、不可撤销的版权许可,以复制、准备衍生作品、公开展示、公开表演、许可和以源代码或目标代码形式分发作品及其衍生作品。

    3. 专利许可授予。在本许可证的条款和条件下,每个贡献者在此授予您一项永久、全球、非独家、免费、无版税、不可撤销(除本节所述外)的专利许可,以制造、要求制造、使用、提供销售、销售、进口和以其他方式转让作品,其中此类许可仅适用于该贡献者可许可的专利权利要求,这些权利要求仅由其贡献(单独或与其提交的作品相结合)必然侵犯。如果您对任何实体(包括诉讼中的交叉诉讼或反诉)提起专利诉讼,声称作品或作品内包含的贡献构成直接或从属专利侵权,则根据本许可证授予的针对该作品的任何专利许可自诉讼提起之日起终止。

    4. 再分发。您可以在任何媒介中复制和分发作品或其衍生物的副本,无论是否修改,以及以源代码或目标代码形式,只要您满足以下条件

      (a) 您必须向作品或衍生物的任何其他接收者提供本许可证的副本;

      (b) 您必须使任何修改过的文件带有显著声明,说明您已更改文件;

      (c) 您必须在您分发的任何衍生物的源代码形式中保留所有版权、专利、商标和归属声明,来自作品源代码形式的所有声明,除不涉及衍生物任何部分的通知声明外;

      (d) 如果作品包含作为其分发一部分的“NOTICE”文本文件,则您分发的任何衍生物必须包含包含在所述NOTICE文件中的归属声明的可读副本,除不涉及衍生物任何部分的通知声明外,至少在以下位置之一:在作为衍生物一部分分发的NOTICE文本文件中;在源代码形式或文档中,如果与衍生物一起提供;或者,在衍生物生成的显示中,如果第三方通知通常出现在其中。NOTICE文件的内容仅用于信息目的,并不修改许可证。您可以在您分发的衍生物中添加您自己的归属声明,并可以为您提供修改的使用、复制或分发许可条款和条件,或为任何此类衍生物的整体提供,只要您的使用、复制和分发作品符合本许可证中所述的条件。

      您可以在您的修改中添加您自己的版权声明,并可以为使用、复制或分发您的修改或任何此类衍生物的整体提供附加或不同的许可条款和条件,只要您的使用、复制和分发作品符合本许可证中所述的条件。

    5. 贡献的提交。除非您明确表示否则,您向许可方提交的旨在包含在作品中的任何贡献均受本许可证的条款和条件约束,没有附加条款或条件。尽管上述内容,本条款不得取代或修改您与许可方就此类贡献可能已签署的任何单独许可协议的条款。

    6. 商标。本许可证不授予使用许可方的商号、商标、服务标志或产品名称的许可,除非为合理和习惯性地描述作品的来源和复制NOTICE文件的内容所必需。

    7. 免责声明。除非适用法律要求或书面同意,否则许可方提供的作品(以及每个贡献者提供的贡献)基于“现状”提供,不提供任何类型的保证或条件,无论是明示的还是默示的,包括但不限于关于所有权、非侵权、适销性或特定用途适用性的任何保证或条件。您自行负责确定使用或重新分发作品的适当性,并承担本许可证下行使许可所产生的任何风险。

    8. 责任限制。在任何情况下,根据任何法律理论,包括侵权(包括疏忽)、合同或否则,除非适用法律(如故意和重大疏忽行为)要求或书面同意,否则任何贡献者不对您承担任何损害赔偿责任,包括任何直接、间接、特殊、偶然或后果性的损害,无论其性质如何,由此许可证或作品的使用或无法使用而产生的,即使此类贡献者已被告知此类损害的可能性。

    9. 接受保证或额外责任。在重新分发作品或其衍生作品时,您可以选择提供并收取接受支持、保证、赔偿或与此许可证一致的其他责任义务和/或权利的费用。然而,在承担此类义务时,您只能代表自己并承担个人责任,而不是代表任何其他贡献者,并且只有在您同意赔偿、辩护并使每个贡献者免受因您接受任何此类保证或额外责任而引起的责任或索赔的情况下。

    条款和条件结束

    附录:如何将Apache许可证应用于您的作品。

    To apply the Apache License to your work, attach the following
    boilerplate notice, with the fields enclosed by brackets "[]"
    replaced with your own identifying information. (Don't include
    the brackets!)  The text should be enclosed in the appropriate
    comment syntax for the file format. We also recommend that a
    file or class name and description of purpose be included on the
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
    

    版权 [yyyy] [版权所有者名称]

    根据Apache许可证版本2.0(以下简称“许可证”)授权;除非遵守许可证,否则不得使用此文件。您可以在以下地址获取许可证副本:

     https://apache.ac.cn/licenses/LICENSE-2.0
    

    除非适用法律要求或书面同意,否则在许可证下分发的软件基于“现状”提供,不提供任何类型的保证或条件,无论是明示的还是默示的。有关许可证下许可和限制的具体语言,请参阅许可证。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分发

ops.manifest-1.2.0.tar.gz (26.5 kB 查看散列

上传时间:

构建分发

ops.manifest-1.2.0-py3-none-any.whl (23.9 kB 查看散列

上传时间: Python 3