发布于 2026-01-05 0 阅读
0

利用 Tracestore、OPA、Flagger 和自定义指标,助力开发者在 Kubernetes 上实现微服务的可观测性

利用 Tracestore、OPA、Flagger 和自定义指标,助力开发者在 Kubernetes 上实现微服务的可观测性

介绍

在现代微服务架构中,实现全面的可观测性不再是可选项,而是必需品。随着应用程序在 Kubernetes 环境中动态扩展,跟踪性能问题、执行安全策略以及确保平稳部署都成为复杂的挑战。传统的监控解决方案无法完全应对这些挑战。

本指南将探讨四种强大的工具,它们可以显著提高微服务环境中的可观测性和控制力:

  • Tracestore:提供对分布式追踪的深入洞察,使开发人员能够追踪请求流、识别延迟问题并诊断微服务中的瓶颈。
  • OPA(开放策略代理):通过直接在 Kubernetes 环境中强制执行动态策略控制来确保安全性和治理。
  • Flagger:通过智能流量转移和回滚策略,实现自动渐进式交付,最大限度地降低部署风险。
  • 自定义指标:捕获特定于应用程序的指标,提供通用监控工具可能忽略的增强洞察力。

开发人员经常面临诊断延迟问题、保障服务安全以及确保动态 Kubernetes 环境中部署稳定等挑战。通过结合使用 Tracestore、OPA、Flagger 和自定义指标,您可以增强可见性、改进安全措施并简化渐进式交付流程。

可观测性工具与 Kubernetes 集群和微服务集成
此图展示了可观测性工具如何与Kubernetes 集群微服务(Java、Node.js 等)集成。诸如TraceStore(分布式追踪)、自定义指标(性能洞察)、Flagger(部署控制)和OPA(策略执行)等关键工具增强了系统的可见性、安全性和稳定性。

为什么这些工具对微服务可观测性至关重要

这些工具的结合解决了传统可观测性方法无法解决的关键痛点:

  • Tracestore 与 Jaeger:虽然 Jaeger 是一个知名的追踪工具,但 Tracestore 与 OpenTelemetry 无缝集成,通过简化的配置提供更大的灵活性,是现代云原生应用程序的理想选择。
  • OPA 与 Kyverno: OPA 在复杂的策略逻辑和动态规则执行方面表现出色,提供了 Kyverno 更简单的语法在复杂的安全场景中可能无法提供的更高级的灵活性。
  • Flagger 与 Argo Rollouts: Flagger 的自动化渐进式交付机制,特别是与 Istio 和 Linkerd 集成,为开发人员提供了一种简化的方式,可以安全地部署更改,最大限度地减少人工干预。

这些工具的独特价值

  • 改进的开发者洞察: Tracestore 通过跟踪跨微服务的事务来增强可见性,从而确保更好地分析延迟问题的根本原因。
  • 增强的安全态势: OPA 动态地强制执行安全策略,无需频繁手动更新应用程序逻辑即可减少漏洞。
  • 更快更安全的部署: Flagger 的金丝雀部署自动化功能允许开发人员更快地部署功能,并可自动回滚失败的版本。
  • 以业务为中心的观测性:自定义指标使开发人员能够将性能数据与关键业务 KPI 保持一致,从而确保工程工作集中在最重要的事情上。

通过集成这些工具,开发人员可以获得全面、主动的可观测性策略,从而提升应用程序性能、加强安全防护并简化部署流程。本指南重点介绍代码片段、最佳实践和集成策略,旨在帮助开发人员直接在应用程序中实现这些解决方案。

第一步:面向开发人员的跟踪存储实现

为什么要优先考虑 Tracestore?

在现代微服务架构中,跟踪请求在服务间的流动对于诊断性能问题、识别延迟瓶颈以及维护应用程序的可靠性至关重要。传统的调试方法在分布式环境中往往难以奏效,因为故障可能发生在多个相互关联的服务中。

Tracestore通过实现分布式追踪来应对这些挑战,使开发人员能够可视化请求路径、跟踪依赖关系并实时精确定位运行缓慢或出现故障的服务。通过集成 Tracestore,开发人员可以深入了解应用程序的行为,从而提高故障排除效率并提升系统可靠性。

缺乏分布式追踪:在缺乏上下文传播的情况下,识别微服务中的性能瓶颈和追踪错误极其困难。开发人员被迫依赖碎片化的日志,从而延误了问题的解决。

借助分布式追踪:通过在服务之间传播追踪上下文标头,开发人员可以实现完整的请求可见性,从而改进延迟分析和故障隔离。

如果没有分布式追踪:无法跨服务查看信息

如果没有分布式追踪,跨服务的请求将缺乏追踪上下文,导致难以追踪请求流。这会造成日志碎片化、可见性受限,并在出现问题时使调试变得复杂。下图展示了在没有追踪上下文的情况下如何处理请求,从而无法清晰了解服务交互情况。

无分布式跟踪的服务通信
无分布式追踪的服务通信——此图展示了一个微服务环境,其中请求处理时没有追踪上下文。因此,开发人员无法跨服务查看信息,从而难以诊断问题、追踪故障或识别性能瓶颈。

借助分布式追踪:跨服务的可见性

此图展示了跟踪上下文(例如,traceparent 标头)如何在多个服务之间注入和转发。每个服务都会通过传出的请求传播跟踪上下文,以确保跟踪流的连续性。数据库调用包含跟踪上下文,从而确保所有服务交互的完全可见性,这有助于开发人员有效地跟踪问题、测量延迟和诊断瓶颈。 微服务架构中的跟踪上下文传播——演示了跟踪上下文如何通过 traceparent 标头在服务之间流动,从而实现端到端的请求跟踪,提高可观测性。无分布式跟踪的服务通信——此图展示了一个微服务环境,其中请求在没有跟踪上下文的情况下进行处理。因此,开发人员无法跨服务查看,这使得诊断问题、跟踪故障或识别性能瓶颈变得困难。
无分布式跟踪的服务通信

Java应用程序 - Tracestore集成(Spring Boot)

这段代码片段演示了如何在Spring Boot应用程序中使用 Java 集成OpenTelemetry进行分布式追踪。让我们逐部分进行分析,以便更好地理解:

依赖关系:

    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-sdk</artifactId>
    <version>1.20.0</version>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
    <version>1.20.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

解释:

  • opentelemetry-sdk — 这是创建跟踪和管理 Java 应用程序中的 span 所需的核心 OpenTelemetry SDK。它包含 TracerProvider、上下文传播和采样策略等关键组件。
  • opentelemetry-exporter-otlp — 此导出器使用OTLP(OpenTelemetry 协议)将跟踪数据发送到OpenTelemetry Collector或直接发送到可观测性后端(例如 Jaeger、Tempo)

这两个依赖项对于生成跟踪信息和将数据导出到监控平台都至关重要。

代码配置:

@Configuration
public class OpenTelemetryConfig {
    @Bean
    public OpenTelemetry openTelemetry() {
        return OpenTelemetrySdk.builder()
            .setTracerProvider(SdkTracerProvider.builder().build())
            .build();
    }
    @Bean
    public Tracer tracer(OpenTelemetry openTelemetry) {
        return openTelemetry.getTracer("my-application");
    }
}
Enter fullscreen mode Exit fullscreen mode

解释:

  1. @配置注解:
    • 将此类标记为 Spring Boot 配置类,用于定义 bean。
  2. @bean public OpenTelemetry openTelemetry()
    • 此方法创建并配置OpenTelemetrySdk的实例,它是检测代码的核心入口点。
    • TracerProvider使用SdkTracerProvider.builder () 进行初始化,以创建和管理跟踪器实例,确保每个服务实例都有一个专用的跟踪器。
    • .build() 方法用于最终确定配置。
  3. @bean public Tracer tracer()
    • 此方法定义了一个Tracer bean,该 bean 将被注入到需要跟踪的应用程序组件中。
    • getTracer("my-application") 会分配一个服务名称(my-application),用于在可观测性后端标识此应用程序。

使用跟踪功能检测 REST 模板

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplateBuilder()
            .interceptors(new RestTemplateInterceptor())
            .build();
    }
}
Enter fullscreen mode Exit fullscreen mode

解释:

  • RestTemplateInterceptor 拦截出站 HTTP 调用并添加跟踪跨度。
  • span 确保跟踪上下文传播到下游服务。

使用 Tracestore 的 Cron 作业示例

@Component
public class ScheduledTask {
    private final Tracer tracer;
    public ScheduledTask(Tracer tracer) {
        this.tracer = tracer;
    }
    @Scheduled(fixedRate = 5000)
    public void performTask() {
        Span span = tracer.spanBuilder("cronjob-task").startSpan();
        try (Scope scope = span.makeCurrent()) {
            System.out.println("Executing scheduled task");
        } finally {
            span.end();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Node.js 应用程序 - Tracestore 集成

这段代码片段演示了如何在Node.js应用程序中集成OpenTelemetry以实现分布式追踪。让我们来详细分析一下依赖项、配置以及它们对于有效可观测性的重要性。

依赖项安装:说明:
npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http

  • @opentelemetry/api — 提供追踪的核心 API 接口。这确保应用程序遵循 OpenTelemetry 的追踪 API 标准。
  • @opentelemetry/sdk-trace-node — Node.js SDK 实现,可直接与 Node 生态系统集成,以创建和管理 span。
  • @opentelemetry/exporter-trace-otlp-http — 使用OTLP(OpenTelemetry 协议)将跟踪数据导出到OpenTelemetry Collector或直接导出到可观测性后端(例如 Jaeger、Tempo)

这些依赖项构成了Node.js应用程序中跟踪检测和数据导出的基础。

tracer.js 中的配置

const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');

const provider = new NodeTracerProvider();
const exporter = new OTLPTraceExporter({ url: 'http://otel-collector:4317' });

provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
Enter fullscreen mode Exit fullscreen mode

解释:

  1. NodeTracerProvider 初始化:
    • NodeTracerProvider是 Node.js 应用程序主要跟踪提供程序,负责创建和管理跟踪器。
    • 该提供商负责生命周期管理、采样和上下文传播。
  2. OTLPTraceExporter 配置:
    • OTLPTraceExporter跟踪数据发送到OpenTelemetry Collector或可观测性后端。
    • URL“ http://otel-collector:4317 ”指向OpenTelemetry Collector中的OTLP端点,该端点能够高效地处理和转发跟踪数据。
  3. SimpleSpanProcessor 设置:
    • SimpleSpanProcessor是一个轻量级的跨度处理器它会在跨度完成后立即导出。
    • 对于生产环境,可以考虑切换到BatchSpanProcessor以提高批量数据导出的性能。
  4. provider.register() 注册:
    • 在 Node.js 应用程序中全局注册跟踪器提供程序。
    • 此步骤确保任何已检测的模块、中间件或库自动使用已定义的跟踪器。

向 Span 添加自定义属性

例子:

app.get('/payment/:id', (req, res) => {
    const span = tracer.startSpan('payment-processing');
    span.setAttribute('payment_id', req.params.id);
    span.setAttribute('user_role', req.user.role);
    try {
        processPayment(req.params.id);
        res.send('Payment Processed');
    } catch (error) {
        span.recordException(error);
    } finally {
        span.end();
    }
});
Enter fullscreen mode Exit fullscreen mode

解释:

  • setAttribute() 将有用的数据附加到 span 上,以提高跟踪可见性。
  • recordException() 会捕获错误以便进行更深入的分析。

微服务中的 ID 传播追踪

发出请求(客户端):

const { context, trace, propagation } = require('@opentelemetry/api');
const axios = require('axios');
app.get('/trigger-service', async (req, res) => {
    const span = tracer.startSpan('trigger-service-call');
    try {
        const headers = {};
        propagation.inject(context.active(), headers);
        const response = await axios.get('http://other-service/api', { headers });
        res.json(response.data);
    } finally {
        span.end();
    }
});
Enter fullscreen mode Exit fullscreen mode

传入请求(服务器端):

const { context, propagation, trace } = require('@opentelemetry/api');
app.get('/api', (req, res) => {
    const extractedContext = propagation.extract(context.active(), req.headers);
    const span = tracer.startSpan('incoming-request', { parent: extractedContext });
    try {
        res.send('Data Retrieved');
    } finally {
        span.end();
    }
});
Enter fullscreen mode Exit fullscreen mode

微服务架构中的 OpenTelemetry 数据流
微服务架构中的 OpenTelemetry 数据流 — 此图展示了跟踪数据从应用程序代码到可观测性后端的流转过程。OpenTelemetry SDK生成跟踪数据,并通过 OTLP 将其导出到OpenTelemetry Collector。收集器处理数据并将其转发到JaegerTempo等可观测性后端,以进行可视化和分析。

步骤 2:面向开发者的 OPA(开放策略代理)

为什么使用 OPA 进行安全和策略执行?

Open Policy Agent (OPA) 是一款功能强大的工具,用于在 Kubernetes 环境中强制执行安全策略并确保一致的访问管理。OPA 利用 Rego 逻辑动态验证请求,防止未经授权的访问,并加强合规性措施。以下是 OPA 在安全性和策略执行方面的主要优势。

  • 准入控制:通过在清单应用到集群之前对其进行验证来防止未经授权的部署。
  • 访问控制:确保只有授权用户和服务才能访问特定的端点或资源。
  • 数据过滤:通过在 API 层强制执行过滤规则来限制敏感数据的暴露。

实际示例:多租户 SaaS 环境中,OPA 可以:

  • 拒绝尝试访问用户所属租户之外的资源的请求。
  • 根据请求参数动态强制执行基于角色的访问控制 (RBAC) 规则,而无需修改应用程序代码。

OPA 灵活的 Rego 策略使开发人员能够定义复杂的逻辑,以适应不断变化的安全和运营要求。

示例用例:假设有一个多租户 SaaS 应用,其中客户拥有相互隔离的数据和权限。使用 OPA,开发人员可以:

  • 拒绝尝试访问用户所属租户之外的资源的请求。
  • 根据请求参数动态强制执行基于角色的访问控制 (RBAC) 规则,而无需修改应用程序代码。

OPA 灵活的 Rego 策略使开发人员能够定义复杂的逻辑,以适应不断变化的安全和运营要求。

了解 OPA Webhook

OPA Webhook 旨在 Kubernetes 中创建或修改资源之前强制执行策略决策。当 Webhook 被触发时,OPA 会根据已定义的策略规则评估传入的请求,并返回允许或拒绝的决策。此图展示了 Kubernetes 准入控制期间 OPA Webhook 的评估过程,确保在资源创建之前安全地执行策略。
Kubernetes准入控制期间的OPA webhook评估过程

OPA Webhook 配置示例

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: opa-webhook
webhooks:
  - name: "example-opa-webhook.k8s.io"
    clientConfig:
      url: "https://opa-service.opa.svc.cluster.local:443/v1/data/authz"
    rules:
      - operations: ["CREATE", "UPDATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    failurePolicy: Fail
Enter fullscreen mode Exit fullscreen mode

车辆登记策略的配置位置

Rego策略存储在指定的策略仓库或Kubernetes ConfigMap中。例如:

示例策略配置映射

apiVersion: v1
kind: ConfigMap
metadata:
  name: opa-policy-config
  namespace: opa
  labels:
    openpolicyagent.org/policy: rego
  annotations:
    openpolicyagent.org/policy-status: "active"
data:
  authz.rego: |
    package authz
    default allow = false
    allow {
        input.user == "admin"
        input.action == "read"
    }

    allow {
        input.user == "developer"
        input.action == "view"
    }
Enter fullscreen mode Exit fullscreen mode

使用 OPA 作为 Sidecar 部署 YAML 文件

要将 OPA 作为 sidecar 集成,请按如下所示修改部署 YAML 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - name: sample-app
        image: sample-app:latest
        ports:
        - containerPort: 8080
      - name: opa-sidecar
        image: openpolicyagent/opa:latest
        args:
        - "run"
        - "--server"
        - "--config-file=/config/opa-config.yaml"
        volumeMounts:
        - mountPath: /config
          name: opa-config-volume
        - mountPath: /policies
          name: opa-policy-volume
      volumes:
      - name: opa-config-volume
        configMap:
          name: opa-config
      - name: opa-policy-volume
        configMap:
          name: opa-policy-config
Enter fullscreen mode Exit fullscreen mode

OPA sidecar 在拦截应用程序请求中的作用
该图展示了 Kubernetes 准入控制期间的 OPA webhook 评估过程,确保在创建资源之前安全地执行策略。

访问控制的 OPA 策略示例(Rego)

OPA策略使用Rego语言编写。以下是控制API端点访问的示例策略。

authz.rego

package authz
default allow = false
allow {
    input.user == "admin"
    input.action == "read"
}
allow {
    input.user == "developer"
    input.action == "view"
}
allow {
    input.role == "finance"
    input.action == "approve"
}
allow {
    input.ip == "192.168.1.1"
    input.method == "GET"
}
allow {
    input.role == "editor"
    startswith(input.path, "/editor-area/")
}
allow {
    input.role == "viewer"
    startswith(input.path, "/public/")
}
Enter fullscreen mode Exit fullscreen mode

规则说明

  • 管理员规则:授予具有管理员角色的用户读取权限。
  • 开发者规则:允许具有开发者角色的用户执行查看操作。
  • 财务角色规则:授予具有财务角色的用户审批权限。
  • 基于 IP 的限制规则:允许来自 IP 地址 192.168.1.1 的 GET 请求。适用于仅限内部使用的 API 端点。
  • 编辑者访问规则:授予具有编辑者角色的用户对以 /editor-area/ 开头的端点的访问权限。
  • 查看者访问规则:允许具有查看者角色的用户访问 /public/ 端点。

每条规则都确保了改善安全性、角色管理和资源控制的明确条件。

Java 集成 - OPA 策略执行

可以使用 HTTP 请求将 OPA 规则集成到 Java 应用程序中,以便与 OPA sidecar 进行通信。

访问控制的示例 Java 代码

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/secure")
public class SecureController {

    @PostMapping("/access")
    public ResponseEntity<String> checkAccess(@RequestBody Map<String, String> request) {
        RestTemplate restTemplate = new RestTemplate();
        String opaEndpoint = "http://localhost:8181/v1/data/authz";

        ResponseEntity<Map> response = restTemplate.postForEntity(opaEndpoint, request, Map.class);
        boolean allowed = (Boolean) response.getBody().get("result");

        if (allowed) {
            return ResponseEntity.ok("Access Granted");
        }
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Access Denied");
    }
}
Enter fullscreen mode Exit fullscreen mode

Node.js 集成 - OPA 策略执行

OPA 还可以通过 HTTP 请求查询 OPA sidecar,从而集成到 Node.js 应用程序中。

用于访问控制的 Node.js 示例代码

const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
app.post('/access', async (req, res) => {
    const opaEndpoint = 'http://localhost:8181/v1/data/authz';
    try {
        const response = await axios.post(opaEndpoint, { input: req.body });
        if (response.data.result) {
            res.status(200).send('Access Granted');
        } else {
            res.status(403).send('Access Denied');
        }
    } catch (error) {
        res.status(500).send('OPA Evaluation Failed');
    }
});
app.listen(3000, () => console.log('Server running on port 3000'));

Enter fullscreen mode Exit fullscreen mode

解释:

  • /access 端点将用户操作和角色转发到 OPA sidecar。
  • OPA 响应定义了请求是被接受还是被拒绝。

OPA集成最佳实践

  1. 尽量减少策略中的复杂逻辑:保持您的 Rego 策略简单,规则清晰,以避免性能瓶颈。
  2. 对策略进行版本控制:为防止兼容性问题,请对策略文件和捆绑包进行版本控制。
  3. 利用 OPA 的决策日志记录功能:启用 OPA 的决策日志,以便更好地进行观察和调试。
  4. 尽可能缓存 OPA 响应:对于重复评估,缓存可以提高性能。

分层策略执行示例(管理员、用户、访客角色)

OPA 通过为不同的用户角色定义清晰的安全边界,有效地实施基于角色的权限,例如:

  • 管理员:拥有完全控制权和无限制访问权限。
  • 用户:权限受限,基于既定标准。
  • 访客:仅限读取权限。

通过集成 OPA,开发人员可以实现强大的安全性、更高的合规性和动态策略执行——所有这些都无需直接修改应用程序代码。

基于角色的访问控制的注册策略示例

package authz
default allow = false
allow {
    input.user.role == "admin"
    input.action in ["create", "read", "update", "delete"]
}
allow {
    input.user.role == "user"
    input.action in ["read", "update"]
}
allow {
    input.user.role == "guest"
    input.action == "read"
}
Enter fullscreen mode Exit fullscreen mode

可视化不同角色如何获得不同的权限
该决策树可视化地展示了管理员、用户和访客等不同角色如何通过 Rego 策略获得不同的权限。

高流量环境下边车扩展性问题

  • CPU/内存开销:每个 OPA sidecar 都需要自己的资源,这在扩展 pod 时可能会增加开销。
  • 延迟影响: OPA 评估会引入延迟,尤其是在策略复杂的情况下。
  • 集群级策略管理:在数百个 pod 中扩展 sidecar 可能会产生维护开销。

解决方案:

  • 启用OPA 捆绑包缓存以减少频繁的策略获取。
  • 通过限制嵌套条件并利用部分求值来预先计算逻辑,从而优化 Rego 策略。
  • 对于大规模环境,可以考虑部署集中式 OPA 实例或使用OPA Gatekeeper以提高可扩展性。

策略版本控制最佳实践

  1. 使用 Git 进行版本控制
  2. 为策略实施 CI/CD 流水线
  3. 利用 OPA 的捆绑 API实现一致的策略分发。
  4. 标签稳定策略版本
  5. 自动回滚失效策略

步骤 3:面向开发人员的标记器实现

Flagger 在 CI/CD 流水线中的作用

Flagger 通过在 Kubernetes 中逐步将流量转移到金丝雀部署,同时测量成功率、延迟和自定义指标,实现渐进式交付的自动化。

Flagger 在确保 CI/CD 流水线中更安全、更自动化的发布方面发挥着至关重要的作用。通过集成 Flagger,开发人员可以:

  • 实现分阶段自动部署,降低部署风险。
  • 通过分析实时指标,持续验证新版本。
  • 在完全转移流量之前,触发 webhook 进行自动化测试或数据验证。

这种计算机化方法使开发人员能够自信地部署变更,同时最大限度地减少服务中断。下图展示了 Flagger 的自动化金丝雀部署流程:Flagger 触发负载测试,评估结果,并根据测试结果决定是将金丝雀版本升级为稳定版本还是在测试失败时将其回滚。
Flagger 的自动化金丝雀部署流程

Flagger Canary 部署配置

示例标记器金丝雀配置

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  provider: istio
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  progressDeadlineSeconds: 60
  autoscalerRef:
    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    gateways:
    - monitor/monitor-gw
    hosts:
    - monitor.dev.scus.cld.samsclub.com
    name: podinfo
    port: 9898
    targetPort: 9898
    portName: http
    portDiscovery: true
    match:
      - uri:
          prefix: /
    rewrite:
      uri: /
    timeout: 5s
  skipAnalysis: false
  analysis:
    interval: 1m
    threshold: 10
    maxWeight: 50
    stepWeight: 5
    metrics:
    - name: checkout-failure-rate
      templateRef:
        name: checkout-failure-rate
        namespace: istio-system
      thresholdRange:
        max: 1
      interval: 1m
    webhooks:
      - name: "load test"
        type: rollout
        url: http://flagger-loadtester.test/
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"
    alerts:
      - name: "dev team Slack"
        severity: error
        providerRef:
          name: dev-slack
          namespace: flagger
      - name: "qa team Discord"
        severity: warn
        providerRef:
          name: qa-discord
Enter fullscreen mode Exit fullscreen mode

关键字段说明

  • provider:指定服务网格提供程序,例如 istio、linkerd 等。
  • targetRef:指的是主部署。
  • autoscalerRef:将 canary 与 HPA 关联起来以实现自动扩展。
  • 分析:定义测试策略:
    • 间隔:每次流量增量之间的时间。
    • 阈值:回滚前失败的检查次数。
    • maxWeight:转移到金丝雀的最大流量百分比。
    • stepWeight:流量增量步长。
  • metrics:指定用于成功标准的 Prometheus metrics 模板。
  • webhook:在推广之前执行外部测试(例如,负载测试)。
  • 警报:定义 Slack、Discord 或 Teams 等服务的警报触发器。

用例:购物车系统的功能推出

想象一下,一个购物车应用需要测试新的结账逻辑。使用 Flagger 的金丝雀发布策略,您可以逐步引入新的结账流程,并通过监控订单成功率和延迟等指标来确保稳定性。

渐进式交通转移图

交通流向逐渐改变,由旗手指挥

渐进式交通转移策略
此图可视化了渐进式流量切换策略,其中流量从稳定版本逐步过渡到金丝雀版本,从而确保安全发布。
说明:

  • Flagger 会逐步将流量从稳定版切换到Canary版。
  • 如果金丝雀部署达到性能目标(例如延迟、成功率),流量将继续增加,直到全面推广。
  • 如果指标超过故障阈值,Flagger 会自动回滚金丝雀部署。

Webhook故障处理的最佳实践

为确保在 webhook 故障期间的恢复能力,请遵循以下做法:

  1. 实现带退避机制的重试:
    • 配置 webhook,使用指数退避算法重试失败的请求,以减少瞬态故障期间不必要的负载。
  2. 引入超时限制:
    • 为 webhook 响应添加超时设置,以避免金丝雀推广出现延迟。
  3. 实施备用警报:
    • 如果 webhook 在多次重试后失败,则配置警报系统以立即通知开发人员(例如,Slack、PagerDuty)。
  4. 添加 Webhook 健康检查:
    • 定期测试 webhook 端点,以便在部署失败发生之前主动检测和修复问题。

指标模板配置

Flagger 可以集成自定义指标,以增强渐进式交付的决策支持。下图展示了 Flagger 如何评估 Prometheus 指标,从而判断金丝雀发布是否成功。Flagger自定义指标配置示例
Prometheus 指标由 Flagger 进行评估。


apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: checkout-failure-rate
  namespace: istio-system
spec:
  provider:
    type: prometheus
    address: http://prometheus.istio-system:9090
  query: |
    100 - sum(
        rate(
            istio_requests_total{
              reporter="destination",
              destination_workload_namespace="{{ namespace }}",
              destination_workload="{{ target }}",
              response_code!~"5.*"
            }[{{ interval }}]
        )
    )
    /
    sum(
        rate(
            istio_requests_total{
              reporter="destination",
              destination_workload_namespace="{{ namespace }}",
              destination_workload="{{ target }}",
            }[{{ interval }}]
        )
    ) * 100
Enter fullscreen mode Exit fullscreen mode

解释:

  • 通过过滤掉 5xx 响应代码来计算成功请求的百分比。
  • 使用 Prometheus 作为后端来获取指标数据。

利用自定义 Prometheus 查询增强指标模板

为了提高 Flagger 的决策能力,可以考虑创建用于自定义指标的高级 Prometheus 查询。

用于 API 延迟分析的自定义 Prometheus 查询示例:

apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: api-latency-threshold
  namespace: istio-system
spec:
  provider:
    type: prometheus
    address: http://prometheus.istio-system:9090
  query: |
    histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="api-service"}[5m])) by (le))
Enter fullscreen mode Exit fullscreen mode

解释:

  • 此查询测量api 服务应用程序的第 95 百分位延迟。
  • 通过跟踪延迟分布而不是简单的平均值,开发人员可以及早发现性能下降的峰值。
  • 利用这些见解来调整您的 Flagger 分析步骤并提高部署安全性。

Flagger集成最佳实践

  1. 分阶段小步推进,更安全:逐步转移交通流量可最大限度地降低风险。
  2. 利用 Webhook 进行自动化测试: Webhook 允许在发布更改之前进行广泛的测试。
  3. 使用自定义指标获得更深入的洞察:跟踪直接影响业绩的关键业务指标。
  4. 确保警报渠道畅通: Slack、Discord 或 Teams 通知可帮助团队在发生故障时迅速采取行动。
  5. 集成负载测试:在金丝雀发布期间进行自动化负载测试,以验证其稳定性,然后再进行正式发布。

第四步:开发者自定义指标

为什么要使用自定义指标?

自定义指标通过跟踪应用程序特定的行为(例如结账成功率、队列大小或内存使用情况)来提供可操作的洞察。通过将指标与业务目标相结合,开发人员可以更深入地了解系统的性能。

  • 监控用户体验:跟踪延迟、响应时间或页面加载速度。
  • 衡量应用程序运行状况:观察错误率、服务可用性或队列积压情况。
  • 跟踪业务成果:监控订单、登录或交易成功率等关键绩效指标。

通过将这些见解融入指标中,开发人员可以改进故障排除,识别性能瓶颈,并将应用程序问题与用户体验影响联系起来。

自定义指标配置

开发人员可以使用Micrometer (Java) 或Prometheus Client (Node.js) 等库将自定义指标集成到他们的应用程序中。

Java 示例 - 使用 Micrometer 实现自定义指标

pom.xml 中的依赖关系

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <version>1.9.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

代码配置

@Configuration
public class MetricsConfig {

    @Bean
    public MeterRegistry meterRegistry() {
        return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
Enter fullscreen mode Exit fullscreen mode

自定义指标示例

@RestController
@RequestMapping("/api")
public class OrderController {

    private final Counter orderCounter;

    public OrderController(MeterRegistry meterRegistry) {
        this.orderCounter = Counter.builder("orders_total")
                .description("Total number of orders processed")
                .register(meterRegistry);
    }

    @PostMapping("/order")
    public ResponseEntity<String> createOrder(@RequestBody Map<String, String> request) {
        orderCounter.increment();
        return ResponseEntity.ok("Order Created");
    }
}
Enter fullscreen mode Exit fullscreen mode

使用 Micrometer 在 Java 应用程序中自定义指标
此图展示了使用 Micrometer 的 Java 应用程序中自定义指标的流程,其中数据在代码中定义,注册到 MeterRegistry,并通过 Grafana 进行可视化。

Node.js 示例 - 使用 Prometheus 客户端实现自定义指标

依赖关系
npm install prom-client

代码配置

const express = require('express');
const client = require('prom-client');

const app = express();
const collectDefaultMetrics = client.collectDefaultMetrics;
collectDefaultMetrics();

const orderCounter = new client.Counter({
    name: 'orders_total',
    help: 'Total number of orders processed'
});

app.post('/order', (req, res) => {
    orderCounter.inc();
    res.send('Order Created');
});

app.get('/metrics', async (req, res) => {
    res.set('Content-Type', client.register.contentType);
    res.end(await client.register.metrics());
});

app.listen(3000, () => console.log('Server running on port 3000'));
Enter fullscreen mode Exit fullscreen mode

使用 Prometheus 客户端库的 Node.js 应用程序
此图展示了如何使用 Prometheus Client 库在 Node.js 应用程序中处理自定义指标,并通过 /metrics 端点公开数据,以便在 Grafana 中进行可视化。

增强 Java Micrometer 示例

1. 添加延迟跟踪直方图

import io.micrometer.core.instrument.Timer;
import org.springframework.web.bind.annotation.*;
import io.micrometer.core.instrument.MeterRegistry;

@RestController
@RequestMapping("/api")
public class LatencyController {

    private final Timer requestTimer;

    public LatencyController(MeterRegistry meterRegistry) {
        this.requestTimer = Timer.builder("http_request_latency")
            .description("Tracks HTTP request latency in milliseconds")
            .publishPercentileHistogram()
            .register(meterRegistry);
    }

    @GetMapping("/process")
    public ResponseEntity<String> processRequest() {
        return requestTimer.record(() -> {
            try { Thread.sleep(200); } catch (InterruptedException e) {}
            return ResponseEntity.ok("Request Processed");
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

2. 添加系统级指标的计量器

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class QueueSizeMetric {

    private final AtomicInteger queueSize = new AtomicInteger(0);

    public QueueSizeMetric(MeterRegistry meterRegistry) {
        Gauge.builder("queue_size", queueSize::get)
            .description("Tracks the current size of the task queue")
            .register(meterRegistry);
    }

    public void addToQueue() {
        queueSize.incrementAndGet();
    }

    public void removeFromQueue() {
        queueSize.decrementAndGet();
    }
}
Enter fullscreen mode Exit fullscreen mode

通过标签最佳实践增强 Node.js 示例

推荐的标签标注规范:

  • 使用有意义的标签:重点关注状态码、端点或区域等关键因素。
  • 尽量减少高基数标签:避免使用具有唯一值的标签,例如 user_id 或 transaction_id。
  • 使用一致的命名规则:在各项指标中保持统一的命名模式。

改进的 Node.js 指标示例:

const client = require('prom-client');

const requestCounter = new client.Counter({
    name: 'http_requests_total',
    help: 'Total HTTP requests processed',
    labelNames: ['method', 'endpoint', 'status_code']
});

app.get('/checkout', (req, res) => {
    requestCounter.inc({ method: 'GET', endpoint: '/checkout', status_code: 200 });
    res.send('Checkout Complete');
});
Enter fullscreen mode Exit fullscreen mode

与 Flagger 集成 - 业务关键指标示例

用于跟踪结账失败的 Prometheus 查询示例:

apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
  name: checkout-failure-rate
  namespace: istio-system
spec:
  provider:
    type: prometheus
    address: http://prometheus.istio-system:9090
  query: |
    sum(rate(http_requests_total{job="checkout-service", status_code!="200"}[5m])) /
    sum(rate(http_requests_total{job="checkout-service"}[5m])) * 100
Enter fullscreen mode Exit fullscreen mode

解释:

  • 该指标追踪结账失败尝试的百分比,是衡量电子商务稳定性的关键指标。
  • 跟踪这些关键业务指标可以为开发人员提供可操作的洞察,从而改善客户体验。下图展示了 Flagger 如何监控 Prometheus 结账服务的指标,并在出现故障时通过 Alert Manager 触发回滚并通知 DevOps 团队。
    Flagger 监控 Prometheus 结账服务的指标

    自定义指标的最佳实践警报

  • 设定与业务影响相符的有意义的警报阈值。

  • 通过微调警报持续时间窗口来抑制过多的警报。

  • 使用 Prometheus AlertManager 主动发送服务性能下降警报。

结论

在 Kubernetes 环境中实现全面的可观测性极具挑战性,但对于确保应用程序的性能、安全性和稳定性至关重要。通过采用合适的工具和最佳实践,开发人员可以显著提升其微服务架构的可见性。

  • Tracestore使开发人员能够跨服务跟踪请求,从而改进根本原因分析并识别性能瓶颈。
  • OPA实施动态策略控制,通过确保一致的访问管理和保护数据完整性来增强安全性。
  • Flagger可自动进行渐进式交付,通过控制流量转移、基于指标的评估和主动回滚来降低部署风险。
  • 自定义指标通过跟踪关键应用程序行为,将性能监控与业务目标保持一致,从而提供可操作的见解。

通过结合使用这些工具,开发人员可以构建弹性、可扩展且安全的 Kubernetes 工作负载。遵循最佳实践,例如高效的跟踪传播、周密的 Rego 策略设计、战略性的 Flagger 配置以及定义完善的自定义指标,可确保您的 Kubernetes 环境能够满足性能需求和不断变化的业务目标。

采用这些可观测性解决方案,开发人员可以从被动故障排除转向主动优化,从而培养可靠性文化并改善用户体验。

参考

文章来源:https://dev.to/prabhucse/empowering-developers-to-achieve-microservices-observability-on-kubernetes-with-tracestore-opa-4mba