Ohhnews

分类导航

$ cd ..
foojay原文

使用 Dash0 实现从零到全栈可观测性

#可观测性#kubernetes#dash0#云原生#应用监控

目录

本指南将详细介绍如何将一个极简的 Spring Boot 服务部署到 Kubernetes,并使用 Dash0 Operator 实现完整的可观测性——且无需对应用程序代码进行任何修改。

Dash0 是一个原生支持 OpenTelemetry 的可观测性平台,能够收集并关联链路追踪(traces)、指标(metrics)和日志(logs),同时提供针对 Kubernetes 资源(如 Pod、节点、命名空间、部署、守护进程集、有状态集、作业和定时作业)以及云基础设施(如 AWS)的监控。其 Kubernetes Operator 可以在 Pod 级别自动对工作负载进行插桩,无需更改应用程序代码或容器镜像。

该设置分为两个不同阶段。第一阶段确立“之前”的状态:服务在 Kubernetes 中运行且没有任何插桩,产生的流量对于任何可观测性工具来说都是完全不可见的。第二阶段将 Dash0 Operator 添加到集群中,它会自动对工作负载进行插桩,并开始将链路追踪、指标和日志发送到 Dash0——同样,无需对应用程序本身进行任何更改。

整个工作流程无需本地安装 Docker。Docker 镜像通过 GitHub Actions 构建并推送,Kubernetes 集群则在 GitHub Codespace 中运行。

之前:没有可观测性的服务

第 1 部分:构建应用程序

起点是一个极简的 Spring Boot REST API,没有配置任何可观测性。没有 OpenTelemetry,没有 Micrometer,没有日志框架——只有 web starter 和一个包含两个端点的控制器。这就是“之前”的状态:一个正在运行但完全不可见的服务。

1. 创建 pom.xml。创建一个只包含一个依赖项的 pom.xml

$ xml
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

只有一个依赖,没有遥测——这是刻意为之的。没有任何 OpenTelemetry 或指标库正是“之前”状态的核心意义所在。

2. 创建主应用程序类。创建 src/main/java/com/example/demo/DemoApplication.java

$ java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

这是标准的 Spring Boot 入口点——除了启动应用程序所需的最低配置外,没有其他内容。

3. 创建控制器。创建 src/main/java/com/example/demo/OrderController.java

$ java
package com.example.demo;

import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
public class OrderController {

    @GetMapping("/orders")
    public List<String> getOrders() {
        return List.of("order-1", "order-2", "order-3");
    }

    @PostMapping("/orders")
    public String createOrder(@RequestBody String order) {
        return "Created: " + order;
    }
}

两个端点都没有日志、插桩或链路追踪——当此服务运行时,你无法了解其运行状态。

4. 构建应用

$ bash
mvn package -DskipTests

这会将应用程序打包成 target/ 目录下的一个可执行 JAR 文件,该文件将在下一步被复制到 Docker 镜像中。

第 2 部分:容器化与发布

要在 Kubernetes 中运行该应用,需要将其打包为容器镜像。我们不使用本地构建和推送 Docker 镜像,而是利用 GitHub Actions 在云端完成此操作。这避免了对本地 Docker 安装的需求。

1. 创建 Dockerfile。此 Dockerfile 使用 Azul Zulu 25 作为基础镜像。

$ dockerfile
FROM azul/zulu:25-jre
COPY target/order-service.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

2. 创建 GitHub Actions 工作流。创建 .github/workflows/build.yml。该工作流会构建 Maven 项目,使用存储库密钥登录 Docker Hub,并推送镜像。它会在每次推送到主分支时自动触发。

$ config
name: Build and Push Docker Image

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '25'
          distribution: 'zulu'

      - name: Build with Maven
        run: mvn package -DskipTests

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ secrets.DOCKER_USERNAME }}/order-service:latest

3. 将 Docker Hub 密钥添加到 GitHub。进入 GitHub 仓库的 Settings → Secrets and variables → Actions 并添加:

  • DOCKER_USERNAME —— 你的 Docker Hub 用户名
  • DOCKER_PASSWORD —— 你的 Docker Hub 密码或访问令牌

推送工作流文件后,GitHub Actions 将自动构建并将镜像推送到 Docker Hub。

延伸阅读:

第 3 部分:部署到 Kubernetes

镜像上传到 Docker Hub 后,我们可以将其部署到 Kubernetes。我们使用 GitHub Codespaces 作为环境,它提供了一个浏览器内的完整 Linux 终端,无需任何本地工具。在此环境中,我们安装 kind,它会在 Codespace 内启动一个集群。

1. 打开 Codespace。进入 GitHub 仓库,点击 Code → Codespaces → Create codespace on main

2. 安装 kind 并创建集群

$ bash
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
kind create cluster

3. 创建 Kubernetes 清单。该清单定义了一个包含一个副本的 Deployment 和一个将其暴露在 80 端口的 Service。镜像引用直接指向前一步推送到 Docker Hub 的镜像。

创建 deployment.yaml

$ config
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: geertjanwielenga/order-service:latest
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
    - port: 80
      targetPort: 8080

4. 部署应用。应用清单并更新镜像引用以指向正确的 Docker Hub 镜像:

$ bash
kubectl apply -f deployment.yaml
kubectl set image deployment/order-service order-service=geertjanwielenga/order-service:latest
kubectl get pods

等待 Pod 显示为 Running

延伸阅读:

第 4 部分:生成流量(初始状态)

由于我们在 Codespace 内部,而不是在本地运行,因此服务无法直接在 localhost 上访问。我们使用 kubectl port-forward 来弥补这一差距。这就是初始状态——服务正在运行并接收流量,但 Dash0 中没有任何显示。没有链路追踪,没有指标,没有日志。

1. 启动端口转发(终端 1)

$ bash
kubectl port-forward svc/order-service 8080:80

2. 启动流量循环(终端 2)。打开第二个终端并运行:

$ bash
while true; do curl http://localhost:8080/orders; sleep 1; done

之后:使用 Dash0 Operator 添加可观测性

第 5 部分:安装 Dash0 Operator

现在我们添加可观测性——无需触碰应用程序代码、pom.xml 或 Docker 镜像。Dash0 Operator 使用 Helm 安装到集群中。它运行在自己的命名空间中,负责将插桩注入工作负载,并将遥测数据转发到 Dash0。

请注意,正确的 Helm 仓库 URL 是 https://dash0hq.github.io/dash0-operator。请在一行中运行安装命令以避免 shell 解析错误。将 <your-region> 替换为您 Dash0 入口端点中的区域,将 <your-auth-token> 替换为您 Dash0 组织中的身份验证令牌。两者都可以在 Dash0 的 Settings → Auth Tokens 中找到。

1. 添加 Helm 仓库并安装 Operator(终端 3)

$ bash
helm repo add dash0-operator https://dash0hq.github.io/dash0-operator
helm repo update dash0-operator
helm install dash0-operator dash0-operator/dash0-operator --namespace dash0-system --create-namespace --set operator.dash0Export.endpoint=ingress.<your-region>.dash0.com:4317 --set operator.dash0Export.token=<your-auth-token>

2. 验证 Operator 是否正在运行

$ bash
kubectl get pods -n dash0-system

等待 Operator Pod 显示为 Running

延伸阅读:

第 6 部分:配置 Operator

仅安装 Helm Chart 是不够的。Operator 还需要一个 Dash0OperatorConfiguration 资源来了解将遥测数据发送到哪里,以及一个 Dash0Monitoring 资源来了解要对哪个命名空间进行插桩。缺少这两者,数据将无法流入 Dash0。

1. 创建 Operator 配置资源

$ bash
cat <<EOF | kubectl apply -f -
apiVersion: operator.dash0.com/v1alpha1
kind: Dash0OperatorConfiguration
metadata:
  name: dash0-operator-configuration
spec:
  export:
    dash0:
      endpoint: ingress.<your-region>.dash0.com:4317
      authorization:
        token: <your-auth-token>
EOF

2. 启用命名空间的监控。此资源用于开启默认命名空间中所有工作负载的插桩。导出配置必须直接包含在资源中。

$ bash
cat <<EOF | kubectl apply -f -
apiVersion: operator.dash0.com/v1alpha1
kind: Dash0Monitoring
metadata:
  name: dash0-monitoring
  namespace: default
spec:
  export:
    dash0:
      endpoint: ingress.<your-region>.dash0.com:4317
      authorization:
        token: <your-auth-token>
EOF

延伸阅读:

第 7 部分:重启与验证

Operator 通过初始化容器(init container)在 Pod 启动时注入插桩。由于 Pod 在创建监控资源之前已经在运行,因此需要重启它,以便 Operator 对其进行插桩。

1. 重启部署

$ bash
kubectl rollout restart deployment/order-service
kubectl get pods

等待新的 Pod 显示为 Running

2. 重启端口转发(终端 1)。使用 Ctrl+C 终止现有的端口转发并重启:

$ bash
kubectl port-forward svc/order-service 8080:80

终端 2 中的 curl 循环将自动恢复。

3. 打开 Dash0。访问 app.dash0.com。随着插桩后的 Pod 运行且流量流动,遥测数据将在 1 到 2 分钟内开始出现。我们没有对应用程序代码、pom.xml 或 Docker 镜像进行任何更改。唯一添加的就是 Dash0 Operator 和两个 Kubernetes 清单。

检查以下内容:

  • Monitoring → Servicesorder-service 及其实时请求率、错误率和延迟。
  • Telemetry → Tracing:每个 /orders 请求的独立链路追踪。
  • Telemetry → Logging:结构化日志。
  • Monitoring → Kubernetes:Pod 和节点的资源使用情况。

延伸阅读: