經過前一天建立了完整的 OTel → Loki 日誌數據流,今天我們要學習 OpenTelemetry Collector 項目本身是如何使用 KinD 進行端到端測試的!就像醫生需要在實驗室裡驗證新藥一樣,我們的可觀測性系統也需要在真實的 Kubernetes 環境中進行全面測試。今天讓我們深入 OpenTelemetry Contrib Collector 的測試架構,學習如何用 KinD 建立測試環境!
今日主要了解 OpenTelemetry Contrib Collector 在 GitHub CICD pipeline 中利用 KinD 建立測試環境來進行 e2e testing。
✅ 理解 OpenTelemetry Collector 如何使用 KinD 進行測試
✅ 掌握 KinD 在 CI/CD Pipeline 中的最佳實踐
🤔 為什麼需要在 Kubernetes 中測試?
# 🔴 傳統測試的局限性
docker run otel/opentelemetry-collector-contrib  # ✅ 單容器測試
go test ./...                                     # ✅ 單元測試
# 😵 但是無法測試:
# - Kubernetes 特定的 receiver(k8sattributes, k8sobjects)
# - 服務發現和自動配置
# - 多節點網路通訊交互
# - 真實的微服務間追蹤
# - Kubernetes 權限和 RBAC
🟢 KinD 解決的問題
# 現代測試方法:真實 K8s 環境
kind create cluster --config e2e-kind-config.yaml  # 🏗️ 建立測試集群
kubectl apply -f test-manifests/                   # 🚀 部署測試應用
go test --tags=e2e ./...                          # 🧪 端到端測試
kind delete cluster                                # 🧹 清理環境
# e2e-kind-config.yaml - OpenTelemetry 測試用 cluster配置
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
# 🔧 全局 kubeadm 配置
kubeadmConfigPatches:
  - |
    kind: KubeletConfiguration
    # 🔐 啟用 TLS bootstrap - 用於測試 kubeletstatsreceiver
    serverTLSBootstrap: true
# 🎯 節點配置
nodes:
  - role: control-plane
    labels:
      # 🏷️ 用於 k8sattributesprocessor e2e 測試的自定義標籤
      foo: too
🎨 配置特色分析
kubeadmConfigPatches:
  - |
    kind: KubeletConfiguration
    serverTLSBootstrap: true
nodes:
  - role: control-plane
    labels:
      foo: too
k8sattributesprocessor 提供測試標籤從 e2e-tests.yml 可以看到 OpenTelemetry 使用了非常完整的測試策略:
# 🎯 多維度測試矩陣
strategy:
  fail-fast: false
  matrix:
    k8s-version:
      - "v1.30.0"    # 🚀 最新版本
      - "v1.23.17"   # 🛡️ 舊版本兼容性
    component:
      - receiver/k8sclusterreceiver      # 🏗️ 集群級別監控
      - processor/k8sattributesprocessor # 🏷️ 屬性豐富化
      - receiver/kubeletstatsreceiver    # 📊 節點統計
      - receiver/k8sobjectsreceiver      # 🎭 物件監控
      - extension/observer/k8sobserver   # 👁️ 服務發現
collector-build:
  runs-on: ubuntu-24.04
  steps:
    - name: Build Collector
      run: make otelcontribcol
    - name: Upload Collector Binary
      uses: actions/upload-artifact@v4
docker-build:
  steps:
    - name: Build Docker Image
      run: make docker-otelcontribcol
    - name: export image to tar
      run: docker save otelcontribcol:latest > /tmp/otelcontribcol.tar
kubernetes-test-matrix:
  steps:
    - name: Create kind cluster
      uses: helm/kind-action@v1.12.0
      with:
        node_image: kindest/node:${{ matrix.k8s-version }}
        config: ./.github/workflows/configs/e2e-kind-config.yaml
    
    - name: Fix kubelet TLS server certificates
      run: |
        kubectl get csr -o=jsonpath='{range.items[?(@.spec.signerName=="kubernetes.io/kubelet-serving")]}{.metadata.name}{" "}{end}' | xargs kubectl certificate approve
其中一個 e2e 測試程式在這,是以 Go 撰寫設計的。
透過宣告註解//go:build e2e 然後執行 go test -v --tags=e2e 就只會對有宣告該註解的測試腳本執行測試。
相關的GitHub Action的執行結果如下。

//go:build e2e
// +build e2e
package k8sobserver
import (
    "context"
    "testing"
    "time"
    
    "github.com/stretchr/testify/require"
    "go.opentelemetry.io/collector/component/componenttest"
    "go.opentelemetry.io/collector/extension/extensiontest"
)
🎯 標籤機制的優勢:
func TestK8sObserver_EndToEnd(t *testing.T) {
    // 🎯 測試設置
    ctx := context.Background()
    
    // 🔧 建立測試配置
    cfg := &Config{
        AuthType: "serviceAccount",
        Node:     "${K8S_NODE_NAME}",
    }
    
    // 🏗️ 建立擴展實例
    factory := NewFactory()
    extension, err := factory.CreateExtension(ctx, extensiontest.NewNopCreateSettings(), cfg)
    require.NoError(t, err)
    
    // 🚀 啟動擴展
    err = extension.Start(ctx, componenttest.NewNopHost())
    require.NoError(t, err)
    defer extension.Shutdown(ctx)
    
    // 🧪 執行測試邏輯
    observer := extension.(*k8sObserver)
    
    // ⏳ 等待服務發現
    time.Sleep(10 * time.Second)
    
    // 🔍 驗證發現的端點
    endpoints := observer.ListEndpoints()
    require.NotEmpty(t, endpoints, "Should discover at least one endpoint")
    
    // 🎯 驗證端點屬性
    for _, endpoint := range endpoints {
        require.NotEmpty(t, endpoint.ID, "Endpoint should have ID")
        require.NotEmpty(t, endpoint.Target, "Endpoint should have target")
        
        // 🏷️ 驗證 Kubernetes 屬性
        attrs := endpoint.Details.GetAttributes()
        require.Contains(t, attrs, "k8s.namespace.name")
        require.Contains(t, attrs, "k8s.pod.name")
    }
}
小弟將自己的程式碼跟 GitHub Actions 做整合。

從 GitHub Actions 執行結果可以看到,我成功實現了一個完整的 KinD E2E 測試流程!🎉
✅ build-app: 47s       # 應用程式建置
✅ build-test: 1m 59s   # 測試映像建置  
✅ e2e-test (v1.30.0)   # Kubernetes 1.30 測試
✅ e2e-test (v1.29.0)   # Kubernetes 1.29 測試
✅ e2e-summary: 3s      # 測試總結
// cmd/server/main.go - 簡潔的測試應用
type HealthResponse struct {
    Status    string            `json:"status"`
    Timestamp time.Time         `json:"timestamp"`
    Version   string            `json:"version"`
    Env       map[string]string `json:"env"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
    response := HealthResponse{
        Status:    "healthy",
        Timestamp: time.Now(),
        Version:   os.Getenv("APP_VERSION"),
        Env: map[string]string{
            "KUBERNETES_SERVICE_HOST": os.Getenv("KUBERNETES_SERVICE_HOST"),
            "HOSTNAME":               os.Getenv("HOSTNAME"),
        },
    }
    // ... JSON response
}
// test/e2e/e2e_test.go
//go:build e2e
// +build e2e
func TestApplicationHealthEndpoint(t *testing.T) {
    // 🔍 健康檢查端點測試
    resp, err := http.Get("http://go-e2e-app-service:8080/health")
    require.NoError(t, err)
    defer resp.Body.Close()
    
    require.Equal(t, http.StatusOK, resp.StatusCode)
    
    var health HealthResponse
    err = json.NewDecoder(resp.Body).Decode(&health)
    require.NoError(t, err)
    require.Equal(t, "healthy", health.Status)
}
# k8s/deployment.yaml - 完整的部署配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-e2e-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: go-e2e-app
  template:
    spec:
      containers:
      - name: app
        image: go-e2e-app:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 8080
        env:
        - name: APP_VERSION
          value: "1.0.0"
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
# k8s/rbac.yaml - 測試用服務帳戶
apiVersion: v1
kind: ServiceAccount
metadata:
  name: e2e-test-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: e2e-test-role
rules:
- apiGroups: [""]
  resources: ["pods", "services", "endpoints"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list"]
# test/k8s/e2e-job.yaml - Kubernetes Job 執行測試
apiVersion: batch/v1
kind: Job
metadata:
  name: e2e-test
spec:
  backoffLimit: 2
  template:
    spec:
      serviceAccountName: e2e-test-sa
      containers:
      - name: e2e-test
        image: go-e2e-test:latest
        imagePullPolicy: Never
        command: ["go", "test", "-v", "--tags=e2e", "./test/e2e/"]
      restartPolicy: Never
我們從 OpenTelemetry 學到的經驗
# 將測試環境配置版本化
kind-config.yaml     # 集群配置
test-manifests/      # 測試用 K8s 資源
e2e-tests/          # 測試腳本
Makefile            # 自動化命令
# 使用不同的集群名稱避免衝突
cluster_name: e2e-test-${{ github.run_id }}
# 完整的測試流程
kind create cluster → 部署應用 → 執行測試 → 收集結果 → 清理環境
# 階段 1: 基本功能測試
make test
# 階段 2: 容器化測試
make docker-build && make test
# 階段 3: Kubernetes 整合測試
make e2e-local
# 階段 4: 多環境兼容性測試
GitHub Actions 自動執行
KinD 讓我們能在 CI/CD 中運行接近運營環境的測試
        🔺 E2E Tests (少量,高價值)
       🔺🔺 Integration Tests (適量)
    🔺🔺🔺🔺 Unit Tests (大量,快速)