理解金絲雀發布策略

金絲雀發布(Canary Release)是一種將新版本應用佈署到小部分使用者或流量的策略,這種方法允許團隊在完全釋出前評估新版本的穩定性和效能。名稱源自早期礦工使用金絲雀檢測有毒氣體的做法—如果金絲雀死亡,礦工就知道環境不安全。

在軟體佈署中,“金絲雀"就是那小部分先體驗新版本的使用者或流量。如果新版本執行良好,團隊可以逐步增加流量比例,直到完全佈署;如果發現問題,可以立即回復,將損失降到最低。

實作金絲雀發布的 Rollout 資源

首先,讓我們建立一個 Argo Rollouts 的金絲雀佈署設定。以下是一個基本的 bgd-rollout.yaml 檔案:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: bgd-rollouts
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {}
      - setWeight: 40
      - pause: {duration: 30s}
      - setWeight: 60
      - pause: {duration: 30s}
      - setWeight: 80
      - pause: {duration: 30s}
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: bgd-rollouts
  template:
    metadata:
      labels:
        app: bgd-rollouts
    spec:
      containers:
      - image: quay.io/rhdevelopers/bgd:1.0.0
        name: bgd
        env:
        - name: COLOR
          value: "blue"
        resources: {}

這個設定檔案定義了一個 Argo Rollouts 資源,實作了一個精細控制的金絲雀發布策略:

  • replicas: 5 指定了總共需要執行 5 個 Pod
  • strategy.canary 設定了金絲雀佈署策略,包含以下步驟:
    • 首先將 20% 的流量導向新版本
    • 暫停佈署,等待手動確認
    • 將流量提升到 40%,並等待 30 秒
    • 繼續增加到 60%,再等待 30 秒
    • 增加到 80%,等待 30 秒
    • 最後完成 100% 流量遷移

這種策略允許團隊在每個階段評估新版本的表現,確保穩定後才繼續推進,如果發現問題可以隨時中止。

佈署應用並觀察初始狀態

讓我們應用這個設定來佈署應用:

kubectl apply -f bgd-rollout.yaml

由於這是初始佈署,Argo Rollouts 會直接建立所有 Pod,金絲雀策略在此時不會生效。我們可以檢查 Pod 狀態:

kubectl get pods

輸出將顯示 5 個執行中的 Pod:

NAME                            READY   STATUS    RESTARTS   AGE
bgd-rollouts-679cdfcfd-6z2zf    1/1     Running   0          12m
bgd-rollouts-679cdfcfd-8c6kl    1/1     Running   0          12m
bgd-rollouts-679cdfcfd-8tb4v    1/1     Running   0          12m
bgd-rollouts-679cdfcfd-f4p7f    1/1     Running   0          12m
bgd-rollouts-679cdfcfd-tljfr    1/1     Running   0          12m

使用 Argo Rollouts 的 kubectl 外掛可以獲得更詳細的訊息:

kubectl argo rollouts get rollout bgd-rollouts

輸出結果會顯示當前狀態:

Name:            bgd-rollouts
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
Step:            8/8
SetWeight:       100
ActualWeight:    100
Images:          quay.io/rhdevelopers/bgd:1.0.0 (stable)

Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5

NAME                                   KIND        STATUS     AGE    INFO
⟳ bgd-rollouts                         Rollout     ✔ Healthy  13m    
└──# revision:1                                                      
   └──⧉ bgd-rollouts-679cdfcfd         ReplicaSet  ✔ Healthy  13m    stable
      ├──□ bgd-rollouts-679cdfcfd-6z2zf Pod         ✔ Running  13m    ready:1/1
      ├──□ bgd-rollouts-679cdfcfd-8c6kl Pod         ✔ Running  13m    ready:1/1
      ├──□ bgd-rollouts-679cdfcfd-8tb4v Pod         ✔ Running  13m    ready:1/1
      ├──□ bgd-rollouts-679cdfcfd-f4p7f Pod         ✔ Running  13m    ready:1/1
      └──□ bgd-rollouts-679cdfcfd-tljfr Pod         ✔ Running  13m    ready:1/1

觸發金絲雀佈署流程

現在,讓我們佈署一個新版本,觸發金絲雀發布流程。建立一個新的 bgd-rollout-v2.yaml 檔案,內容與先前相同,但將環境變數 COLOR 從 “blue” 改為 “green”:

# bgd-rollout-v2.yaml 的關鍵部分
spec:
  containers:
  - image: quay.io/rhdevelopers/bgd:1.0.0
    name: bgd
    env:
    - name: COLOR
      value: "green"
    resources: {}

應用這個更新:

kubectl apply -f bgd-rollout-v2.yaml

現在,讓我們檢查 Pod 的狀態:

kubectl get pods

輸出將顯示新舊版本的 Pod 分佈:

NAME                            READY   STATUS    RESTARTS   AGE
bgd-rollouts-679cdfcfd-6z2zf    1/1     Running   0          27m
bgd-rollouts-679cdfcfd-8c6kl    1/1     Running   0          27m
bgd-rollouts-679cdfcfd-8tb4v    1/1     Running   0          27m
bgd-rollouts-679cdfcfd-tljfr    1/1     Running   0          27m
bgd-rollouts-c5495c6ff-zfgvn    1/1     Running   0          13s

注意到只有一個新的 Pod 被建立,這對應於我們設定的 20% 流量權重(5 個 Pod 中的 1 個)。

使用 Argo Rollouts 外掛檢視更詳細的狀態:

kubectl argo rollouts get rollout bgd-rollouts

輸出會顯示佈署處於暫停狀態,等待手動確認:

NAME                                   KIND        STATUS     AGE     INFO
⟳ bgd-rollouts                         Rollout     Paused     31m     
├──# revision:2                                                       
│  └──⧉ bgd-rollouts-c5495c6ff         ReplicaSet  ✔ Healthy  3m21s   canary
│     └──□ bgd-rollouts-c5495c6ff-zfgvn Pod         ✔ Running  3m21s   ready:1/1
└──# revision:1                                                       
   └──⧉ bgd-rollouts-679cdfcfd         ReplicaSet  ✔ Healthy  31m     stable
      ├──□ bgd-rollouts-679cdfcfd-6z2zf Pod         ✔ Running  31m     ready:1/1
      ├──□ bgd-rollouts-679cdfcfd-8c6kl Pod         ✔ Running  31m     ready:1/1
      ├──□ bgd-rollouts-679cdfcfd-8tb4v Pod         ✔ Running  31m     ready:1/1
      └──□ bgd-rollouts-679cdfcfd-tljfr Pod         ✔ Running  31m     ready:1/1

手動推進金絲雀佈署

由於我們在設定中設定了手動確認步驟(pause: {}),佈署流程現在處於暫停狀態。在確認新版本執行正常後,我們可以手動推進佈署:

kubectl argo rollouts promote bgd-rollouts

此命令會繼續執行剩餘步驟,根據我們的設定,流量會逐步增加(40% -> 60% -> 80% -> 100%),每個步驟間隔 30 秒。

再次檢查 Pod 狀態:

kubectl get pods

最終,所有 Pod 都會更新到新版本:

NAME                            READY   STATUS    RESTARTS   AGE
bgd-rollouts-c5495c6ff-2g7r8    1/1     Running   0          89s
bgd-rollouts-c5495c6ff-7mdch    1/1     Running   0          122s
bgd-rollouts-c5495c6ff-d9828    1/1     Running   0          13s
bgd-rollouts-c5495c6ff-h4t6f    1/1     Running   0          56s
bgd-rollouts-c5495c6ff-zfgvn    1/1     Running   0          11m

進階實踐:Argo Rollouts 與 Istio 整合

Argo Rollouts 的基本模式是透過控制 Pod 數量來實作流量分配,但這種方式存在一些侷限性。對於更精確的流量控制,我們可以將 Argo Rollouts 與服務網格技術(如 Istio)整合。

Argo Rollouts 與 Istio 的整合優勢

在我的實踐中,發現 Argo Rollouts 與 Istio 整合後能夠提供以下優勢:

  1. 精確的流量控制:Istio 可以在網路層面精確控制流量分配,而非依賴 Pod 數量
  2. 更豐富的路由規則:可以根據 HTTP 標頭、cookie 或其他條件進行流量導向
  3. 細粒度的網路策略:可以實施更複雜的網路策略和安全控制
  4. 可觀測性增強:Istio 提供了更豐富的監控和追蹤能力

實作 Istio 整合的 Rollout 資源

以下是一個與 Istio 整合的 Argo Rollouts 設定:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: bgdapp
  labels:
    app: bgdapp
spec:
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause:
          duration: "1m"
      - setWeight: 50
      - pause:
          duration: "2m"
      canaryService: bgd-canary
      stableService: bgd
      trafficRouting

## GitOps與雲原生佈署的演進之路

在現代軟體開發世界中,GitOps已經從一個新興概念演變為許多企業核心的佈署策略。當我開始接觸GitOps時,被其簡單而強大的理念所吸引:將Git作為單一事實來源,透過宣告式組態管理基礎設施和應用程式。這種方法不僅提升了佈署的可靠性,也極大地改善了團隊協作和系統可觀測性。

實施GitOps的過程中,我發現它特別適合Kubernetes環境。Kubernetes的宣告式設定與GitOps的理念完美契合,形成了一種高效的佈署模式。本文將帶領大家深入瞭解GitOps在Kubernetes上的實作,從核心概念到實用工具和最佳實踐。

### GitOps的核心原則與工作流程

GitOps建立在幾個關鍵原則上,這些原則共同定義了一個可靠與高效的系統管理方法:

1. 系統的期望狀態以宣告式方式定義並儲存在Git中
2. 任何狀態變更都透過Git操作(如提交、合併請求)進行
3. 自動化控制器確保系統的實際狀態與期望狀態比對
4. 所有變更都可追溯、可稽核和可回復

在GitOps工作流程中,開發人員不再直接與Kubernetes API互動來佈署應用程式。相反,他們提交更改到Git儲存函式庫後由自動化控制器(如Argo CD或Flux)檢測這些更改並將它們應用到叢集。這種方法建立了一個明確的佈署流程,提高了系統穩定性並減少了人為錯誤。

分析實際專案時,我發現GitOps工作流程通常包含以下迴圈:

- **內部迴圈**:開發人員在本地開發和測試應用程式
- **外部迴圈**:透過Git提交和CI/CD流程將更改佈署到生產環境

這種雙迴圈結構提供了快速迭代與穩定佈署之間的平衡。

## Kubernetes應用佈署模型

Kubernetes徹底改變了應用程式佈署的方式。不再是簡單地將應用程式放在伺服器上,而是採用宣告式設定來定義所需的狀態。這種模型完美契合GitOps的理念,因為兩者都強調宣告式而非命令式的操作方式。

### 本地Kubernetes叢集建置實務

在深入GitOps之前,建立一個本地Kubernetes環境進行實驗和學習是非常有價值的。經過多種工具的嘗試,我推薦以下幾種方案:

**使用kind建立本地叢集**:

```bash
# 安裝kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/

# 建立叢集
kind create cluster --name gitops-demo

這段命令首先下載kind工具(Kubernetes IN Docker),賦予執行許可權並移動到系統路徑中。然後建立一個名為gitops-demo的Kubernetes叢集。kind特別適合學習和測試環境,因為它在Docker容器中執行Kubernetes節點,資源消耗較少,與設定簡單。

使用Minikube作為替代方案

# 安裝Minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 啟動叢集
minikube start --driver=docker

Minikube是另一個流行的本地Kubernetes開發工具。這段命令下載並安裝Minikube,然後使用Docker驅動啟動一個單節點叢集。Minikube提供了更多的外掛和功能,但資源消耗稍高於kind。選擇哪種工具取決於個人偏好和系統資源。

在實際工作中,我發現kind通常啟動更快與更輕量,而Minikube則提供更豐富的功能和更接近生產環境的體驗。

Helm:Kubernetes應用封裝與佈署利器

在GitOps實踐中,Helm已成為管理Kubernetes應用的標準工具。它解決了Kubernetes原始清單管理的複雜性問題,提供了範本化、版本控制和發布管理功能。

Helm專案建立與結構設計

建立一個基本的Helm 圖表結構是理解Helm工作原理的第一步:

# 安裝Helm
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

# 建立一個新的Helm 圖表
helm create my-webapp

第一行安裝Helm 3,這是目前最新的主要版本,不需要在叢集中安裝Tiller(Helm 2的伺服器端元件)。第二行建立一個名為my-webapp的新圖表,它會生成一個標準的目錄結構,包含範本、值檔案和圖表中繼資料。

建立後的Helm 圖表結構如下:

my-webapp/
├── charts/                 # 依賴的子圖表
├── 圖表.yaml              # 圖表的中繼資料
├── templates/              # Kubernetes資源範本
│   ├── deployment.yaml     # 佈署定義
│   ├── _helpers.tpl        # 通用範本函式
│   ├── hpa.yaml            # 水平Pod自動擴充套件
│   ├── ingress.yaml        # Ingress設定
│   ├── NOTES.txt           # 安裝後的提示訊息
│   ├── serviceaccount.yaml # 服務帳號
│   ├── service.yaml        # 服務定義
│   └── tests/              # 測試資源
└── values.yaml             # 預設設定值

這個結構是Helm 圖表的核心,其中範本目錄包含了將要佈署到Kubernetes的資源定義,而values.yaml允許自定義這些範本。

Helm 圖表佈署與管理技巧

在實際工作中,我發現Helm 圖表的佈署和管理涉及多個關鍵步驟:

渲染並驗證Helm範本

# 渲染範本而不實際安裝
helm template my-webapp ./my-webapp

# 使用--debug選項檢視更詳細訊息
helm template my-webapp ./my-webapp --debug

這些命令將Helm 圖表範本渲染為Kubernetes清單,但不實際佈署。這是驗證範本是否正確的好方法,特別是在進行更改後。--debug選項提供更詳細的輸出,包括範本渲染過程中的中間值,這對於排查範本問題非常有用。

佈署Helm 圖表

# 安裝圖表
helm install my-webapp ./my-webapp

# 使用自定義值覆寫預設設定
helm install my-webapp ./my-webapp --set replicaCount=3 --set service.type=LoadBalancer

第一個命令使用預設值安裝圖表。第二個命令展示瞭如何在安裝時覆寫預設值,這裡我們將副本數量設為3,並將服務類別更改為LoadBalancer。這種靈活性使Helm非常強大,同一個圖表可以在不同環境中以不同設定佈署。

管理Helm發布

# 列出所有發布
helm list

# 升級現有發布
helm upgrade my-webapp ./my-webapp --set imageTag=v2.0.0

# 回復到先前版本
helm rollback my-webapp 1

這些命令展示了Helm的發布管理功能。helm list列出所有已安裝的圖表。helm upgrade更新現有佈署,例如更改映象標籤。helm rollback將發布回復到指定版本(這裡是版本1,即初始安裝)。這種版本控制機制是Helm的關鍵優勢之一,使得佈署更安全、更可控。

Helm 圖表分享與重用策略

Helm的強大之處還在於其圖表的分享和重用能力:

封裝與分發圖表

# 封裝圖表
helm package ./my-webapp

# 建立本地儲存函式庫kdir -p ~/helm-repo
mv my-webapp-0.1.0.tgz ~/helm-repo
helm repo index ~/helm-repo

# 增加儲存函式庫elm repo add local file://$HOME/helm-repo

這些命令展示瞭如何封裝圖表並建立本地儲存函式庫helm package建立一個壓縮的tgz檔案。然後我們建立一個目錄作為儲存函式庫動封裝的圖表到該目錄,並使用helm repo index`生成index.yaml檔案,這是Helm儲存函式庫心。最後,我們將本地儲存函式庫到Helm設定中。

**使用公共儲存函式庫:

# 增加常用的公共儲存函式庫elm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# 搜尋可用的圖表
helm search repo bitnami/nginx

# 安裝來自儲存函式庫表
helm install my-nginx bitnami/nginx

這裡展示瞭如何使用公共儲存函式庫itnami維護了一個包含許多常用應用的高品質儲存函式庫helm repo add命令增加儲存函式庫helm repo update更新本地快取的儲存函式庫。然後我們可以搜尋特定圖表並直接安裝它。這種方式大簡化了常用應用的佈署。

在實際專案中,我常使用圖表依賴來組合多個服務。例如,一個Web應用可能依賴於資料函式庫取服務:

# 圖表.yaml
dependencies:
  - name: postgresql
    version: 11.6.12
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled
  - name: redis
    version: 16.13.1
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled

這種相依性管理使得複雜應用的佈署變得更加模組化和可維護。

Kustomize:Kubernetes原生設定製工具

雖然Helm提供了豐富的範本功能,但有時我們需要一種更輕量級的方法來管理Kubernetes設定。這就是Kustomize的用武之地,它是Kubernetes的原生設定製工具。

Kustomize基礎結構與工作原理

Kustomize使用疊加的方式管理Kubernetes資源,而不是使用範本。它的基本工作流程是:

  1. 建立基礎資源檔案
  2. 建立kustomization.yaml定義如何修改這些資源
  3. 使用kustomize build命令生成最終設定

以下是一個簡單的Kustomize專案結構:

my-app/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    ├── development/
    │   └── kustomization.yaml
    └── production/
        └── kustomization.yaml

基礎設定可能如下:

# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app:1.0.0
        ports:
        - containerPort: 8080
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

這個基本結構展示了Kustomize的核心概念。base/目錄包含原始的Kubernetes資源定義和一個kustomization.yaml檔案,它列出了所有資源。overlays/目錄包含不同環境的特定設定。這種結構使得管理多環境設定變得簡單與直觀。

Kustomize組態管理與覆寫技術

Kustomize的強大之處在於其覆寫機制,允許為不同環境定製設定而不修改基礎檔案:

# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: prod-
replicas:
- name: my-app
  count: 3
images:
- name: my-app
  newName: registry.example.com/

## Kubernetes工作區與持久化的GitOps實踐

在現代雲原生環境中,GitOps已成為管理基礎設施和應用佈署的主流方法。然而,隨著專案規模擴大,如何有效管理Kubernetes工作區和確保設定持久化成為許多團隊面臨的挑戰。本文將分享玄貓在實際專案中積累的經驗,探討工作區管理策略和持久化解決方案。

### 工作區管理的挑戰與策略

Kubernetes工作區是邏輯上隔離的環境,允許團隊在同一叢集中獨立工作。在GitOps流程中,工作區管理直接影響佈署效率和系統穩定性。

#### 多工作區GitOps架構

在設計GitOps架構時,我發現多工作區策略能有效隔離不同環境和團隊的設定:

```yaml
# 工作區定義範例
apiVersion: v1
kind: Namespace
metadata:
  name: team-a-dev
  labels:
    workspace: team-a
    environment: development
---
apiVersion: v1
kind: Namespace
metadata:
  name: team-a-prod
  labels:
    workspace: team-a
    environment: production

這段設定建立了兩個名稱空間,分別用於同一團隊的開發和生產環境。透過標籤系統,我們建立了工作區的邏輯分組,使GitOps工具能夠識別相關資源。標籤workspace標識團隊,而environment則區分環境類別。這種結構允許我們在後續的GitOps流程中精確定位資源組。

實際上,工作區管理不僅是名稱空間的簡單區分,還包括:

  1. 資源配額與限制策略
  2. 網路策略與安全邊界
  3. RBAC許可權控制
  4. 監控與日誌收集策略

在大型組織中,我通常建議採用分層工作區架構,將企業級策略、團隊級設定和應用級定義清晰分離,形成可重用與易於維護的結構。

持久化解決方案

GitOps的核心是將所有設定儲存在Git中,但持久化資料需要特殊處理。在實踐中,有幾種模式可供選擇:

資料持久化模式

  1. Git外部儲存參照:將永續性儲存區宣告(PVC)定義在Git中,但實際資料儲存在外部
# 在GitOps倉函式庫義PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: application-data
  namespace: team-a-prod
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: managed-premium

這個PVC定義是GitOps管理持久化資料的典型方法。我們在Git中維護PVC定義,但實際資料儲存在雲提供商的永續性儲存區中。storageClassName指定使用高效能儲存類別,適合生產環境。這種方式的優勢是將設定與資料分離,允許GitOps工具管理資源定義,同時保持資料獨立性。

  1. 有狀態集合與持久標識:對於需要穩定網路標識和儲存的服務
apiVersion: apps/v1
kind: 有狀態集合
metadata:
  name: database-cluster
  namespace: team-a-prod
spec:
  serviceName: "database"
  replicas: 3
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
    spec:
      containers:
      - name: database
        image: postgres:14
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "managed-premium"
      resources:
        requests:
          storage: 10Gi

有狀態集合是管理有狀態應用的理想選擇。這個設定建立了一個包含三個PostgreSQL例項的叢集,每個例項都有自己的持久儲存。volumeClaimTemplates部分自動為每個Pod建立唯一命名的PVC,確保Pod重啟後能掛載相同的資料卷。這種方式特別適合資料函式庫要穩定網路身份和持久儲存的應用。

在實踐中,我發現將持久化策略與備份策略結合尤為重要。可以透過Kubernetes 定時工作或專用的備份工具(如Velero)定期將關鍵資料備份到外部儲存:

apiVersion: batch/v1
kind: 定時工作
metadata:
  name: database-backup
  namespace: team-a-prod
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: custom-backup-tool:v1.2
            env:
            - name: DB_HOST
              value: database-cluster-0.database
            - name: BACKUP_PATH
              value: /backups
            volumeMounts:
            - name: backup-volume
              mountPath: /backups
          volumes:
          - name: backup-volume
            persistentVolumeClaim:
              claimName: backup-storage
          restartPolicy: OnFailure

這個定時工作設定在每天凌晨2點執行資料函式庫。它連線到有狀態集合的第一個例項(database-cluster-0.database),執行備份操作並將結果儲存到專用的備份PVC中。將備份策略納入GitOps工作流程確保了資料保護措施與應用佈署保持同步。在設計備份解決方案時,我特別注重考慮還原測試的自動化,確保備份實際可用。

YAML與Kustomize進階設定

在GitOps實踐中,直接管理原始YAML檔案很快會變得難以維護。Kustomize作為Kubernetes的原生組態管理工具,提供了一種優雅的方式來組織和自定義設定。

Kustomize的層級結構

在我的專案中,通常採用以下Kustomize目錄結構:

base/
  kustomization.yaml
  deployment.yaml
  service.yaml
overlays/
  development/
    kustomization.yaml
    config-patch.yaml
  production/
    kustomization.yaml
    config-patch.yaml
    scaling-patch.yaml

基礎設定義通用元素,而覆寫層則根據環境提供特定的修改:

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
  app: my-application
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- config-patch.yaml
- scaling-patch.yaml
namespace: team-a-prod

這種層級結構是Kustomize的核心優勢。基礎目錄包含應用的通用定義,而覆寫目錄則包含特定環境的調整。在生產覆寫中,我們應用了兩個補丁:一個用於設定,另一個用於擴充套件引數。namespace欄位確保所有資源都佈署到指定名稱空間,這對維護環境隔離至關重要。

這種結構使團隊能夠分享基礎設定,同時允許環境特定的變化。從GitOps角度看,這減少了重複程式碼,降低了錯誤風險。

Patch表示式的高階應用

Kustomize的補丁功能不僅限於簡單的覆寫。在複雜場景中,我經常使用更精確的補丁表示式:

# overlays/production/scaling-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
spec:
  replicas: 5
  template:
    spec:
      containers:
      - name: main-container
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1000m"

這個補丁針對生產環境增加了副本數量並調整了資源限制。它只修改需要變更的欄位,保留基礎設定中的其他設定。這種精確控制使設定更具可讀性和可維護性。

對於更複雜的場景,JSON補丁提供了更精細的控制:

# overlays/production/advanced-patch.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

patches:
- target:
    group: apps
    version: v1
    kind: Deployment
    name: my-application
  patch: |-
    - op: replace
      path: /spec/template/spec/containers/0/image
      value: my-application:v2.3.4
    - op: add
      path: /spec/template/spec/containers/0/env/-
      value:
        name: FEATURE_FLAG
        value: "true"

這種JSON補丁格式提供了更精確的操作控制。第一個操作替換容器映像版本,第二個操作增加環境變數。這種方法特別適合需要精確欄位修改的複雜場景,如陣列元素的增加或替換。

在實踐中,我發現結合使用策略性合併補丁和JSON補丁能夠解決幾乎所有設定變更需求。選擇哪種方式主要取決於修改的複雜性和團隊的熟悉程度。

GitOps工作流程的持續改進

成功的GitOps實踐不僅關乎工具,還涉及流程和文化。在實施過程中,我總結了幾點關鍵經驗:

  1. 漸進式採用:從單一應用開始,逐步擴充套件到更多團隊和系統
  2. 自動化驗證:在CI流程中加入設定驗證,確保佈署前捕捉問題
  3. 可觀測性融合:將監控和告警設定納入GitOps流程,確保一致性
  4. 版本策略明確:為設定建立清晰的版本策略,便於回復和稽核
  5. 知識分享:建立團隊間的最佳實踐分享機制,避免重複解決相同問題

最終,GitOps是關於將軟體交付視為一個統一、可重複與可稽核的過程。透過將基礎設施和應用設定儲存在Git中,團隊獲得了透明度、可追溯性和協作的能力。

在GitOps實踐中,工作區管理和持久化策略是兩個關鍵挑戰,但透過精心設計的架構和適當的工具選擇,可以建立一個既靈活又穩定的系統。Kustomize的分層結構和補丁機制提供了處理環境差異的強大方法,使組態管理變得更加可控和可維護。

採用GitOps並不意味著一蹴而就地改變一切,而是逐步改進佈署流程,增強團隊對變更的信心。透過將工作區隔離、持久化管理和設定自定義納入GitOps流程,團隊可以實作更高效、更可靠的雲原生佈署。

在實施GitOps的旅程中,技術選擇固然重要,但更關鍵的是培養團隊對此方法的理解和認同。當團隊成員能夠輕鬆地透過Git提交來管理基礎設施,並確信這些變更會被可靠地應用時,GitOps的真正價值才得以實作。

透過本文介紹的技術和策略,希望能為正在實施或最佳化GitOps流程的團隊提供實用指導。隨著雲原生技術的不斷發展,GitOps實踐也將繼續演進,但其核心原則—將設定作為程式碼、自動化佈署和宣告式管理—將持續指導我們構建更強大、更可靠的系統。