查看原文
其他

使用Kubernetes和Spring Boot进行自我修复的应用程序

Yunooa SpringForAll社区 2020-10-17

原文链接 https://www.baeldung.com/spring-debugging-reactive-streams

作者: Daniel Barrigas

译者: skeeve

1 简介

在本教程中,我们将讨论 Kubernetes的探测器, 并演示如何利用 Actuator的 HealthIndicator 准确了解我们的应用程序状态。

出于本教程的目的,我们将假设一些预先存在的 Spring Boot Actuator, Kubernetes和 Docker的经验。

2 Kubernetes 探针

Kubernetes定义了两种不同的探针,我们可以用它来定期检查一切是否按预期工作: 活跃度探针和准备度探针。

2.1 活跃度探针和准备度探针

通过Liveness和 Readiness探测器, Kubelet 可以在检测到某些东西时立即行动,并最大限度地减少应用程序的停机时间。

两者都以相同的方式配置,但它们具有不同的语义,Kubelet 根据触发的操作执行不同的操作:

  • 准备就绪 - 准备情况验证我们的 Pod是否已准备好开始接收流量。当所有容器准备就绪时,我们的 P od已经准备就绪

  • 活力 - 与准备情况相反 , 活跃度检查我们的 Pod应该重新启动。它可以获取我们的应用程序正在运行但处于无法取得进展的状态的用例; 例如,它处于死锁状态

我们在容器级别配置两种探测器类型:

  1. apiVersion: v1

  2. kind: Pod

  3. metadata:

  4.  name: goproxy

  5.  labels:

  6.    app: goproxy

  7. spec:

  8.  containers:

  9.  - name: goproxy

  10.    image: k8s.gcr.io/goproxy:0.1

  11.    ports:

  12.    - containerPort: 8080

  13.    readinessProbe:

  14.      tcpSocket:

  15.        port: 8080

  16.      initialDelaySeconds: 5

  17.      periodSeconds: 10

  18.      timeoutSeconds: 2

  19.      failureThreshold: 1

  20.      successThreshold: 1

  21.    livenessProbe:

  22.      tcpSocket:

  23.        port: 8080

  24.      initialDelaySeconds: 15

  25.      periodSeconds: 20

  26.      timeoutSeconds: 2

  27.      failureThreshold: 1

  28.      successThreshold: 1

我们可以配置许多字段来更精确地控制探针的行为:

  • initialDelaySeconds - 创建容器后,在启动探测之前等待n 秒.

  • periodSeconds - 应该运行此探测的频率,默认为10秒; 最小值是1秒.

  • timeoutSeconds - 在超时探测之前等待多长时间,默认为1秒; 最小值再次为1秒.

  • failureThreshold - 在放弃之前尝试 n次。在准备就绪的情况下 ,我们的pod将被标记为未准备好,而在活跃的情况下放弃意味着重新启动 Pod。此处的默认值为3次失败,最小值为1.

  • successThreshold - 这是失败后探测成功的最小连续成功次数。默认为1成功,最小值为1.

在这种情况下,我们选择了 tcp探测器,但是,我们也可以使用其他类型的探测器。

2.2 探针类型

根据我们的使用情况,一种探针类型可能比另一种更有用。例如,如果我们的容器是Web服务器,则使用 http探测器可能比tcp探测器更可靠 。

幸运的是, Kubernetes有三种不同类型的探针可供我们使用:

  • exec - 在我们的容器中执行 bash指令。例如,检查特定文件是否存在。如果指令返回失败代码,则探测失败

  • tcpSocket - 尝试 使用指定的端口建立与容器的tcp连接。如果无法建立连接,则探测失败

  • httpGet - 将HTTP GET请求发送到在容器中运行并侦听指定端口的服务器。任何大于或等于200且小于400的代码表示成功

重要的是要注意 HTTP探测器除了前面提到的那些之外还有其他字段:


  • host - 要连接的主机名,默认为我们的pod的IP



  • scheme - 应该用于连接, HTTP或 HTTPS的方案,默认为 HTTP



  • path - Web服务器上的访问路径



  • httpHeaders - 要在请求中设置的自定义标头



  • port - 要在容器中访问的端口的名称或编号

    3 Spring actuator 和 Kubernetes 的自愈能力

    现在,我们已经对如何总体思路 Kubernetes能够检测到,如果我们的应用是在一个异常的状态,让我们看看如何,我们 可以 采取 利用 的 Spring的 致动器,以保持更密切的关注不仅对我们的应用程序,而且它依赖!


出于这些示例的目的,我们将依赖于 Minikube。

3.1 执行器及其 HealthIndicator s

考虑到Spring有许多 HealthIndicator可供使用,反映我们的一些应用程序依赖 Kubernetes的探测器的状态就像在我们的pom.xml中添加Actuator依赖 一样简单 :

  1. <dependency>

  2.    <groupId>org.springframework.boot</groupId>

  3.    <artifactId>spring-boot-starter-actuator</artifactId>

  4. </dependency>

####3.2 活力示例 让我们将正常启动,并且应用程序开始 后 30 秒 将 过渡 到一个的 状态。

我们将通过创建一个 验证布尔变量是否为真的HealthIndicator来模拟一个异常的状态。我们将变量初始化为 true,然后我们将安排任务在30秒后将其更改为 false:

  1. @Component

  2. public class CustomHealthIndicator implements HealthIndicator {


  3.    private boolean isHealthy = true;


  4.    public CustomHealthIndicator() {

  5.        ScheduledExecutorService scheduled =

  6.          Executors.newSingleThreadScheduledExecutor();

  7.        scheduled.schedule(() -> {

  8.            isHealthy = false;

  9.        }, 30, TimeUnit.SECONDS);

  10.    }


  11.    @Override

  12.    public Health health() {

  13.        return isHealthy ? Health.up().build() : Health.down().build();

  14.    }

  15. }

有了我们的 HealthIndicator,我们需要将我们的应用程序容器化:

  1. FROM openjdk:8-jdk-alpine

  2. RUN mkdir -p /usr/opt/service

  3. COPY target/*.jar /usr/opt/service/service.jar

  4. EXPOSE 8080

  5. ENTRYPOINT exec java -jar /usr/opt/service/service.jar

接下来,我们创建我们的 Kubernetes模板:

  1. apiVersion: apps/v1

  2. kind: Deployment

  3. metadata:

  4.  name: liveness-example

  5. spec:

  6.  ...

  7.    spec:

  8.      containers:

  9.      - name: liveness-example

  10.        image: dbdock/liveness-example:1.0.0

  11.        ...

  12.        readinessProbe:

  13.          httpGet:

  14.            path: /health

  15.            port: 8080

  16.          initialDelaySeconds: 10

  17.          timeoutSeconds: 2

  18.          periodSeconds: 3

  19.          failureThreshold: 1

  20.        livenessProbe:

  21.          httpGet:

  22.            path: /health

  23.            port: 8080

  24.          initialDelaySeconds: 20

  25.          timeoutSeconds: 2

  26.          periodSeconds: 8

  27.          failureThreshold: 1

我们正在使用指向Actuator健康端点的httpGet探针。 对我们的应用程序状态(及其依赖项)的任何更改都将反映在我们部署的健康状况上。

在将我们的应用程序部署到 Kubernetes后,我们将能够看到两个探测器在运行:大约30秒后,我们的 Pod将被标记为未准备好并从旋转中移除; 几秒钟后, Pod重新启动。

我们可以看到我们的Pod 执行 kubectl 的事件描述了 pod liveness -example:

  1. Warning  Unhealthy 3s (x2 over 7s)   kubelet, minikube  Readiness probe failed: HTTP probe failed ...

  2. Warning  Unhealthy 1s                kubelet, minikube  Liveness probe failed: HTTP probe failed ...

  3. Normal   Killing   0s                kubelet, minikube  Killing container with id ...

3.3 准备范例

在前面的示例中,我们了解了如何使用 HealthIndicator来反映应用程序在Kubernetes部署的健康状况方面的状态 。

让我们用它在不同的使用情况:假设我们的应用程序需要 一个 位 的 时间 之前, 它 能够 对 接收 的流量。例如,它需要将文件加载到内存中并验证其内容。

这是我们何时可以利用准备情况探测的一个很好的例子 。

让我们修改 上一个示例中的 HealthIndicator和 Kubernetes模板,并使它们适应这个用例:

  1. @Component

  2. public class CustomHealthIndicator implements HealthIndicator {


  3.    private boolean isHealthy = false;


  4.    public CustomHealthIndicator() {

  5.        ScheduledExecutorService scheduled =

  6.          Executors.newSingleThreadScheduledExecutor();

  7.        scheduled.schedule(() -> {

  8.            isHealthy = true;

  9.        }, 40, TimeUnit.SECONDS);

  10.    }


  11.    @Override

  12.    public Health health() {

  13.        return isHealthy ? Health.up().build() : Health.down().build();

  14.    }

  15. }

我们将变量初始化为false,并在40秒后执行任务并将其设置为 true。

接下来,我们使用以下模板对我们的应用程序进行容器化并部署:

  1. apiVersion: apps/v1

  2. kind: Deployment

  3. metadata:

  4.  name: readiness-example

  5. spec:

  6.  ...

  7.    spec:

  8.      containers:

  9.      - name: readiness-example

  10.        image: dbdock/readiness-example:1.0.0

  11.        ...

  12.        readinessProbe:

  13.          httpGet:

  14.            path: /health

  15.            port: 8080

  16.          initialDelaySeconds: 40

  17.          timeoutSeconds: 2

  18.          periodSeconds: 3

  19.          failureThreshold: 2

  20.        livenessProbe:

  21.          httpGet:

  22.            path: /health

  23.            port: 8080

  24.          initialDelaySeconds: 100

  25.          timeoutSeconds: 2

  26.          periodSeconds: 8

  27.          failureThreshold: 1

虽然类似,但我们需要指出的探针配置有一些变化:

  • 因为我们知道,我们的应用程序需要40秒左右,成为准备接收的流量,我们增加了 initialDelaySeconds 我们的准备探测到40秒

  • 同样,我们增加了 initialDelaySeconds我们的 活跃度 探测到100秒,以避免过早地杀死 Kubernetes 如果在40秒后仍然没有完成,它仍然有大约60秒完成。之后,我们的 活动探测器将启动并重新启动 Pod。

4 结论

在本文中,我们讨论了Kubernetes探针以及如何使用Spring的 Actuator 来改进我们的应用程序的健康监控。

可以在Github上找到这些示例的完整实现。


推荐: SpringBoot WebFlux 入门案例

上一篇:微服务架构简介(单一架构VS微服务架构)

关注公众号

点击原文阅读更多


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存