iT邦幫忙

2025 iThome 鐵人賽

DAY 21
1

賢者大叔的容器修煉手札:

Day 21 - 微服務架構的奠基之路 🏗️

經過前面 20 天的修煉,我們已經掌握了 Kubernetes 的各種武器。今天,是時候建造我們自己的「微服務王國」了!就像建造一座城市需要先規劃基礎設施一樣,我們要為接下來的可觀測性和混沌工程實驗,建立一個穩固的後端服務架構。

今天來建立一個基本的後端服務架構,分別有order-serviceuser-service以及一台資料庫。
這將作為我們接著幾天的實驗場。

https://ithelp.ithome.com.tw/upload/images/20250905/20104930NsWVTqE09m.png

後端架構建立 + KinD + DevSpace

simple-ecommerce/
.
├── database
│   ├── devspace.yaml
│   └── postgres.yaml
├── deployments
│   ├── deploy-namespace.sh
│   ├── order-service.yaml
│   └── user-service.yaml
├── deploy-services.sh
├── devspace.yaml
├── go.mod
├── go.sum
├── kind-config.yaml
├── order-service
│   ├── devspace.yaml
│   ├── Dockerfile
│   └── main.go
├── shared
│   ├── config
│   │   └── config.go
│   └── telemetry
│       └── telemetry.go
└── user-service
  ├── devspace.yaml
  ├── Dockerfile
  └── main.go

因為整個系統有 2 個 API 服務和依賴一個資料庫,我們能活用之前學到的 DevSpace Dependencies:微服務編排的藝術 🎭來編排這三個服務的依賴關係跟啟動順序。

然後每個服務裡面也都有自己的 devspace.yaml 跟對應的 K8s DeploymentService 等資源的宣告。根目錄的devspace.yaml 則是用來定義全局相關的設定。

實戰

☸️ 建立 KinD Cluster:我們的遊樂場

第一步:建立王國的疆域

建立 namespace,這次的 pod 就都在這 ecommerce 下操作。

kubectl create namespace ecommerce --dry-run=client -o yaml | kubectl apply -f -
# day21/kind-config.yaml
# kind-config.yaml - 遊樂場的設計圖
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: ecommerce-cluster
nodes:
- role: control-plane  # 🎪 馬戲團團長(管理一切)
- role: worker        # 🎭 表演者1(運行應用)
- role: worker        # 🎭 表演者2(運行應用)
kind create cluster --config=kind-config.yaml

🎛️ 根目錄的總控制台

# day21/devspace.yaml
# devspace.yaml - 總指揮官的配置
version: v2beta1
name: ecommerce-microservices

# 🎼 依賴關係編排 - 就像樂團的演奏順序
dependencies:
  database:           # 🥁 鼓手先開始(基礎服務)
    path: ./database
    
  user-service:       # 🎹 鋼琴跟上(核心服務)
    path: ./user-service
    
  order-service:      # 🎻 小提琴最後(業務服務)
    path: ./order-service

# 🎮 開發模式配置 - 讓你像玩遊戲一樣調試
dev:
  user-service:
    labelSelector:
      app: user-service
    ports:
      - port: "8080:8080"    # 🚪 為用戶服務開門
  
  order-service:
    labelSelector:
      app: order-service
    ports:
      - port: "8081:8081"    # 🚪 為訂單服務開門
  
  postgresql:
    labelSelector:
      app: postgresql
    ports:
      - port: "5432:5432"    # 🚪 為資料庫開門

# 🛠️ 便民服務指令 - 就像遙控器的快捷鍵
commands:
  migrate:              # 🔄 一鍵資料庫初始化
    command: |-
      kubectl exec -it deployment/postgresql -- 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(),
          updated_at TIMESTAMP DEFAULT NOW()
      );
      -- 更多 SQL..."

  test:                 # 🧪 一鍵系統測試
    command: |-
      echo "🔍 測試用戶服務..."
      curl -X POST http://localhost:8080/users \
        -H "Content-Type: application/json" \
        -d '{"username":"testuser2","email":"test2@example.com"}'

  status:               # 📊 一鍵健康檢查
    command: |-
      echo "=== 🏥 系統健康檢查 ==="
      kubectl get pods -o wide
      curl -s http://localhost:8080/health || echo "❌ User service not ready"

🏦 資料庫服務:系統的記憶中樞

資料庫就像銀行的金庫,需要特別小心地設置:

# day21/database/devspace.yaml
# database/devspace.yaml - 金庫管理員的手冊
version: v2beta1
name: database

deployments:
  postgresql:
    kubectl:
      manifests:
        - ./postgres.yaml   # 📋 金庫建造藍圖

# 🎣 生命週期鉤子 - 像釣魚一樣等待時機
hooks:
  - name: "wait-for-database"
    events: ["after:deploy"]     # 🎪 部署完成後的表演
    command: |
      echo "⏳ 等待金庫就緒..."
      kubectl wait --for=condition=ready pod -l app=postgresql --timeout=300s
      sleep 10  # 😴 讓資料庫喝杯咖啡醒醒腦
      echo "✅ 金庫已就緒!"

  - name: "run-migrations"
    events: ["after:deploy"]
    command: |
      echo "🔧 開始裝修金庫內部..."
      kubectl exec deployment/postgresql -- 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(),
          updated_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,
          status VARCHAR(20) DEFAULT 'pending',
          created_at TIMESTAMP DEFAULT NOW(),
          updated_at TIMESTAMP DEFAULT NOW()
      );
      
      -- 🎁 放入一些樣品資料
      INSERT INTO users (username, email) VALUES 
      ('admin', 'admin@example.com'),
      ('testuser', 'test@example.com')
      ON CONFLICT (username) DO NOTHING;
      "
      echo "🎉 金庫裝修完成!"

建立 Order 服務:業務的核心引擎

訂單服務就像餐廳的廚房,負責處理所有的訂單邏輯:

# day21/order-service/devspace.yaml
# order-service/devspace.yaml - 廚房主廚的操作手冊
version: v2beta1
name: order-service

images:
  order-service:
    image: order-service:latest
    dockerfile: ./Dockerfile
    context: ..

deployments:
  order-service:
    kubectl:
      manifests:
        - ../deployments/order-service.yaml

dev:
  order-service:
    imageSelector: order-service:latest
    workingDir: /app
    ports:
      - port: "8081:8081"          # 🚪 廚房的專用通道
    env:
      - name: DATABASE_URL         # 🗺️ 金庫位置
        value: "postgres://postgres:postgres123@postgresql:5432/ecommerce?sslmode=disable"
      - name: USER_SERVICE_URL     # 🗺️ 前台位置
        value: "http://user-service:8080"
      - name: PORT
        value: "8081"

hooks:
  - name: "wait-for-order-service"
    events: ["after:deploy"]
    command: |
      echo "👨‍🍳 檢查主廚是否準備就緒..."
      kubectl wait --for=condition=ready pod -l app=order-service --timeout=300s
      echo "✅ 主廚已準備就緒!"

建立User服務:系統的門面擔當

用戶服務就像餐廳的前台接待,負責處理所有與客戶相關的事務:

# user-service/devspace.yaml - 前台接待員的工作手冊
version: v2beta1
name: user-service

# 🏭 映像工廠 - 打造服務的容器
images:
  user-service:
    image: user-service:latest
    dockerfile: ./Dockerfile
    context: ..                    # 📂 工廠的原料倉庫

deployments:
  user-service:
    kubectl:
      manifests:
        - ../deployments/user-service.yaml

# 🎮 開發者模式 - 讓你像超級瑪利歐一樣靈活
dev:
  user-service:
    imageSelector: user-service:latest
    workingDir: /app
    ports:
      - port: "8080:8080"          # 🚪 為客戶開啟專屬通道
    env:
      - name: DATABASE_URL         # 🗺️ 告訴服務金庫在哪裡
        value: "postgres://postgres:postgres123@postgresql:5432/ecommerce?sslmode=disable"
      - name: PORT
        value: "8080"

# 🎭 服務就緒檢查 - 像醫生檢查病人一樣仔細
hooks:
  - name: "wait-for-user-service"
    events: ["after:deploy"]
    command: |
      echo "🏥 檢查前台接待員是否就位..."
      kubectl wait --for=condition=ready pod -l app=user-service --timeout=300s
      echo "✅ 前台接待員已就位!"

第二步:啟動整個微服務生態系

# 🎮 進入開發模式(熱重載 + 端口轉發)
devspace dev --debug
20:55:50 info Using namespace 'ecommerce'
20:55:50 info Using kube context 'kind-demo'

第三步:測試我們的作品

# 🧪 測試用戶服務
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser2","email":"test2@example.com"}'

# 🧪 測試訂單服務
curl -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}'

# 📊 檢查系統狀態
devspace run status

也可以透過 devspace ui 來觸發我們自定義的 command 有個 status 能檢查系統。
https://ithelp.ithome.com.tw/upload/images/20250906/20104930w967NLTU8J.png

總結

今天我們建立的這個微服務架構,就像一座精心設計的實驗室。在接下來的日子裡,我們預計將在這個實驗室中:

  • Day 22-28:安裝各種「監控設備」(Prometheus、Grafana、Loki、Tempo)
  • Day 29:設計「實驗方案」(混沌工程測試案例)
  • Day 30:進行「壓力測試」(xk6-disruptor 實戰)

🎯 關鍵洞察
微服務不是銀彈,而是一把雙刃劍。 它帶來了靈活性和可擴展性,但也增加了複雜度。DevSpace Dependencies 這樣的工具,就是幫我們駕馭這把雙刃劍的利器。
好的架構不是一蹴而就的,而是在實踐中不斷演進的。 今天的基礎架構,將成為我們探索可觀測性和韌性工程的堅實基石。


上一篇
🌟 雲原生時代的內部迴圈革命:DevSpace 修煉心得總結
系列文
賢者大叔的容器修煉手札21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言