返回文章列表

CI/CD 自動化 Helm Chart 部署完整實戰指南

深入解析 CI/CD 與 GitOps 技術在 Helm Chart 自動化部署的完整實務應用,從環境配置、Pipeline 架構設計到多環境部署策略。涵蓋 Jenkins MultiBranch Pipeline 配置、GitHub Pages Chart 倉庫整合、多層級 Values 管理與生產環境審批機制,提供台灣 DevOps 團隊可立即應用的技術方案與架構設計指引。

DevOps 實踐 容器化技術 自動化部署

在雲端原生應用程式的開發與維運領域中,持續整合與持續交付已經從輔助性工具演變為核心基礎設施的重要組成部分。這些技術範式不僅徹底改變了軟體交付的速度與品質標準,更深刻地重新定義了開發團隊與維運團隊之間的協作模式與責任邊界。Helm 作為 Kubernetes 生態系統中最廣泛採用的應用程式套件管理工具,其 Chart 封裝機制提供了標準化的應用程式版本控制與配置管理能力。透過將 Helm Chart 深度整合進入完整的 CI/CD 自動化流程,能夠建立起從程式碼提交到生產環境部署的端到端自動化交付通道。

本文將以台灣企業的實務案例為基礎,詳細解析如何建構一套完整且可靠的 Helm Chart 自動化部署系統架構。這套系統涵蓋了從開發環境到生產環境的完整多階段部署流程,每個部署階段都配備了適當的驗證機制與回滾策略保障。透過 Jenkins 的 MultiBranch Pipeline 強大功能,能夠針對不同的程式碼分支執行對應的部署策略規則,實現精細化的版本控制管理。GitHub Pages 作為輕量級 Chart 倉庫的託管平台,提供了穩定可靠的存取端點與完整的版本管理能力。整個架構設計嚴格遵循 GitOps 核心原則,將基礎設施配置與應用程式配置統一納入版本控制系統管理,確保每次變更都擁有完整的稽核軌跡記錄。

Kubernetes 命名空間隔離策略

在 Kubernetes 叢集環境中實施嚴格的環境隔離機制,是確保不同開發階段互不干擾的基礎架構設計決策。命名空間機制提供了邏輯層面的資源隔離能力,使得同一個實體運算叢集能夠安全可靠地託管多個獨立的應用環境。針對典型的三階段軟體開發流程,需要建立開發環境、測試環境與生產環境三個完全獨立的命名空間區域,每個命名空間都擁有獨立配置的資源配額限制與存取控制策略規則。

開發環境的命名空間通常採用較為寬鬆的資源限制配置策略,允許開發人員快速進行功能疊代與技術實驗探索。測試環境則需要盡可能模擬生產環境的真實配置條件,但可以接受相對較低的服務可用性要求標準。生產環境的命名空間必須配備最嚴格的安全策略規則與資源保障機制,確保關鍵業務服務的穩定運行不受其他環境活動的任何影響。

#!/usr/bin/env bash

# 建立開發環境命名空間
kubectl create namespace dev

# 建立測試環境命名空間
kubectl create namespace qa

# 建立生產環境命名空間
kubectl create namespace prod

# 為命名空間加入環境標籤
kubectl label namespace dev environment=development tier=dev
kubectl label namespace qa environment=qa tier=testing
kubectl label namespace prod environment=production tier=prod

# 驗證命名空間建立狀態
kubectl get namespaces --show-labels | grep -E "dev|qa|prod"

# 為各命名空間設定資源配額限制
kubectl create quota dev-resource-quota \
  --hard=requests.cpu=4,requests.memory=8Gi,limits.cpu=8,limits.memory=16Gi \
  --namespace=dev

kubectl create quota qa-resource-quota \
  --hard=requests.cpu=8,requests.memory=16Gi,limits.cpu=16,limits.memory=32Gi \
  --namespace=qa

kubectl create quota prod-resource-quota \
  --hard=requests.cpu=16,requests.memory=32Gi,limits.cpu=32,limits.memory=64Gi \
  --namespace=prod

# 查看資源配額狀態
kubectl get resourcequota --all-namespaces

# 建立命名空間級別的網路政策
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: prod
spec:
  podSelector: {}
  policyTypes:
  - Ingress
EOF

# 驗證網路政策配置
kubectl get networkpolicy --all-namespaces

命名空間的標籤與註解策略對於後續的資源管理追蹤至關重要。透過為每個命名空間加入環境類型標識、責任團隊資訊、成本中心歸屬等關鍵標籤,能夠在企業級監控系統與成本分析平台中實現精確的資源追蹤與費用分攤。網路政策的配置設定需要根據不同環境的安全特性進行差異化調整,開發環境可以允許相對開放的網路存取模式,而生產環境則必須實施嚴格的入站與出站流量控制規則。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 140

package "Kubernetes 叢集架構" {
  
  rectangle "開發命名空間 (dev)" as dev_ns {
    component "NGINX 開發版本" as nginx_dev
    component "資源配額\n4C/8G" as dev_quota
    note right of dev_quota
      **資源限制策略:
      CPU 請求: 4 核心
      記憶體請求: 8 GB
      CPU 限制: 8 核心
      記憶體限制: 16 GB
    end note
  }
  
  rectangle "測試命名空間 (qa)" as qa_ns {
    component "NGINX 測試版本" as nginx_qa
    component "資源配額\n8C/16G" as qa_quota
    note right of qa_quota
      **資源限制策略:
      CPU 請求: 8 核心
      記憶體請求: 16 GB
      CPU 限制: 16 核心
      記憶體限制: 32 GB
    end note
  }
  
  rectangle "生產命名空間 (prod)" as prod_ns {
    component "NGINX 生產版本" as nginx_prod
    component "資源配額\n16C/32G" as prod_quota
    note right of prod_quota
      **資源限制策略:
      CPU 請求: 16 核心
      記憶體請求: 32 GB
      CPU 限制: 32 核心
      記憶體限制: 64 GB
    end note
  }
}

cloud "網路隔離政策" as network {
  component "開發網路政策\n寬鬆規則" as dev_policy
  component "測試網路政策\n中等規則" as qa_policy
  component "生產網路政策\n嚴格規則" as prod_policy
}

dev_policy -down-> dev_ns: 套用政策
qa_policy -down-> qa_ns: 套用政策
prod_policy -down-> prod_ns: 套用政策

@enduml

Jenkins Pipeline 自動化架構

Jenkins 作為持續整合與持續交付流程的核心執行引擎,需要透過精心設計的配置來存取 Helm Chart 倉庫並管理複雜的多階段部署流程。GitHub Pages 提供了免費且穩定可靠的靜態檔案託管服務能力,非常適合作為輕量級 Helm Chart 倉庫的託管平台選擇。透過在 Jenkins 系統中配置適當的環境變數參數,能夠讓 Pipeline 腳本動態取得 Chart 倉庫的網路位置資訊,有效避免硬編碼方式帶來的長期維護成本問題。

#!/usr/bin/env bash

# 定義 Chart 倉庫的完整 URL 位址
GITHUB_USERNAME="your-github-username"
GITHUB_PAGES_SITE_URL="https://${GITHUB_USERNAME}.github.io/helm-charts/stable"

# 升級 Jenkins 實例並注入必要的環境變數
helm upgrade jenkins stable/jenkins \
  --namespace cicd \
  --version 2.19.0 \
  --reuse-values \
  --set controller.ingress.enabled=true \
  --set controller.jenkinsUrl="https://jenkins.example.com" \
  --set controller.adminPassword="${JENKINS_ADMIN_PASSWORD}" \
  --set-string "controller.initScripts.env-vars=\
export GITHUB_PAGES_SITE_URL=${GITHUB_PAGES_SITE_URL}\n\
export KUBECONFIG=/var/jenkins_home/.kube/config\n\
export HELM_CACHE_HOME=/var/jenkins_home/.cache/helm"

# 監控 Jenkins 控制器 Pod 的滾動更新狀態
kubectl rollout status deployment/jenkins-controller --namespace=cicd --watch

# 檢查新 Pod 的啟動日誌確認配置正確載入
kubectl logs --follow deployment/jenkins-controller --namespace=cicd --tail=100

# 驗證環境變數配置
kubectl exec -it deployment/jenkins-controller --namespace=cicd -- env | grep GITHUB_PAGES_SITE_URL

Jenkins 的動態 Agent 建置機制基於 Kubernetes Plugin 的容器化執行環境,每次 Pipeline 任務執行時都會動態啟動全新的 Pod 實例,任務執行完畢後自動進行資源清理回收。這種設計模式確保了每次建置作業都在完全乾淨的環境中執行,有效避免了環境狀態污染導致的非預期行為問題。

pipeline {
    agent {
        kubernetes {
            label "helm-deployment-${UUID.randomUUID().toString()}"
            yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    jenkins: agent
    app: helm-deployment
spec:
  serviceAccountName: jenkins-agent
  securityContext:
    fsGroup: 1000
  containers:
  - name: helm
    image: alpine/helm:3.10.0
    command:
    - cat
    tty: true
    resources:
      requests:
        memory: "256Mi"
        cpu: "250m"
      limits:
        memory: "512Mi"
        cpu: "500m"
  - name: kubectl
    image: bitnami/kubectl:1.25
    command:
    - cat
    tty: true
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "200m"
"""
        }
    }
    
    environment {
        CHART_REPO_URL = "${env.GITHUB_PAGES_SITE_URL}"
        CHART_NAME = 'nginx'
        REPO_NAME = 'enterprise-charts'
        GIT_COMMIT_SHORT = "${env.GIT_COMMIT.take(7)}"
    }
    
    options {
        buildDiscarder(logRotator(numToKeepStr: '30', daysToKeepStr: '90'))
        timestamps()
        timeout(time: 1, unit: 'HOURS')
    }
    
    stages {
        stage('環境準備') {
            steps {
                container('helm') {
                    sh '''
                        echo "驗證工具版本資訊"
                        helm version --short
                        
                        echo "加入 Chart 倉庫"
                        helm repo add ${REPO_NAME} ${CHART_REPO_URL}
                        
                        echo "更新倉庫索引"
                        helm repo update
                        
                        echo "搜尋可用的 Chart 版本"
                        helm search repo ${REPO_NAME}/${CHART_NAME} --versions
                    '''
                }
                container('kubectl') {
                    sh '''
                        echo "驗證 Kubernetes 叢集連線"
                        kubectl version --client
                        kubectl cluster-info
                        
                        echo "檢查命名空間狀態"
                        kubectl get namespaces dev qa prod
                    '''
                }
            }
        }
        
        stage('部署至開發環境') {
            steps {
                container('helm') {
                    script {
                        def releaseName = "${CHART_NAME}-${env.BRANCH_NAME}"
                        
                        echo "開始部署至開發環境: ${releaseName}"
                        
                        sh """
                            helm upgrade --install ${releaseName} \
                              ${REPO_NAME}/${CHART_NAME} \
                              --values nginx-cd/common-values.yaml \
                              --values nginx-cd/dev/values.yaml \
                              --namespace dev \
                              --create-namespace \
                              --wait \
                              --timeout 5m \
                              --atomic \
                              --cleanup-on-fail \
                              --description "Build: ${env.BUILD_NUMBER}, Commit: ${GIT_COMMIT_SHORT}" \
                              --set image.tag=${GIT_COMMIT_SHORT}
                        """
                        
                        echo "部署完成,驗證資源狀態"
                        sh """
                            kubectl get all -n dev -l app.kubernetes.io/instance=${releaseName}
                            kubectl describe deployment -n dev -l app.kubernetes.io/instance=${releaseName}
                        """
                    }
                }
            }
        }
        
        stage('開發環境驗證測試') {
            steps {
                container('helm') {
                    script {
                        def releaseName = "${CHART_NAME}-${env.BRANCH_NAME}"
                        
                        echo "執行 Helm 測試套件"
                        sh """
                            helm test ${releaseName} -n dev --timeout 3m --logs
                        """
                        
                        echo "檢查 Pod 日誌"
                        sh """
                            kubectl logs -n dev -l app.kubernetes.io/instance=${releaseName} \
                              --tail=100 --prefix=true
                        """
                    }
                }
            }
        }
    }
    
    post {
        success {
            echo "Pipeline 執行成功"
        }
        failure {
            echo "Pipeline 執行失敗,請檢查日誌"
        }
        always {
            echo "清理暫存資源"
        }
    }
}

這段完整的 Jenkins Pipeline 腳本展示了從環境準備到部署驗證的完整自動化流程。透過動態 Agent Pod 的設計,每個建置任務都擁有獨立的執行環境,有效避免了並發建置之間的資源競爭問題。環境變數的統一管理使得配置變更能夠集中控制,降低了維護複雜度。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 140

start

:Git 提交觸發 Webhook;
note right
  **觸發條件:
  推送至主要分支
  建立 Pull Request
  標籤發布事件
end note

:Jenkins 接收建置請求;

:動態建立 Agent Pod;
note right
  **Pod 規格配置:
  Helm 3.10 容器
  kubectl 1.25 容器
  資源限制設定
  服務帳戶綁定
end note

:環境準備階段;
fork
  :驗證 Helm 版本;
fork again
  :驗證 kubectl 連線;
fork again
  :加入 Chart 倉庫;
fork again
  :更新倉庫索引;
end fork

:部署至開發環境;
note right
  **部署參數:
  common-values.yaml
  dev/values.yaml
  動態映像標籤
  建置資訊註解
end note

:等待 Pod 就緒;

if (部署成功?) then (是)
  :執行驗證測試;
  
  if (測試通過?) then (是)
    if (主要分支?) then (是)
      :部署至測試環境;
      :執行整合測試;
      
      if (測試通過?) then (是)
        :等待生產審批;
        note right
          **審批要求:
          授權人員確認
          變更單號驗證
          回滾計畫審查
        end note
        
        if (獲得批准?) then (是)
          :部署至生產環境;
          :生產環境驗證;
          :發送成功通知;
          stop
        else (否)
          :取消部署;
          stop
        endif
      else (否)
        :標記失敗;
        stop
      endif
    else (否)
      :完成開發部署;
      stop
    endif
  else (否)
    :自動回滾開發環境;
    :記錄失敗原因;
    stop
  endif
else (否)
  :自動回滾操作;
  :發送告警通知;
  stop
endif

@enduml

Values 配置分層管理策略

Helm 的 Values 配置機制提供了強大且靈活的應用程式參數管理能力。透過多層 Values 檔案的合併機制,能夠在保持共通基礎配置的同時,實現不同環境的差異化配置需求。這種分層設計架構遵循了配置管理領域的最佳實踐原則,將不變的基礎配置內容與可變的環境特定配置內容明確分離,大幅降低了配置錯誤導致的部署失敗風險。

# nginx-cd/common-values.yaml
# 所有環境共用的基礎配置定義

replicaCount: 2

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21.6"

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

resources:
  requests:
    memory: "128Mi"
    cpu: "100m"
  limits:
    memory: "256Mi"
    cpu: "200m"

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 5
  successThreshold: 1
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 5
  periodSeconds: 5
  timeoutSeconds: 3
  successThreshold: 1
  failureThreshold: 3

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true

podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "9113"
  prometheus.io/path: "/metrics"

開發環境的配置檔案通常包含除錯相關的特殊設定項目,例如啟用詳細程度較高的日誌輸出級別、暴露額外的除錯診斷端點、適當放寬資源限制約束以便進行效能實驗測試等。測試環境則需要盡可能模擬生產環境的實際約束條件,但可以使用專門的測試用外部服務端點位址,有效避免測試活動對生產系統資料造成潛在影響。

# nginx-cd/prod/values.yaml
# 生產環境專屬配置定義

environment:
  name: "production"
  logLevel: "warn"

env:
  - name: ENVIRONMENT
    value: "production"
  - name: LOG_LEVEL
    value: "warn"
  - name: DATABASE_CONNECTION
    valueFrom:
      secretKeyRef:
        name: database-prod-credentials
        key: connection-string
  - name: REDIS_URL
    value: "redis://redis-cluster.prod.svc.cluster.local:6379/0"

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
  hosts:
    - host: nginx.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: nginx-prod-tls-cert
      hosts:
        - nginx.example.com

replicaCount: 5

resources:
  requests:
    memory: "1Gi"
    cpu: "1000m"
  limits:
    memory: "2Gi"
    cpu: "2000m"

autoscaling:
  enabled: true
  minReplicas: 5
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

podDisruptionBudget:
  enabled: true
  minAvailable: 3

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
            - key: app.kubernetes.io/name
              operator: In
              values:
                - nginx
        topologyKey: kubernetes.io/hostname

生產環境的配置必須經過嚴格的安全審查流程,確保所有安全相關的設定項目都已經正確啟用並符合企業安全政策要求。資源限制參數應該根據實際的負載壓力測試結果進行精確調整,預留充足的緩衝空間餘裕以妥善應對業務流量的高峰時段。監控指標與日誌收集相關的配置設定需要完整整合企業級的可觀測性平台系統,確保系統問題能夠被及時發現並快速處理解決。

玄貓認為,成功的 CI/CD 實踐不僅需要先進技術工具的完善支援,更需要組織文化與工作流程的深度配合。自動化部署能力能夠顯著提升軟體交付的整體速度,但這個前提條件是測試覆蓋率必須足夠高且測試品質可靠穩定。多環境管理策略有效降低了生產部署的風險程度,但同時也增加了基礎設施架構的整體複雜度與長期維護成本。

在實際導入這些先進技術的過程中,台灣企業需要根據團隊的技術成熟度水平與專案的具體特性需求進行適當調整,避免陷入過度工程化的技術陷阱。持續關注雲端原生技術領域的最新發展趨勢,適時採納經過驗證的新興最佳實踐方法,是保持企業技術競爭力的關鍵要素。GitOps 理念的深入應用將進一步提升整個系統的可追溯性與可靠性水準,而服務網格技術的逐步成熟則為流量管理與安全加固提供了全新的技術可能性。