Java Operator SDK

Operators 代表Kubernetes管理集群和非集群资源。这个Java Operator SDK (JOSDK) 旨在通过使用一个对Java开发人员来说应该感觉自然的API,使编写Kubernetes操作员变得尽可能容易,并且不必担心许多低级细节,因为SDK会自动处理。

生成项目骨架

该项目包括一个Maven插件,用于生成项目的骨架:

mvn io.javaoperatorsdk:bootstrapper:[version]:create 
-DprojectGroupId=org.acme 
-DprojectArtifactId=getting-started

这个命令使用了Java Operator SDK的bootstrapper插件来创建一个项目的骨架。具体命令是mvn io.javaoperatorsdk:bootstrapper:[version]:create -DprojectGroupId=org.acme -DprojectArtifactId=getting-started

其中[version]是指Java Operator SDK的版本号,-DprojectGroupId=org.acme指定了项目的groupId为org.acme-DprojectArtifactId=getting-started指定了项目的artifactId为getting-started

运行这个命令后,bootstrapper插件会自动生成一个基本的项目结构,包括Maven的pom.xml文件和一些示例代码,以便你可以开始编写Kubernetes操作员。这个骨架项目可以作为一个起点,你可以根据需要进行修改和扩展。

快速入门

使用SDK的最简单方法是启动并执行我们的示例之一。有一个专门的页面来描述如何开始。

以下是开发代码并将operator部署到Kubernetes集群的主要步骤。在samples/mysql-schema/目录下可以找到更详细和具体的版本。

  • 配置kubectl以与您选择的Kubernetes集群一起使用。
  • 应用自定义资源定义(Custom Resource Definition)。
  • 在根目录下使用mvn install编译整个项目(包括框架和示例)。
  • 运行您选择的示例的主类,并查看示例的README文件以了解其功能。在本地运行时,框架将使用您的Kubernetes客户端配置(在~/.kube/config中)建立与集群的连接。这就是为什么提前设置kubectl非常重要。
  • 您可以在本地开发模式下使用这个代码进行测试。
  • 构建Docker镜像并将其推送到镜像仓库。
  • 应用RBAC配置。
  • 应用部署配置。
  • 验证operator是否正在运行。请不要再在本地运行它,以避免处理来自集群API服务器的事件时发生冲突。

模式和最佳实践

本文档介绍了构建和运行操作员的模式和最佳实践,以及如何使用Java Operator SDK (JOSDK)实现它们。请参阅Operator SDK中的最佳实践。

实现Reconciler

始终协调所有资源

协调可以由多个来源的事件触发。检查事件并只协调控制器管理的相关资源或资源子集可能很诱人。然而,这被认为是操作员的反模式,因为Kubernetes的分布式性质使得很难确保始终接收到所有事件。如果由于某种原因,您的操作员没有接收到一些事件,如果您不协调整个状态,您可能会根据关于集群状态的不适当假设进行操作。这就是为什么始终协调所有资源很重要,无论多么诱人只考虑子集。幸运的是,JOSDK尽可能地使其易于使用和高效,通过提供智能缓存来避免过度访问Kubernetes API服务器,并确保仅在需要时触发您的调和器。

由于在业界对这个话题有共识,JOSDK从框架的第2个版本开始不再提供Reconciler实现中的事件访问。

事件源和缓存

如上所述,在协调期间,最佳实践是协调控制器管理的所有相关资源。这意味着我们希望将期望状态与集群的实际状态进行比较。直接从Kubernetes API服务器读取资源的实际状态意味着会产生很大的负载。因此,通常的做法是为相关资源创建一个监视器,并缓存其最新状态。这是使用Informer模式完成的。在Java Operator SDK中,informer被封装在EventSource中,以将其集成到框架的事件系统中。这是通过InformerEventSource类实现的。

仅当实际资源已经在缓存中时,才会将新事件传播到Reconciler。因此,Reconciler实现只需要将期望状态与由缓存资源提供的观察到的状态进行比较。如果在缓存中找不到资源,则需要创建该资源。如果实际状态与期望状态不匹配,则需要更新该资源。

幂等性

由于在触发Reconciler时应协调所有资源,并且在任何给定资源上可以多次触发协调,特别是在使用重试策略时,因此Reconciler实现必须是幂等的,这意味着相同的观察到的状态应该产生完全相同的结果。这也意味着操作员通常应以无状态方式运行。幸运的是,由于操作员通常管理声明性资源,因此通常很容易确保幂等性。

同步或异步方式处理资源

根据您的用例,您的协调逻辑可能需要等待相当长的时间,而操作员等待资源达到其期望状态。例如,您的Reconciler可能需要等待Pod准备就绪,然后再执行其他操作。可以通过同步或异步方式来解决此问题。

异步方式是仅在Reconciler确定无法在此时完成其全部逻辑时退出协调逻辑。这将释放资源以处理其他主资源事件。但是,这需要放置足够的事件源以监视操作员等待的所有资源的状态更改。当正确执行此操作时,任何状态更改都将再次触发Reconciler,它将有机会完成其处理。

同步方式是定期轮询资源的状态,直到它们达到所需状态。如果在您的Reconciler实现的协调方法的上下文中执行此操作,这将阻止当前线程,可能需要很长时间。因此,通常建议使用异步处理方式。

为什么要自动重试?

默认情况下,自动重试已启用,并且可以根据您的需求进行配置。虽然完全关闭此功能是可能的,但我们建议不要这样做。为您的Reconciler配置自动重试的主要原因是由于Kubernetes的分布式性质,错误经常发生:瞬态网络错误可以通过自动重试轻松处理。同样,当与Kubernetes资源一起工作时,不同的操作者可能会修改资源,因此在处理Kubernetes资源时可能会发生冲突。这样的冲突通常可以通过再次协调资源来自然地解决。如果自动完成,整个过程可以完全透明地进行。

管理状态

由于Kubernetes资源的声明性本质,仅处理Kubernetes资源的操作员可以以无状态方式运行,即它们不需要维护有关这些资源状态的信息,因为应该可以从其表示中完全重建资源状态(毕竟,这就是声明性的含义)。但是,当处理外部资源时,这通常不再成立,可能需要操作员跟踪此外部状态,以便在发生另一个协调时可用。虽然这样的状态可以放在主资源的状态子资源中,但如果需要跟踪大量状态,则可能很难管理。它也违反了最佳实践,即资源的状态应该表示实际资源状态,而其规范表示期望状态。因此,不建议将不严格表示资源实际状态的状态放入其中。相反,建议将这种状态放入用于此目的的单独资源中,例如Kubernetes Secret或ConfigMap甚至是专用的自定义资源,其结构更容易验证。

在Informer错误和缓存同步超时的情况下停止(或不停止)操作员

可以配置,如果任何Informer错误发生在启动时,操作员是否应停止。默认情况下,如果在启动时出现错误,例如informer没有权限列出目标资源(包括主资源或辅助资源),则操作员将立即停止。通过将上述标志设置为false,可以更改此行为,从而操作员即使某些informer未启动也会启动。在这种情况下-与稍后遇到问题的informer启动时一样-将无限期地使用指数回退重试连接。仅当资源无法反序列化时,操作员才会停止,当前。更改此标志的典型用例是监视控制器的名称空间列表。在某些名称空间中某些资源的权限问题可能存在时,最好启动操作员,以便在处理其他名称空间时可以处理其他名称空间。

stopOnInformerErrorDuringStartup对缓存同步超时行为产生影响。如果为true,则操作员将在缓存同步超时时停止。如果为false,则在超时后,即使一个或多个事件源缓存未同步,控制器也将开始协调资源。

使用示例Operators

我们在目录下提供了一些示例,旨在演示不同场景下使用不同组件的用法,但主要是更真实的示例:

  • webpage: 简单的示例,创建包含HTML代码的自定义资源的NGINX Web服务器。
  • mysql-schema: 管理MySQL数据库中模式的操作员。演示如何管理非Kubernetes资源。
  • tomcat: 具有两个控制器的操作员,管理Tomcat实例和运行在Tomcat中的Web应用程序。这个示例的目的是展示如何管理多个相关的自定义资源和/或更多的控制器。

实现示例Operator

使用Maven将以下依赖项添加到您的项目中:

<dependency>
    <groupId>io.javaoperatorsdk</groupId>
    <artifactId>operator-framework</artifactId>
    <version>{see https://search.maven.org/search?q=a:operator-framework%20AND%20g:io.javaoperatorsdk for latest version}</version>
</dependency>

或者,您也可以使用Gradle,但是需要将SDK声明为注解处理器,以便生成控制器和自定义资源类之间的映射关系:

dependencies {
    implementation "io.javaoperatorsdk:operator-framework:${javaOperatorVersion}"
    annotationProcessor "io.javaoperatorsdk:operator-framework:${javaOperatorVersion}"
}

在添加了依赖项后,定义一个主方法来初始化Operator并注册一个控制器。

public class Runner {

    public static void main(String[] args) {
        Operator operator = new Operator();
        operator.register(new WebPageReconciler());
        operator.start();
    }
}

控制器实现业务逻辑,并描述了处理CRD所需的所有类。

@ControllerConfiguration
public class WebPageReconciler implements Reconciler<WebPage> {

    // Return the changed resource, so it gets updated. See javadoc for details.
    @Override
    public UpdateControl<CustomService> reconcile(CustomService resource,
                                                               Context context) {
        // ... your logic ...
        return UpdateControl.patchStatus(resource);
    }
}

一个示例的自定义资源POJO表示

@Group("sample.javaoperatorsdk")
@Version("v1")
public class WebPage extends CustomResource<WebPageSpec, WebPageStatus> implements
        Namespaced {
}

public class WebServerSpec {

    private String html;

    public String getHtml() {
        return html;
    }

    public void setHtml(String html) {
        this.html = html;
    }
}

禁用CustomResource实现的验证

operator默认会查询部署的CRD以检查CustomResource实现是否与集群中已知的匹配。这需要向集群发起额外的查询,并且有时需要提升operator的权限才能从集群中读取CRD。这种验证主要是为了帮助新手operator开发人员入门并避免常见错误。高级用户或生产部署可能希望跳过此步骤。可以通过将CHECK_CRD_ENV_KEY环境变量设置为false来实现。

自动生成CRD
要从您的注解自定义资源类自动生成CRD清单,您只需要将以下依赖项添加到您的项目中(在背景中使用了注解处理器),使用Maven:

<dependency>
    <groupId>io.fabric8</groupId>
    <artifactId>crd-generator-apt</artifactId>
    <scope>provided</scope>
</dependency>

或者使用Gradle:

dependencies {
    annotationProcessor 'io.fabric8:crd-generator-apt:<version>'
    ...
}

CRD将在target/classes/META-INF/fabric8目录中生成(如果使用测试范围,则在target/test-classes/META-INF/fabric8目录中生成),其中CRD名称后缀为生成的规范版本。例如,

  • mycrs.java-operator-sdk.io-v1.yml
  • mycrs.java-operator-sdk.io-v1beta1.yml

注意:使用quarkus-operator-sdk扩展的Quarkus用户无需添加任何额外的依赖项来生成他们的CRD,因为扩展本身会处理这个过程。

Quarkus

还提供了一个Quarkus扩展,以便于基于Quarkus的操作员开发。
在您的项目中添加以下依赖项:这个依赖项

<dependency>
    <groupId>io.quarkiverse.operatorsdk</groupId>
    <artifactId>quarkus-operator-sdk</artifactId>
    <version>{see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version}
    </version>
</dependency>

创建一个应用程序,Quarkus将自动创建和注入一个KubernetesClient(或OpenShiftClient)、Operator、ConfigurationService和ResourceController实例,您的应用程序可以使用它们。下面是您需要编写的最小代码,以使您的操作员和控制器运行起来:

@QuarkusMain
public class QuarkusOperator implements QuarkusApplication {

    @Inject
    Operator operator;

    public static void main(String... args) {
        Quarkus.run(QuarkusOperator.class, args);
    }

    @Override
    public int run(String... args) throws Exception {
        operator.start();
        Quarkus.waitForExit();
        return 0;
    }
}

Spring Boot

您还可以让Spring Boot自动连接您的应用程序并自动注册控制器。
将以下依赖项添加到您的项目中:这个依赖项

<dependency>
    <groupId>io.javaoperatorsdk</groupId>
    <artifactId>operator-framework-spring-boot-starter</artifactId>
    <version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter%20AND%20g:io.javaoperatorsdk for
        latest version}
    </version>
</dependency>

创建应用

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

您还需要一个 @Configuration 来确保您的协调器已注册:

@Configuration
public class Config {

    @Bean
    public WebPageReconciler customServiceController() {
        return new WebPageReconciler();
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    @SuppressWarnings("rawtypes")
    public Operator operator(List<Reconciler> controllers) {
        Operator operator = new Operator();
        controllers.forEach(operator::register);
        return operator;
    }
}

Spring Boot 测试支持

添加以下依赖项可以让您模拟需要加载 spring 容器的测试操作员,但不需要真正访问 Kubernetes 集群。

<dependency>
    <groupId>io.javaoperatorsdk</groupId>
    <artifactId>operator-framework-spring-boot-starter-test</artifactId>
    <version>{see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter%20AND%20g:io.javaoperatorsdk for
        latest version}
    </version>
</dependency>

模拟operator:

@SpringBootTest
@EnableMockOperator
public class SpringBootStarterSampleApplicationTest {

    @Test
    void contextLoads() {
    }
}

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐骑行^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值