經過前兩天分別建立了 Fluent Bit 日誌收集和 OpenTelemetry Collector 可觀測性中樞,今天我們要完成最後的拼圖!就像指揮家統領整個交響樂團一樣,我們將用 DevSpace 的根目錄配置,一鍵啟動包含資料庫、微服務、日誌收集、指標追蹤的完整平台。這不只是技術整合,更是架構思維的昇華!
✅ 掌握 DevSpace 多層級依賴管理的精髓
✅ 實戰部署完整的可觀測性微服務架構
✅ 建立統一的開發、測試、監控工作流
✅ 驗證端到端的可觀測性數據流
🎭 昨日回顧:各自為政的時代
# 第 24 天:Fluent Bit Sidecar
cd user-service && devspace dev # 🏃♂️ 啟動用戶服務
cd order-service && devspace dev # 🏃♂️ 啟動訂單服務
kubectl apply -f fluent-bit-config.yaml # 📝 手動部署日誌配置
# 第 25 天:OTel Collector
cd observability/otel-collector && devspace dev # 🧠 啟動收集器
# 😵 問題:需要開多個 terminal,手動協調啟動順序
🎯 今日目標:一鍵交響樂
# 🎼 一條指令,啟動整個世界
devspace dev --debug
# ✨ 自動協調:
# 1. 資料庫先啟動
# 2. 配置文件部署
# 3. 微服務並行啟動
# 4. 可觀測性組件就緒
# 5. 所有端口自動轉發
層級 | 組件 | DevSpace 角色 | 啟動順序 |
---|---|---|---|
🗄️ 基礎設施層 | PostgreSQL | database/devspace.yaml | 1️⃣ 最先啟動 |
⚙️ 配置層 | ConfigMaps, Secrets | root/deployments/ | 2️⃣ 配置就緒 |
🚀 應用層 | User/Order Services | root/deployments/ | 3️⃣ 並行啟動 |
👁️ 觀測層 | OTel Collector | observability/otel-collector/ | 4️⃣ 最後就緒 |
# 🎼 依賴編排:像指揮家一樣精確控制
dependencies:
database: # 🗄️ 基石:先有數據庫
path: ./database
user-service: # 🏃♂️ 服務:依賴數據庫
path: ./user-service
order-service: # 🛒 服務:依賴數據庫
path: ./order-service
otel-collector: # 🧠 觀測:最後啟動
path: ./observability/otel-collector
# 🎯 部署統一管理:配置和服務分離
deployments:
services:
kubectl:
manifests:
- ./deployments/user-service.yaml # 📦 應用部署
- ./deployments/order-service.yaml # 📦 應用部署
- ./deployments/fluent-bit-config.yaml # ⚙️ 日誌配置
# 🎭 多場景管道:不同需求,不同啟動方式
pipelines:
dev: # 🎯 完整開發環境
run: |-
echo "🚀 Starting full ecommerce platform..."
create_deployments services # ⚙️ 先部署配置
run_dependencies database # 🗄️ 啟動數據庫
run_dependencies otel-collector # 🧠 啟動收集器
start_dev user-service # 🏃♂️ 開發模式服務
start_dev order-service # 🛒 開發模式服務
start_dev otel-collector # 👁️ 開發模式觀測
apps: # 🔧 純應用開發
run: |-
create_deployments services
run_dependencies database
start_dev user-service
start_dev order-service
obs: # 👁️ 純觀測開發
run: |-
create_deployments services
run_dependencies otel-collector
start_dev otel-collector
🌐 服務端口規劃
dev:
# 🏃♂️ 應用服務端口
user-service:
labelSelector:
app: user-service
ports:
- port: "8080:8080" # 🌐 REST API
logs:
enabled: true
order-service:
labelSelector:
app: order-service
ports:
- port: "8081:8081" # 🌐 REST API
logs:
enabled: true
# 🗄️ 數據庫端口
postgresql:
labelSelector:
app: postgresql
ports:
- port: "5432:5432" # 🗄️ PostgreSQL
# 🧠 觀測中樞端口
otel-collector:
labelSelector:
app: otel-collector
ports:
- port: "4317:4317" # 📡 OTLP gRPC
- port: "4318:4318" # 🌐 OTLP HTTP
- port: "13133:13133" # ❤️ Health Check
- port: "8889:8889" # 📊 Prometheus Metrics
- port: "55679:55679" # 🔍 zPages Debug
open:
- url: http://localhost:13133 # 🏥 健康檢查
- url: http://localhost:8889/metrics # 📈 指標查看
🎯 完整生命週期管理
commands:
# 📊 系統狀態總覽
status:
command: |-
echo "=== 🏗️ Namespace & Pods ==="
kubectl get pods -n ecommerce -o wide
echo "=== 🌐 Services ==="
kubectl get svc -n ecommerce
echo "=== 🔍 Quick Health Check ==="
echo "User Service: $(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health 2>/dev/null || echo 'Not Ready')"
echo "Order Service: $(curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/health 2>/dev/null || echo 'Not Ready')"
echo "OTel Collector: $(curl -s -o /dev/null -w "%{http_code}" http://localhost:13133 2>/dev/null || echo 'Not Ready')"
# 🗃️ 資料庫初始化
migrate:
command: |-
echo "🗃️ Running database migrations..."
kubectl exec -it deployment/postgresql -n ecommerce -- psql -U postgres -d ecommerce -c "
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
product_name VARCHAR(200) NOT NULL,
quantity INTEGER NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);"
# 🧪 端到端測試
test:
command: |-
echo "🧪 Running integration tests..."
echo "1️⃣ Creating test user..."
USER_RESPONSE=$(curl -s -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{"username":"testuser","email":"test@example.com"}')
echo "Response: $USER_RESPONSE"
echo "2️⃣ Creating test order..."
ORDER_RESPONSE=$(curl -s -X POST http://localhost:8081/orders \
-H "Content-Type: application/json" \
-d '{"user_id":1,"product_name":"Test Product","quantity":2,"total_amount":99.99}')
echo "Response: $ORDER_RESPONSE"
# 👁️ 可觀測性檢查
obs-check:
command: |-
echo "👁️ Observability Stack Health Check"
echo "=== OTel Collector ==="
echo "Health: $(curl -s http://localhost:13133 2>/dev/null || echo 'DOWN')"
echo "=== Key Metrics ==="
curl -s http://localhost:8889/metrics 2>/dev/null | grep -E "(otelcol_receiver_received|otelcol_exporter_sent)" | head -10
🎯 Hooks 自動化
hooks:
# 🧠 OTel 配置熱重載
- name: watch-otel-config
on:
paths:
- ./observability/otel-collector/otel-config.yaml
command: |-
echo "🔄 [Hook] OTel config changed → reloading..."
kubectl apply -f ./observability/otel-collector/otel-config.yaml
kubectl delete pod -l app=otel-collector -n ecommerce --ignore-not-found=true
# 📝 Fluent Bit 配置熱重載
- name: watch-fluent-config
on:
paths:
- ./deployments/fluent-bit-config.yaml
command: |-
echo "🔄 [Hook] Fluent Bit config changed → reloading..."
kubectl apply -f ./deployments/fluent-bit-config.yaml
kubectl delete pod -l app=user-service -n ecommerce --ignore-not-found=true
kubectl delete pod -l app=order-service -n ecommerce --ignore-not-found=true
# 🎼 一鍵啟動完整平台
> devspace dev --debug
23:38:20 info Using namespace 'ecommerce'
23:38:20 info Using kube context 'kind-demo'
23:38:21 debug Run pipeline:
name: dev
run: |-
run_dependencies --all
ensure_pull_secrets --all
build_images --all
create_deployments --all
start_dev --all
23:38:21 run_dependencies --all
23:38:21 Marked project excluded: ecommerce-microservices
23:38:21 Namespace is the default Devspace namespace
23:38:21 Namespace is the default Devspace namespace
23:38:21 Namespace is the default Devspace namespace
23:38:21 otel-collector create_deployments --all
23:38:21 Namespace is the default Devspace namespace
23:38:21 database run_dependencies --all
23:38:21 order-service run_dependencies --all
23:38:21 user-service run_dependencies --all
23:38:21 database ensure_pull_secrets --all
23:38:21 user-service ensure_pull_secrets --all
23:38:21 database build_images --all
23:38:21 otel-collector Deploying 2 deployments concurrently...
23:38:21 user-service build_images --all
23:38:21 database create_deployments --all
23:38:21 database Deploying 2 deployments concurrently...
23:38:59 debug Wait for dev to finish
佈署完成後,我們能透過 devspace ui
看見所有服務都如預期的起來了。
能看到 OTel collector 也確實收到了 FluentBit 傳送過來的 application tracing data
我想回顧的是Host otel-collector.ecommerce.svc.cluster.local
,這是很完整的 FQDN格式 。
我們之前有一篇學習 K8s Service
也能是Host otel-collector
,畢竟都在同一個namespace下的pod。
# 輸出到 OpenTelemetry Collector
[OUTPUT]
Name opentelemetry
Match app.logs
Host otel-collector.ecommerce.svc.cluster.local
Port 4318
Logs_uri /v1/logs
Log_response_payload True
Tls Off
Tls.verify Off
# 🔥 使用環境變數動態添加資源屬性
add_label service.name ${SERVICE_NAME}
add_label service.version ${SERVICE_VERSION}
add_label deployment.environment ${ENVIRONMENT}
恩...就零散的服務慢慢連結起來了。
有需要的話也是能透過之前分享過得 DevSpace Profile,來決定啟用多少服務。
# ================
# Profiles (不同運行模式)
# ================
profiles:
- name: apps-only
description: "只啟動應用服務,不包含觀測組件"
replace:
pipelines:
dev:
run: |-
echo "🔧 Apps-only mode"
create_deployments services
run_dependencies database
start_dev user-service
start_dev order-service
- name: obs-only
description: "只啟動觀測組件"
replace:
pipelines:
dev:
run: |-
echo "👁️ Observability-only mode"
create_deployments services
run_dependencies otel-collector
start_dev otel-collector
- name: minimal
description: "最小化部署,單一副本"
patches:
- op: replace
path: deployments.services.kubectl.manifests
value:
- ./deployments/fluent-bit-config.yaml
- name: debug
description: "除錯模式,開啟所有日誌和端口"
patches:
- op: add
path: dev.user-service.open
value:
- url: http://localhost:8080
- op: add
path: dev.order-service.open
value:
- url: http://localhost:8081
今天我們完成了從「分散管理」到「統一指揮」的重大躍進。這不只是技術整合,更是思維模式的轉變。就像從手工作坊進化到現代化工廠,我們建立了標準化、自動化、可觀測的微服務平台。
記住:優秀的架構規劃不是寫最多程式的人,而是用最少的配置實現最大價值的人。DevSpace 讓我們做到了這一點!