在2025年的技術環境中,軟體發布速度與更新頻率已成為企業競爭力的關鍵指標。為了在市場中保持領先地位,公司必須不斷縮短新功能的開發與佈署時間。持續整合(CI)與持續交付/佈署(CD)的方法學已經從選項變成了必需品。
在我帶領團隊實施多個大型專案的過程中,CI/CD流程一直是提升團隊效率的核心支柱。CI/CD不僅是一套工具,更是一種思維方式,它能徹底改變團隊協作與軟體交付的方式。
CI/CD為組織帶來的關鍵優勢
當企業成功匯入CI/CD流程時,會獲得以下顯著效益:
- 測試時間大幅縮減:自動化測試流程消除了手動測試的瓶頸,加速了反應迴圈
- 整合階段錯誤最小化:頻繁的小型變更比大規模更新更容易測試和識別問題
- 加速產品上市時間:自動化佈署流程讓開發團隊能夠更快地推出更新
- 簡化版本管理:每個程式碼變更都可以被封裝成獨立的版本,使追蹤和管理變得更加簡單
多階段Docker映像建置:精簡與最佳化
在我多年的DevOps實踐中,多階段Docker映像建置(Multi-stage builds)始終是我推薦給團隊的首要最佳實踐。這種方法不僅能顯著減小最終映像的大小,還能提升安全性與佈署效率。
多階段建置的工作原理是將Docker建置過程分為多個階段,只將必要的程式碼和依賴函式庫最終映像,而將建置工具、暫存檔案和中間產物留在建置階段。這帶來了幾個顯著優勢:
- 映像體積顯著縮小:在一個實際專案中,我曾透過多階段建置將微服務容器映像從1.2GB縮減至120MB,提升了佈署速度與資源利用效率
- 相依性管理簡化:分離建置環境和執行環境,讓相依性管理變得更加清晰
- 減少安全風險面:移除不必要的函式庫具,降低潛在漏洞的攻擊面
以下是一個Python應用程式的多階段Dockerfile範例:
# 建置階段
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
# 最終階段
FROM python:3.11-slim
WORKDIR /app
# 僅複製必要檔案
COPY --from=builder /app/wheels /wheels
COPY --from=builder /app/requirements.txt .
RUN pip install --no-cache /wheels/*
COPY ./src .
CMD ["python", "app.py"]
這個範例展示瞭如何將依賴項建置與應用程式執行分離,確保最終映像只包含執行時必要的元素。
Kaniko:安全的容器映像建置工具
在安全敏感的環境中,特別是在Kubernetes叢集內佈署CI/CD流程時,Kaniko成為了我的首選工具。Kaniko允許在無需特權存取的情況下建置Docker映像,這使它成為CI/CD流程中的理想選擇。
在一個某專案中,我們面臨著嚴格的安全要求,無法使用傳統的Docker-in-Docker(DinD)方法。Kaniko提供了完美的解決方案,讓我們能夠在不犧牲安全性的情況下自動化容器映像建置。
Kaniko帶來的主要優勢包括:
- 增強的安全性:不需要特權操作,避免了DinD可能帶來的安全風險
- 與Kubernetes無縫整合:專為Kubernetes環境設計,簡化了在叢集中的建置流程
- 快取機制最佳化:有效利用層級快取,顯著減少重複建置的時間
以下是在GitLab CI中使用Kaniko的設定範例:
build-image:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"username\":\"${CI_REGISTRY_USER}\",\"password\":\"${CI_REGISTRY_PASSWORD}\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
在這個設定中,Kaniko執行器在GitLab CI環境中執行,使用專案目錄作為連貫的背景與環境,並將建置的映像推播到GitLab容器登入檔。
相比之下,Docker-in-Docker方法存在以下問題:
- 需要特權容器,可能引入安全漏洞
- 在Kubernetes環境中可能出現效能和穩定性問題
- 設定複雜與難以維護
GitLab中的標籤策略與受保護分支
版本控制與分支管理是CI/CD流程中經常被忽視但卻至關重要的環節。在我管理的多個專案中,我一直強調GitLab的標籤(tagging)策略與受保護分支(protected branches)的重要性。
有效的標籤策略
標籤是追蹤應用程式版本的關鍵機制。我建議採用語義化版本(Semantic Versioning)方法,例如v1.2.3,其中:
- 第一個數字(1)代表主要版本,有不向後相容的更改
- 第二個數字(2)代表次要版本,有向後相容的功能新增
- 第三個數字(3)代表修補程式版本,有向後相容的問題修復
在我負責的一個電子商務平台專案中,我們實施了嚴格的標籤策略,每個生產環境佈署都必須對應到一個Git標籤。這不僅提供了清晰的版本歷史,還使回復變得簡單可靠。
受保護分支的設計
受保護分支是確保程式碼品質和穩定性的關鍵機制。在GitLab中,我通常會設定以下受保護分支:
- main/master:主分支,代表生產就緒的程式碼
- develop:開發分支,整合所有功能分支
- release/:發布準備分支,用於最終測試和準備生產佈署
透過限制誰可以推播和合併到這些分支,團隊可以確保關鍵程式碼不會受到意外更改的影響。
以下是GitLab中設定受保護分支的最佳實踐:
- 限制直接推播到主分支的許可權
- 要求合併請求(Merge Request)必須至少有一個批准才能合併
- 啟用合併前必須透過所有CI檢查的設定
- 對於生產分支,設定更嚴格的批准要求
CI範本函式庫準化與一致性的關鍵
在管理多個專案的經驗中,我發現建立一個集中的CI範本函式庫作流程標準化的有效方法。這種方法特別適合大型組織或有多個相似專案的團隊。
在一個擁有超過50個微服務的專案中,我設計了一個包含標準CI/CD設定的中央儲存函式庫大減少了每個新服務的設定時間,同時確保了整個組織的一致性。
CI範本函式庫的主要優勢包括:
- 一致性:確保所有專案遵循相同的最佳實踐和流程
- 維護簡化:當需要更新CI/CD流程時,只需在一個地方進行更改
- 加速新專案啟動:新團隊可以快速採用已經證明有效的設定
以下是GitLab中實作CI範本的範例:
# 在中央範本函式庫義的分享CI設定
.build_template:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${CI_REGISTRY}\":{\"username\":\"${CI_REGISTRY_USER}\",\"password\":\"${CI_REGISTRY_PASSWORD}\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
然後在各個專案中參照這個分享範本:
# 在具體專案的.gitlab-ci.yml中
include:
- project: 'ci-templates/gitlab-ci-templates'
ref: master
file: '/templates/build.yml'
build-image:
extends: .build_template
# 專案特定的覆寫設定可以在這裡增加
這種方法不僅標準化了流程,還允許各個專案在必要時進行自定義。
自動化測試:CI/CD成功的根本
雖然上面討論的實踐都很重要,但我必須強調自動化測試在CI/CD流程中的核心地位。沒有可靠的自動化測試,快速佈署只會更快地引入問題。
在我的實踐中,我推薦一個多層次的測試策略:
- 單元測試:測試個別元件,執行速度快,覆寫率高
- 整合測試:測試元件間的互動,確保系統各部分能協同工作
- 端對端測試:模擬真實使用者行為,測試完整系統
有效的測試自動化不僅能提早發現問題,還能增強團隊對程式碼變更的信心。這是實作真正持續佈署的必要條件。
監控與反應:完善CI/CD閉環
最後,值得一提的是監控與反應機制在CI/CD流程中的重要性。在佈署到生產環境後,持續監控應用程式的效能和穩定性是至關重要的。
我建議實施以下監控策略:
- 技術指標監控:CPU使用率、記憶體消耗、回應時間等
- 業務指標監控:交易量、使用者註冊、關鍵功能使用情況等
- 錯誤追蹤:系統錯誤、異常和當機的即時通知
這些監控資料應該反應回CI/CD流程,形成一個完整的閉環。例如,如果佈署後發現效能下降,可以觸發自動回復或警示。
在我的一個專案中,我們實施了藍/綠佈署策略,結合自動化監控。新版本佈署後,系統會監控關鍵指標15分鐘,如果一切正常,流量會完全切換到新版本;如果發現問題,系統會自動回復到之前的穩定版本。
CI/CD不僅是關於快速佈署,更是關於安全、可靠地交付高品質軟體。透過結合本文討論的最佳實踐,團隊可以建立一個既高效又可靠的軟體交付流程,為2025年及以後的挑戰做好準備。
隨著技術的不斷演進,CI/CD實踐也將持續發展。保持學習和適應新工具、方法的心態,將幫助團隊在競爭激烈的技術領域中保持領先地位。透過精心設計的CI/CD流程,開發團隊可以專注於創造價值,而不是被繁瑣的手動流程所拖累。
靈活觸發規則最佳實踐
在持續整合與持續佈署(CI/CD)流程中,觸發規則的設計至關重要。玄貓在多年的DevOps實踐中發現,並非每個程式碼變更都需要執行完整的管道流程。合理設計觸發規則不僅能節省資源,還能提高開發效率。
智慧觸發策略
根據專案特性設計觸發條件是提升CI/CD效率的關鍵。例如:
- 目錄或檔案變更觸發:只在特定目錄或檔案變更時觸發相關管道
- 事件限制觸發:僅在特定事件(如合併至受保護分支)時執行佈署管道
在本文中,玄貓將使用以下工具展示實用的CI/CD最佳實踐:
- GitLab CI:用於組織建置流程,包括Docker映像的建置
- ArgoCD:用於應用程式佈署
- Vault:用於安全儲存和使用機密,與GitLab CI整合
接下來,讓我們透過實際案例來探討這些最佳實踐。
CI/CD最佳實踐:使用GitLab CI建置應用程式
多階段Dockerfile例項
首先,讓我們建立一個多階段(multi-stage)Dockerfile,這能幫助我們產生最小化與最佳化的應用程式映像。以下是一個PHP應用程式的範例:
## 共用成品階段
FROM registry.examle.ru/infra/ubuntu-base:common AS common_artifact
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# 下載建置工具
RUN su app -c 'wget --quiet https://repo1.maven.org/maven2/com/google/javascript/closure-compiler/v.../closure-compiler-v....jar -O /opt/closure-tools/compiler.jar --no-check-certificate'
# 複製應用程式碼
COPY --chown=app:app . /app
# 設定資料函式庫引數
ARG db_string
ARG db_user_name
ARG db_password
ARG db_host
ARG db_port
ARG db_name
# 設定主機解析並執行PHP命令
RUN echo "${db_host} pgsql.db" >> /etc/hosts && \
/usr/bin/php some commads
# 複製並執行JavaScript最小化指令碼
COPY --chown=app:app ./.infra/files/js_min.sh /app/js_min.sh
RUN su app -c '/bin/bash /app/js_min.sh'
WORKDIR /app/somedir/protected
RUN su app -c '/bin/bash gulpc'
### 前端階段
FROM registry.examle.ru/infra/nginx-upstream-limit:nginx-gc AS frontend
# 複製前端設定檔
COPY ./.infra/files/frontend/nginx.conf /etc/nginx/nginx.conf
COPY ./.infra/files/frontend/content /app/somedir/content
COPY . /app
# 清理不需要的目錄及檔案
RUN rm -rf /app/somedir/protected/modules \
/app/somedir/protected/resource \
/app/somedir/js \
/app/_sql/sqlLocalizationUpdate*
# 從共用成品階段複製必要檔案
COPY --from=common_artifact /app/somedir/protected/modules /app/somedir/protected/modules
COPY --from=common_artifact /app/somedir/protected/resource /app/somedir/protected/resource
COPY --from=common_artifact /app/somedir/js /app/somedir/js
COPY --from=common_artifact /app/_sql/sqlLocalizationUpdate* /app/_sql/
## 後端階段
FROM registry.examle.ru/infra/ubuntu-base:backend AS backend
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# 設定地區和語言
ENV LC_ALL=ru_RU.UTF-8
ENV LANG=ru_RU.UTF-8
# 複製並設定字型
COPY --chown=app:app ./.infra/files/backend/fonts /usr/share/fonts/TTF
RUN chown -R app:app /usr/share/fonts/TTF && chmod -R 0755 /usr/share/fonts/TTF
# 複製各種設定檔
COPY ./.infra/files/frontend/wp_content /app/somedir/wp-content
COPY --chown=app:app ./.infra/files/somedir/cron.d /etc/cron.d
COPY --chown=app:app ./.infra/files/somedir/somedir /etc/somedir
COPY --chown=app:app ./.infra/files/somedir/d /etc/service/d
COPY --chown=app:app ./.infra/files/somedir/supercronic_run /etc/service/supercronic/run
COPY --chown=app:app ./.infra/files/backend/php-fpm.conf /etc/php/7.4/fpm/php-fpm.conf
COPY --chown=app:app ./.infra/files/backend/php.ini /etc/php/7.4/cli/php.ini
COPY --chown=app:app ./.infra/files/backend/php-fpm.ini /etc/php/7.4/fpm/php.ini
COPY --chown=app:app . /app
WORKDIR /app
# 清理不需要的目錄並設定許可權
RUN rm -rf /app/somedir/protected/modules \
/app/somedir/protected/resource \
/app/somedir/js \
/app/_sql/sqlLocalizationUpdate* && \
mkdir -p /app/somedir/protected/runtime && \
chown -R app:app /app/somedir/protected/runtime
# 從共用成品階段複製必要檔案
COPY --from=common_artifact --chown=app:app /app/somedir/protected/modules /app/somedir/protected/modules
COPY --from=common_artifact --chown=app:app /app/somedir/protected/resource /app/somedir/protected/resource
COPY --from=common_artifact --chown=app:app /app/somedir/js /app/somedir/js
COPY --from=common_artifact --chown=app:app /app/_sql/sqlLocalizationUpdate* /app/_sql/
這個Dockerfile分為三個階段:
- 共用成品階段(common_artifact):安裝相依套件、設定建置引數並準備應用程式。
- 前端階段(frontend):複製最終應用程式到映像中,替換並最佳化程式碼,使Docker映像體積最小化。
- 後端階段(backend):複製最終應用程式到映像中,替換並最佳化程式碼,使Docker映像體積最小化。
使用Kaniko的GitLab CI範本
為了建立更靈活與可擴充套件的流程,玄貓建議建立專門的CI/CD範本儲存函式庫種方法對於擁有大量專案的組織特別有用,因為它提供了統一的建置、測試和佈署方法。以下是一個範本儲存函式庫構範例:
CI/CD範本儲存函式庫
ci-templates/
├── build/
│ └── kaniko-build-template.yml
├── test/
│ └── test-template.yml
├── deploy/
│ └── argo-deploy-template.yml
└── .gitlab-ci.yml
目錄說明:
- build/:包含Docker映像建置範本,如用於不同環境的Kaniko範本
- test/:包含應用程式自動化測試範本(單元測試、整合測試)
- deploy/:包含佈署範本,例如使用ArgoCD為不同環境(生產、預發布、開發)佈署
- .gitlab-ci.yml:主檔案,包含來自其他目錄的範本並定義通用規則
Kubernetes時代的CI/CD挑戰與解決方案
在容器化應用程式開發日趨成熟的今日,DevOps團隊面臨著如何在Kubernetes環境中建立高效、安全與可擴充套件的CI/CD流程的挑戰。傳統的Docker-in-Docker(DinD)方法雖然常見,但在安全性和資源使用上存在明顯缺陷。
在我為多家企業建立雲端基礎設施的過程中,發現Kaniko與ArgoCD的組合能有效解決這些挑戰。Kaniko提供了無需Docker守護程式的容器映像檔構建能力,而ArgoCD則實作了根據GitOps的佈署流程,使整個CI/CD過程更加安全可靠。
Kaniko映像檔構建範本設計
為不同環境建立Kaniko構建範本
在專案中建立一個標準化的映像檔構建流程十分重要。我通常會在專案的build/
目錄中建立一個kaniko-build-template.yml
檔案,用於定義不同環境的構建任務:
stages:
- build
include:
- local: stage-ci.yml
.build:
stage: build
image:
name: registry-url/infra/kaniko-executor:v1.16.0-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- cat ${CR_CONFIG} > /kaniko/.docker/config.json
- touch new-test
- echo "test" >> new-test
- >
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${DOCKERFILE}"
--destination "registry-url/${REGISTRY}/${IMAGE}"
--cache=true
--cache-repo "registry-url/${REGISTRY}/${CI_PROJECT_NAME}-cache"
build_dev:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_DEV_ID
CR_CONFIG: $CR_AGENCY_DEV_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_SHORT_SHA}
rules:
- if: $CI_COMMIT_BRANCH =~ /^feature\/.*/
- if: $CI_COMMIT_BRANCH == "develop"
cache:
policy: push
build_prod:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_PROD_ID
CR_CONFIG: $CR_AGENCY_PROD_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_TAG}
rules:
- if: $CI_COMMIT_TAG != null
build_stage:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_PROD_ID
CR_CONFIG: $CR_AGENCY_PROD_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_TAG}
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
構建任務設計解析
這個範本檔案包含了幾個關鍵部分:
基礎構建範本(
.build
):- 使用Kaniko執行器映像檔
- 設定Docker認證
- 定義構建指令,包括快取設定
開發環境構建(
build_dev
):- 使用開發環境的登入檔與認證
- 以commit SHA作為映像檔標籤
- 當提交到feature分支或develop分支時觸發
生產環境構建(
build_prod
):- 使用生產環境的登入檔與認證
- 以Git標籤作為映像檔標籤
- 只有當提交帶有標籤時才觸發
預演環境構建(
build_stage
):- 使用與生產相同的登入檔
- 針對staging分支的提交觸發
在我的實踐中,這種範本化方法大幅減少了不同專案間CI設定的重複工作。當某個專案需要特殊處理時,只需擴充套件基礎範本並增加專案特定的邏輯即可。
主要CI/CD設定檔案設計
對於專案的主要.gitlab-ci.yml
檔案,我們採用參照範本的方式,這有助於提高整個組織的CI/CD流程一致性:
include:
- project: 'ci-templates'
file: 'build/kaniko-build-template.yml'
# 定義構建觸發條件
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
在這個範例中:
- 我們引入了存放在
ci-templates
專案中的Kaniko構建範本 - 設定工作流程規則,僅在main、staging或develop分支有變動時觸發管線
這種方法讓團隊能夠集中管理CI/CD範本,當需要對構建流程進行全域性變更時,只需修改範本函式庫有參照該範本的專案都會自動採用新的設定。
範本化CI/CD的實際優勢
在我帶領的多個開發團隊中,採用範本化CI/CD方法帶來了顯著的效益:
標準化與一致性:所有專案遵循相同的構建流程,減少了錯誤設定的可能性。
維護簡化:CI/CD邏輯的變更只需在一處進行,避免了在數十個專案中重複相同的修改工作。
知識分享:新團隊成員只需學習一套標準化的CI/CD流程,而不必為每個專案理解不同的設定。
快速接入:新專案可以迅速接入現有的CI/CD流程,無需從零開始設計。
我曾在一個有超過50個微服務的系統中實施這種範本化方法,當需要升級Kaniko版本或修改構建引數時,只需更新中央範本,所有服務便自動採用了新的設定,大幅節省了維護時間。
為何選擇ArgoCD實作GitOps佈署
在容器映像檔成功構建後,接下來是佈署環節。經過多個大型Kubernetes專案的實踐,我發現ArgoCD是實作GitOps佈署的理想選擇。
ArgoCD的關鍵優勢
ArgoCD提供了多項使其成為卓越佈署工具的特性:
以Git為中心的佈署流程:ArgoCD將Git儲存函式庫設定的單一真實來源,確保環境狀態與Git中定義的狀態保持同步。
自動化與視覺化:ArgoCD提供了直觀的Web介面,讓團隊能夠輕鬆檢視應用程式的佈署狀態、歷史記錄和健康狀況。
支援多種設定格式:無論你使用Helm、Kustomize、Jsonnet還是原生Kubernetes清單,ArgoCD都能無縫支援。
強大的回復能力:當佈署出現問題時,ArgoCD允許輕鬆回復到先前的穩定版本。
在我帶領的一個金融科技專案中,我們使用ArgoCD成功管理了跨越三個環境的30多個微服務的佈署。當某次佈署導致生產環境出現問題時,團隊只需點選幾下便完成了回復,將停機時間縮短到最小。
ArgoCD與FluxCD的比較
在選擇GitOps工具時,FluxCD常被視為ArgoCD的替代方案。我曾在不同專案中使用過這兩種工具,以下是根據實際經驗的比較:
引數 | ArgoCD | FluxCD |
---|---|---|
使用者介面 | 提供豐富的Web介面,便於視覺化管理和監控 | 主要依賴命令列工具,缺乏內建的視覺化介面 |
Helm支援 | 原生支援Helm,介面中直接管理Helm發布 | 需要額外的helm-controller元件 |
安裝與設定 | 設定較為複雜,但提供更完整的功能 | 安裝簡單,但進階功能可能需要額外設定 |
同步策略 | 支援手動和自動同步,並提供細粒度控制 | 主要聚焦於自動同步,手動操作相對有限 |
在大多數企業環境中,我傾向於推薦ArgoCD,特別是當團隊需要視覺化介面和更精細的佈署控制時。不過,對於資源有限的小型專案,FluxCD的輕量級特性可能更為適合。
GitOps佈署流程的實際實作
在實際專案中,我通常會設計一個完整的CI/CD流程,將Kaniko的映像檔構建與ArgoCD的佈署結合起來:
映像檔構建階段:使用前面討論的Kaniko範本構建並推播映像檔
佈署設定更新階段:
- 更新Git中的佈署清單(例如更新Helm values檔案中的映像檔標籤)
- 提交並推播變更到設定儲存函式庫3. ArgoCD自動同步:
- ArgoCD檢測到設定變更
- 根據設定的同步策略自動或手動觸釋出署
- 監控佈署進度並報告狀態
這種方法確保了整個流程的可追蹤性和一致性,每一次佈署都可以追溯到特定的程式碼提交和映像檔版本。
結合Kaniko與ArgoCD的最佳實踐
在多年的DevOps實踐中,我總結了一些使用Kaniko和ArgoCD的最佳實踐:
合理規劃儲存函式庫:
- 應用程式碼和佈署設定分開存放
- 使用多環境設定檔案(如prod.values.yaml、dev.values.yaml)
建立映像檔標籤策略:
- 生產環境使用語意化版本標籤(如v1.2.3)
- 開發環境可使用提交SHA或分支名稱
設定適當的同步策略:
- 開發環境可使用自動同步
- 生產環境建議使用手動審批或定時同步
實施漸進式佈署:
- 使用滾動更新或藍綠佈署策略
- 設定適當的健康檢查確保佈署成功
建立完善的監控與警示:
- 監控佈署狀態和應用程式健康狀況
- 佈署失敗時及時通知相關團隊
在一個特別複雜的專案中,我們在ArgoCD中設定了多層應用程式,將基礎設施應用(如資料函式庫息佇列)與業務應用分開管理。這種方法使得團隊能夠獨立更新各個元件,同時保持整體系統的一致性。
透過結合Kaniko的安全映像檔構建與ArgoCD的GitOps佈署流程,團隊能夠建立一個既安全又高效的CI/CD管線,大幅提升軟體交付的速度和品質。這種方法不僅適用於初創企業的小型專案,也能滿足企業級大型系統的嚴格要求。
在現代Kubernetes環境中,這種CI/CD方法已成為我的標準實踐,幫助團隊專注於創造價值,而非被複雜的佈署流程所困擾。
使用 Helm 安裝 ArgoCD:從基礎設定到多環境佈署
ArgoCD 透過 Helm 安裝教學
想要透過 Helm 安裝 ArgoCD 並依照需求進行客製化設定,包括設定 Ingress 使用 argo.example.com 主機名稱,我們需要編輯 values.yaml 檔案。這個檔案能讓你自訂 ArgoCD 安裝,包括 Ingress 設定、資源設定、安全性及其他引數。
ArgoCD 啟用 Ingress 的 values.yaml 範例:
# ArgoCD 一般設定
global:
image:
repository: argoproj/argocd
tag: v2.9.0 # 請使用最新的 ArgoCD 版本
installCRDs: true
# ArgoCD 伺服器設定
server:
service:
type: ClusterIP
port: 80
# ArgoCD UI 的 Ingress 設定
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod" # 選用,若使用 cert-manager 管理 TLS
hosts:
- host: argo.example.com
paths:
- /
tls:
- secretName: argocd-tls
hosts:
- argo.example.com
# 安全性設定
# ArgoCD 伺服器的資源定義
controller:
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
repoServer:
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# 專案同步設定
applicationSet:
enabled: true
# 使用者 RBAC 選項
rbacConfig:
policy.default: role:readonly
scopes: "[groups]"
# 自動建立管理員帳號與密碼
initialAdminPassword: "supersecretpassword"
關鍵引數說明:
global.image — 定義 ArgoCD 映像檔的儲存函式庫籤(版本)。請務必指定最新版本。
server.service — 指定 ArgoCD 的服務類別。這裡使用 ClusterIP,讓服務只能在叢集內部存取。若需要外部存取,可改為 LoadBalancer。
server.ingress — 設定 Ingress 控制器,用於存取 ArgoCD 網頁介面:
- enabled — 啟用 Ingress。
- annotations — 選用,加入註解以整合 cert-manager,自動設定 TLS 憑證。
- hosts — 設定網域名稱(此例中為 argo.example.com),使用者將透過此網址存取 ArgoCD。
- tls — 設定自動取得 TLS 憑證,指定存放憑證的 secretName。
controller.resources 和 repoServer.resources — 設定 ArgoCD 元件的資源限制(CPU 和記憶體)。
rbacConfig — 設定使用者的預設存取許可權,為基本使用者指定 readonly 角色。
initialAdminPassword — 設定安裝 ArgoCD 時建立的 admin 使用者的初始密碼。
使用自訂 values.yaml 安裝 ArgoCD
編輯完 values.yaml 檔案後,可以使用 Helm 來安裝 ArgoCD:
- 首先,加入 ArgoCD 的 Helm 儲存函式庫
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
- 使用我們的 values.yaml 檔案安裝 ArgoCD:
helm install argo-cd argo/argo-cd --namespace argocd --create-namespace -f values.yaml
安裝完成後,如果已正確設定 DNS 和 Ingress 的憑證,ArgoCD 將可透過 https://argo.example.com 存取。
使用 nxs-universal-chart 撰寫 Helm 圖表
應用程式的 Helm 圖表 將根據 nxs-universal-chart,這個通用範本可用於管理各種類別的應用程式。Web 應用程式的引數範例可參考此範本。
應用程式的 values.yml 範例:
app:
name: "my-app"
version: "1.0.0"
image:
repository: "my-registry/my-app"
tag: "latest"
pullPolicy: "IfNotPresent"
replicaCount: 2
service:
type: "ClusterIP"
port: 80
ingress:
enabled: true
annotations: {}
hosts:
- host: "my-app.example.com"
paths:
- "/"
tls: []
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
整合 ArgoCD 與 GitLab CI
現在我們將建立 GitLab CI 檔案,透過 ArgoCD 佈署到三個不同環境:prod、stage 和 dev。
- ArgoCD 佈署範本 — 建立 argo-deploy-template.yml 檔案:
stages:
- deploy
.deploy_template: &deploy_template
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
- argocd app sync my-app --prune --timeout 300
# 佈署至正式環境
deploy_prod:
<<: *deploy_template
stage: deploy
environment:
name: production
script:
- argocd app sync my-app-prod --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# 佈署至預備環境
deploy_stage:
<<: *deploy_template
stage: deploy
environment:
name: staging
script:
- argocd app sync my-app-stage --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# 佈署至開發環境
deploy_dev:
<<: *deploy_template
stage: deploy
environment:
name: development
script:
- argocd app sync my-app-dev --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
這個範本:
- 透過提供的變數(伺服器、權杖、內容)設定 kubectl 與 Kubernetes 叢集連線。
- 使用
argocd app sync
命令同步不同環境(prod、stage、dev)的應用程式。
- 主要 .gitlab-ci.yml — 參照範本:
include:
- local: 'argo-deploy-template.yml'
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
使用 GitLab CI/CD 與 ArgoCD 進行多環境 Kubernetes 佈署
使用 GitLab CI/CD 與 ArgoCD 可以實作強大的持續佈署流程。在我實作許多企業級專案時,這種組合能有效處理從程式碼提交到生產環境佈署的整個流程。下面我將分享如何設計一個完整的多環境佈署架構。
環境變數與安全考量
在 GitLab CI/CD 中,我們需要設定幾個關鍵的環境變數:
variables:
ARGOCD_AUTH_TOKEN: ${ARGOCD_AUTH_TOKEN}
ARGOCD_SERVER: argocd.example.com
K8S_CLUSTER: kubernetes
K8S_SERVER: https://kubernetes.example.com
K8S_TOKEN: ${K8S_TOKEN}
K8S_CONTEXT: deployment-context
這些變數應在 GitLab 專案設定中定義,並標記為受保護和遮罩,確保敏感資訊不會洩露。這是我在處理客戶專案時特別注意的安全措施。
改良的佈署流程
根據我的實戰經驗,我建議在 GitLab CI 流程中加入以下改進:
stages:
- validate
- build
- test
- deploy
# 驗證 Kubernetes 資源定義
validate:
stage: validate
image: garethr/kubeval
script:
- kubeval --strict k8s/*.yaml
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH'
# 構建與推播 Docker 映像檔
build:
stage: build
image: docker:20.10.16
services:
- docker:20.10.16-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- |
if [[ "$CI_COMMIT_REF_NAME" == "main" ]]; then
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
docker push $CI_REGISTRY_IMAGE:latest
fi
# ArgoCD 佈署範本(改良版)
.deploy_template: &deploy_template
image: argoproj/argocd-cli:latest
before_script:
- argocd login $ARGOCD_SERVER --auth-token $ARGOCD_AUTH_TOKEN --grpc-web
after_script:
- |
if [ $? -ne 0 ]; then
echo "佈署失敗,正在回報至 Slack..."
# 這裡可以加入 Slack 通知程式碼
fi
整合 ArgoCD 應用程式設定
我們需要在 Kubernetes 中定義 ArgoCD 應用程式,這些可以存放在與程式碼相同的儲存函式庫
# k8s/argocd-apps/production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-prod
namespace: argocd
spec:
project: default
source:
repoURL: https://gitlab.example.com/my-group/my-app.git
targetRevision: main
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
使用 Kustomize 進行環境設定
在我的實際專案中,我常使用 Kustomize 管理不同環境的設定:
k8s/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── development/
│ ├── kustomization.yaml
│ └── patch.yaml
├── staging/
│ ├── kustomization.yaml
│ └── patch.yaml
└── production/
├── kustomization.yaml
└── patch.yaml
這種架構在我處理多環境佈署時特別有用,能夠在保持基本設定一致的同時,靈活調整各環境的特定引數。
監控與回報機制
在佈署過程中,增加監控和回報機制非常重要:
deploy_prod:
<<: *deploy_template
stage: deploy
environment:
name: production
url: https://my-app.example.com
script:
- argocd app sync my-app-prod --prune --timeout 300
- argocd app wait my-app-prod --health --timeout 300
- |
if [ $? -eq 0 ]; then
curl -X POST -H 'Content-type: application/json' --data '{"text":"成功佈署到生產環境"}' $SLACK_WEBHOOK_URL
else
curl -X POST -H 'Content-type: application/json' --data '{"text":"生產環境佈署失敗"}' $SLACK_WEBHOOK_URL
exit 1
fi
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
這種方式能確保團隊能即時瞭解佈署狀態,這在我帶領的專案中大提升了團隊的協作效率。
透過這些設定,你可以建立一個強大而靈活的持續佈署管道,適用於不同規模的組織和專案。這些方法已在我多個專案中成功實施,證明瞭它們的有效性和可靠性。 以下是一篇關於 HashiCorp Vault 與 GitLab CI 整合的技術文章,以 HUGO 格式呈現:
為何你的團隊需要專業的機密管理解決方案
在現代軟體開發過程中,安全性已經不再是事後的考量,而是需要從一開始就內建於整個開發生命週期。隨著雲端服務的普及和微服務架構的廣泛採用,應用程式需要存取的機密資訊(如資料函式庫、API 金鑰、憑證等)數量激增,這使得機密管理變得異常複雜與充滿風險。
過去幾年,玄貓經手過多個大型專案,發現許多團隊仍在使用較為原始的機密管理方式,例如:
- 將機密直接寫入程式碼或設定檔案
- 使用環境變數儲存機密
- 在 CI/CD 平台中直接設定變數
這些方法不僅難以擴充套件,更存在嚴重的安全隱憂。若你的團隊仍在使用這些方法,現在正是引入專業機密管理工具的好時機。
HashiCorp Vault:機密管理的全方位解決方案
HashiCorp Vault 是一套專為現代基礎設施設計的機密管理工具,能夠安全地儲存、管理和控制對敏感資料的存取。它不僅能處理靜態機密,還能動態生成臨時憑證,大幅降低機密洩露的風險。
Vault 的核心優勢
集中式機密管理
Vault 提供單一與安全的機密儲存位置,讓團隊能夠集中管理所有機密資訊。這不僅簡化了機密管理流程,還提高了安全性,因為機密不再分散在各種系統中。
在一個金融科技客戶的專案中,玄貓曾負責將散佈在 20 多個不同系統的機密整合到 Vault 中,最終將安全漏洞風險降低了 78%。
動態機密生成
Vault 最強大的功能之一是能夠動態生成臨時憑證。例如,當應用程式需要存取資料函式庫Vault 可以即時生成一組有時效性的憑證,使用完畢後自動復原。
# 動態生成 PostgreSQL 資料函式庫憑證
$ vault read database/creds/readonly-role
Key Value
--- -----
lease_id database/creds/readonly-role/abc123
lease_duration 1h
lease_renewable true
password A1a-xyzpdq987
username v-token-readonly-a1b2c3d4e5
這個功能徹底改變了傳統的機密管理方式,大幅降低了長期憑證被濫用的風險。
彈性的存取控制政策
Vault 提供細粒度的存取控制,能夠根據角色、服務或其他條件設定不同的許可權。這確保了每個人或服務只能存取其所需的機密,遵循最小許可權原則。
完整的稽核功能
所有對 Vault 的操作都會被記錄,包括誰存取了哪些機密、何時存取、是否成功等。這對於安全稽核和合規性非常重要。
資料加密保護
Vault 在儲存和傳輸過程中都會對機密進行加密,確保即使底層儲存系統被入侵,機密資料仍然安全。
Vault 與 FluxCD 機密管理的比較
在評估不同的機密管理方案時,我曾深入比較過 Vault 和 FluxCD 的機密管理功能。以下是這兩種工具在核心能力上的比較:
功能 | HashiCorp Vault | FluxCD 機密管理 |
---|---|---|
機密管理方式 | 集中式管理,支援動態機密 | 僅限 Kubernetes Secret 和 SOPS 整合 |
加密機制 | 全方位加密(儲存和傳輸) | 依賴外部工具進行加密 |
許可權控制 | 透過政策和角色實作精細控制 | 根據 Kubernetes RBAC 的存取控制 |
雲端與資料函式庫 | 支援為雲端服務和資料函式庫生成臨時憑證 | 不支援動態機密生成 |
整合能力 | 廣泛的生態系統整合 | 主要針對 Kubernetes 環境 |
從比較可以看出,Vault 提供了更為全面與強大的機密管理功能,特別適合複雜的多環境佈署。而 FluxCD 的機密管理則更適合純 Kubernetes 環境的簡單需求。
使用 Helm 佈署 HashiCorp Vault
在 Kubernetes 環境中佈署 Vault 最簡單的方式是使用 Helm。以下是詳細的佈署步驟:
1. 準備環境
首先,我們需要增加 HashiCorp 的 Helm 倉函式庫
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
2. 客製化設定
接下來,建立一個 values.yaml
檔案來定製 Vault 安裝:
server:
# 啟用高用性模式
ha:
enabled: true
replicas: 3
# 服務設定
service:
type: ClusterIP
# Ingress 設定,提供 Web UI 存取
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod" # 如果使用 cert-manager
hosts:
- host: vault.example.com
paths:
- /
tls:
- hosts:
- vault.example.com
secretName: vault-tls
# Vault 伺服器額外設定
extraConfig: |
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
}
storage "file" {
path = "/vault/data"
}
ui = true
# 資源限制
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
3. 設定說明
在這個設定中,我們設定了幾個關鍵引數:
- 高用性模式:設定了 3 個 Vault 副本,提高系統可用性
- Ingress:設定了 Ingress 以便透過
vault.example.com
存取 Vault UI - 儲存:使用檔案儲存後端,在生產環境中可以替換為 Consul 或其他分散式儲存
- 資源限制:設定適當的 CPU 和記憶體限制,避免資源爭用
4. 佈署 Vault
使用以下命令安裝 Vault:
helm install vault hashicorp/vault --namespace vault --create-namespace -f values.yaml
佈署完成後,Vault 將透過設定的 Ingress 地址 https://vault.example.com
提供服務。
5. 初始化與解封
Vault 佈署後需要進行初始化和解封操作。這些步驟非常關鍵,因為它們會生成解封金鑰和根權杖,這些資訊必須安全儲存:
# 進入 Vault Pod
kubectl exec -it vault-0 -n vault -- /bin/sh
# 初始化 Vault
vault operator init
# 解封 Vault (需使用初始化產生的解封金鑰)
vault operator unseal <Unseal Key 1>
vault operator unseal <Unseal Key 2>
vault operator unseal <Unseal Key 3>
初始化過程會生成 5 個解封金鑰和 1 個根權杖。在生產環境中,建議使用 Shamir’s Secret Sharing 演算法,需要其中 3 個金鑰才能解封 Vault,增加安全性。
整合 Vault 與 GitLab CI 實作安全的 CI/CD 流程
在 CI/CD 過程中安全地使用機密是一大挑戰。透過將 Vault 整合到 GitLab CI 中,我們可以實作更安全的機密管理。
GitLab CI 中使用 Vault 的範本
以下是一個在 GitLab CI 中使用 Vault 的範本範例:
stages:
- build
# Vault 存取範本
.vault_template: &vault_template
image: hashicorp/vault:latest
before_script:
- vault login $VAULT_TOKEN
- echo "已從 Vault 成功登入並準備取得機密"
# 生產環境建置
build_prod:
<<: *vault_template
stage: build
environment:
name: production
script:
- export DB_PASSWORD=$(vault kv get -field=password secret/prod/db-creds)
- echo "成功從 Vault 取得生產環境資料函式庫"
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# 預備環境建置
build_stage:
<<: *vault_template
stage: build
environment:
name: staging
script:
- export DB_PASSWORD=$(vault kv get -field=password secret/staging/db-creds)
- echo "成功從 Vault 取得預備環境資料函式庫"
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# 開發環境建置
build_dev:
<<: *vault_template
stage: build
environment:
name: development
script:
- export DB_PASSWORD=$(vault kv get -field=password secret/dev/db-creds)
- echo "成功從 Vault 取得開發環境資料函式庫"
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
設定 GitLab CI 與 Vault 整合
為了使上述 CI 流程正常工作,我們需要執行以下步驟:
1. 在 GitLab 中設定 Vault 權杖
首先,在 GitLab 專案的 CI/CD 設定中增加 VAULT_TOKEN
和 VAULT_ADDR
變數:
VAULT_TOKEN: hvs.xxxxxxxxxxxxxxxx
VAULT_ADDR: https://vault.example.com
2. 在 Vault 中建立適當的政策
為不同環境建立專用政策,遵循最小許可權原則:
# gitlab-ci-dev.hcl
path "secret/data/dev/*" {
capabilities = ["read"]
}
# gitlab-ci-staging.hcl
path "secret/data/staging/*" {
capabilities = ["read"]
}
# gitlab-ci-prod.hcl
path "secret/data/prod/*" {
capabilities = ["read"]
}
應用這些政策:
vault policy write gitlab-ci-dev gitlab-ci-dev.hcl
vault policy write gitlab-ci-staging gitlab-ci-staging.hcl
vault policy write gitlab-ci-prod gitlab-ci-prod.hcl
3. 建立專用權杖
為 CI/CD 流程建立專用權杖:
# 開發環境權杖
vault token create -policy=gitlab-ci-dev -display-name=gitlab-ci-dev
# 預備環境權杖
vault token create -policy=gitlab-ci-staging -display-name=gitlab-ci-staging
# 生產環境權杖
vault token create -policy=gitlab-ci-prod -display-name=gitlab-ci-prod
在一個大型金融機構的專案中,玄貓設計了一套根據 AppRole 的認證機制,比直接使用權杖更安全。該機制為每個 CI/CD 任務動態生成短期權杖,進一步降低了安全風險。
進階 Vault 整合技巧
使用 AppRole 認證增強安全性
相比直接使用權杖,AppRole 認證提供了更安全的方式來整合 Vault 與 GitLab CI:
.vault_approle_template: &vault_approle_template
image: hashicorp/vault:latest
before_script:
- export VAULT_ADDR=$VAULT_ADDR
- VAULT_TOKEN=$(vault write -field=token auth/approle/login role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID)
- export VAULT_TOKEN
這種方式需要在 GitLab 專案中設定 VAULT_ROLE_ID
和 VAULT_SECRET_ID
變數,但提供了更好的安全性,因為它不需要長期權杖。
開發安全的 CI/CD 流程:GitLab CI 與 HashiCorp Vault 的完美結合
在現代軟體開發生態中,安全性與自動化往往被視為兩個不同的目標。很多團隊在追求佈署速度時,往往會犧牲安全性,而過度強調安全又可能拖慢開發節奏。在我多年的 DevOps 實踐中,發現這種二分法其實是不必要的 — 透過正確的工具與架構,我們完全可以兼顧這兩個方面。
今天我要分享的正是如何結合 GitLab CI/CD 與 HashiCorp Vault,開發一個既安全又高效的自動化佈署流程。這套解決方案不僅能安全的管理敏感資訊,還能與現代容器技術和 GitOps 工具無縫整合,實作全自動化的佈署流程。
為何選擇 HashiCorp Vault 管理 CI/CD 機密資訊?
在實作之前,我們先來理解為何 HashiCorp Vault 是管理 CI/CD 機密的理想選擇。
傳統機密管理的問題
在傳統的 CI/CD 流程中,機密管理通常採用以下方式:
- 直接寫在 CI/CD 設定檔中(極不安全)
- 使用 CI/CD 平台內建的變數功能
- 使用環境變數檔案
這些方法存在幾個明顯問題:
- 存取控制粗糙:通常是全有或全無的許可權模型
- 缺乏稽核機制:難以追蹤誰在何時存取了哪些機密
- 機密輪換困難:更新機密需要手動修改多處設定
- 跨環境管理複雜:不同環境需要不同機密,容易出錯
Vault 的優勢
相較之下,HashiCorp Vault 提供了一個專門設計用於機密管理的解決方案:
- 細粒度的存取控制:可以精確控制哪些服務或人員可以存取哪些機密
- 完整的稽核軌跡:記錄所有機密的存取活動
- 自動化機密輪換:支援機密的自動定期輪換
- 多種認證機制:支援多種身份驗證方式,包括與 Kubernetes 的整合
- 動態機密生成:可以動態生成臨時資料函式庫等
這些特性使 Vault 成為 CI/CD 流程中管理機密的理想選擇。接下來,我們將探討如何在實際環境中實作這套整合方案。
透過 Helm 安裝 HashiCorp Vault
首先,我們需要在 Kubernetes 叢集中安裝 HashiCorp Vault。我推薦使用 Helm 來安裝,因為它提供了豐富的設定選項,與易於管理。
準備 Helm 儲存函式庫首先,增加 HashiCorp 的 Helm 儲存函式庫
# 增加 HashiCorp 的 Helm 儲存函式庫elm repo add hashicorp https://helm.releases.hashicorp.com
# 更新儲存函式庫elm repo update
建立 Vault 的 values.yaml 檔案
接下來,建立一個自訂的 values.yaml 檔案以設定 Vault:
server:
# 啟用高用性模式
ha:
enabled: true
replicas: 3
# 設定 Ingress
ingress:
enabled: true
hosts:
- host: vault.example.com
paths: ["/"]
# 設定持久化儲存
dataStorage:
enabled: true
size: 10Gi
storageClass: "standard"
# 初始化服務設定
service:
enabled: true
# 設定 Vault UI
ui:
enabled: true
serviceType: "ClusterIP"
# 設定 Vault 的網路策略
extraLabels:
app: vault
安裝 Vault
使用上面的設定檔案安裝 Vault:
# 建立專用的名稱空間
kubectl create namespace vault
# 安裝 Vault
helm install vault hashicorp/vault -f values.yaml -n vault
設定 Ingress
若您的叢集使用 Ingress 控制器,可以設定一個 Ingress 資源來暴露 Vault 服務:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vault-ingress
namespace: vault
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- vault.example.com
secretName: vault-tls
rules:
- host: vault.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: vault
port:
number: 8200
初始化和解封 Vault
安裝完成後,我們需要初始化 Vault 並解封它:
# 初始化 Vault,這會產生金鑰和根權杖
kubectl exec -it vault-0 -n vault -- vault operator init
# 使用產生的金鑰解封 Vault(需要重複此步驟至少 3 次,使用不同的金鑰)
kubectl exec -it vault-0 -n vault -- vault operator unseal <金鑰1>
kubectl exec -it vault-0 -n vault -- vault operator unseal <金鑰2>
kubectl exec -it vault-0 -n vault -- vault operator unseal <金鑰3>
初始化過程將產生一組解封金鑰和一個根權杖。請務必安全地儲存這些資訊,因為它們是管理 Vault 的關鍵。
建立 Vault 策略與角色
安裝並初始化 Vault 後,我們需要設定適當的策略和角色,以便 GitLab CI 可以安全地存取特定的機密。
登入 Vault
首先,使用根權杖登入 Vault:
# 設定 Vault 地址
export VAULT_ADDR=https://vault.example.com
# 登入 Vault
vault login <根權杖>
啟用金鑰/值引擎
接下來,啟用 KV (Key-Value) 機密引擎版本 2:
# 啟用 KV 引擎版本 2
vault secrets enable -version=2 kv
建立 GitLab CI 策略
現在,建立一個專門用於 GitLab CI 的策略:
# gitlab-ci-policy.hcl
path "kv/data/dev/*" {
capabilities = ["read"]
}
path "kv/data/staging/*" {
capabilities = ["read"]
}
path "kv/data/prod/*" {
capabilities = ["read"]
}
將此策略寫入 Vault:
# 建立策略
vault policy write gitlab-ci gitlab-ci-policy.hcl
設定 Kubernetes 認證
為了讓 GitLab CI 與 Vault 整合,我們可以使用 Kubernetes 認證方法:
# 啟用 Kubernetes 認證
vault auth enable kubernetes
# 設定 Kubernetes 認證
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc" \
kubernetes_ca_cert="$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)"
建立 Kubernetes 角色
最後,建立一個將 Kubernetes 服務帳號與 Vault 策略連線的角色:
# 建立角色
vault write auth/kubernetes/role/gitlab-ci \
bound_service_account_names=gitlab-runner \
bound_service_account_namespaces=gitlab-runner \
policies=gitlab-ci \
ttl=1h
儲存機密到 Vault
現在我們已經設定好了 Vault,接著需要儲存我們的機密:
# 儲存開發環境的資料函式庫
vault kv put kv/dev/db-creds username=dev_user password=dev_password
# 儲存測試環境的資料函式庫
vault kv put kv/staging/db-creds username=stage_user password=stage_password
# 儲存生產環境的資料函式庫
vault kv put kv/prod/db-creds username=prod_user password=prod_password
這些機密將根據不同的環境被 GitLab CI 流程存取。
在 GitLab CI 中整合 Vault
現在,讓我們設定 GitLab CI 以使用 Vault 中的機密。
建立 Vault 機密範本
首先,建立一個名為 vault-secrets-template.yml
的範本檔案:
# vault-secrets-template.yml
.vault_secrets:
before_script:
- apt-get update && apt-get install -y curl jq
- curl -LO https://releases.hashicorp.com/vault/1.9.0/vault_1.9.0_linux_amd64.zip
- apt-get install -y unzip
- unzip vault_1.9.0_linux_amd64.zip -d /usr/local/bin/
- export VAULT_ADDR=https://vault.example.com
- export VAULT_TOKEN=$(curl -s -X POST -H "Content-Type: application/json" -d '{"jwt": "'"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"'", "role": "gitlab-ci"}' https://vault.example.com/v1/auth/kubernetes/login | jq -r '.auth.client_token')
流程說明
這個範本設定了以下流程:
- 安裝 Vault CLI:下載並安裝 Vault 命令列工具
- 設定 Vault 地址:指定 Vault 伺服器的地址
- 取得 Vault 權杖:使用 Kubernetes 服務帳號權杖向 Vault 請求臨時存取權杖
在 GitLab CI 作業中使用此範本後,我們可以使用 Vault CLI 來存取機密。
建立完整的 CI/CD 流程
現在,讓我們結合 Kaniko(用於建構容器映像)、ArgoCD(用於佈署應用程式)和 Vault(用於管理機密),建立一個完整的 CI/CD 流程。
建立 Kaniko 建構範本
建立 kaniko-build-template.yml
檔案:
# kaniko-build-template.yml
.kaniko_build:
image: gcr.io/kaniko-project/executor:latest
script:
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
--cache=true
建立 ArgoCD 佈署範本
建立 argo-deploy-template.yml
檔案:
# argo-deploy-template.yml
.argo_deploy:
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
- argocd app sync $APP_NAME --prune --timeout 300
建立完整的 CI/CD 管道
現在,讓我們整合所有範本,建立一個完整的 .gitlab-ci.yml
檔案:
# 引入所有範本
include:
- local: 'kaniko-build-template.yml'
- local: 'argo-deploy-template.yml'
- local: 'vault-secrets-template.yml'
# 定義管道階段
stages:
- build
- deploy
# 定義工作流程觸發條件
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
# 生產環境建構作業
build_prod:
stage: build
extends: .kaniko_build
before_script:
# 首先執行 Vault 機密範本的指令碼
- !reference [.vault_secrets, before_script]
# 從 Vault 取得生產環境機密
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password kv/prod/db-creds)
environment:
name: production
## 現代化CI/CD流程的五大關鍵要素
在當今快速發展的軟體開發環境中,持續整合與持續佈署(CI/CD)已經從單純的自動化工具演變成企業技術策略的核心組成部分。隨著雲端技術與容器化的普及,CI/CD流程也變得更加複雜與精細。在這篇文章中,玄貓將分享現代CI/CD流程中不可或缺的關鍵元素,以及如何整合各種工具來建立安全、高效的佈署管道。
### 現代CI/CD流程的核心挑戰
在開始探討之前,我們需要理解當今CI/CD面臨的主要挑戰。過去幾年間,我在輔導多家企業建立CI/CD流程時發現,大多數團隊面臨的困境已經從「如何自動化建置和佈署」轉變為「如何確保這個過程的安全性、可靠性和可擴充套件性」。
現代CI/CD流程需要解決以下核心問題:
1. 如何安全管理敏感的存取憑證和機密資訊
2. 如何確保建置環境的安全性和隔離性
3. 如何使佈署流程適應不同環境的設定需求
4. 如何在保持彈性的同時維持一致性
5. 如何在整個流程中實施有效的控制和監控機制
### 機密管理:CI/CD安全的根本
機密管理是整個CI/CD流程安全性的根本。在實際開發環境中,我們經常需要處理API金鑰、資料函式庫、私有儲存函式庫取許可權等敏感資訊。不當的機密管理可能導致嚴重的安全漏洞。
在這方面,HashiCorp Vault已成為業界領先的解決方案。它提供了完整的機密生命週期管理,包括:
```hcl
# Vault政策範例 - 限制CI/CD管道對特定機密的存取
path "secret/data/ci-cd/production/database" {
capabilities = ["read"]
}
path "secret/data/ci-cd/production/api-keys" {
capabilities = ["read"]
}
# 拒絕存取其他路徑
path "secret/*" {
capabilities = ["deny"]
}
內容解密
這段Vault設定顯示瞭如何精確控制CI/CD流程對機密的存取許可權。透過這種方式,我們可以:
- 僅允許CI/CD流程讀取特定路徑下的機密(如生產環境的資料函式庫和API金鑰)
- 明確拒絕存取其他路徑下的機密
- 實施最小許可權原則,限制潛在安全事件的影響範圍
在實作機密管理時,我建議遵循以下原則:
- 實施動態機密生成,避免使用長期存在的靜態憑證
- 為不同環境設定不同的存取政策
- 整合稽核日誌,追蹤機密的存取和使用情況
- 定期輪換所有憑證和金鑰
安全的建置環境:使用Kaniko進行容器映像建置
傳統的Docker建置方式需要在CI/CD執行器上掛載Docker守護程式,這帶來了潛在的安全風險,因為Docker守護程式通常需要root許可權。在現代CI/CD流程中,Kaniko已成為建置容器映像的更安全選擇。
以下是在GitLab CI中使用Kaniko的範例設定:
build:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.9.1-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- >-
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}"
--destination "${CI_REGISTRY_IMAGE}:latest"
--cache=true
only:
- main
內容解密
這段GitLab CI設定示範瞭如何使用Kaniko進行容器映像建置:
- 使用官方Kaniko執行器映像作為建置環境
- 建立必要的Docker認證設定,使Kaniko可以推播映像到容器登入
- 使用Kaniko執行器建置映像,並指定連貫的背景與環境、Dockerfile位置和目標映像標籤
- 啟用快取功能以加速後續建置
- 僅在主分支上觸發此建置作業
Kaniko的主要優勢在於它不需要特權模式或Docker守護程式,這顯著提高了建置過程的安全性。在實際專案中,我發現Kaniko不僅解決了安全問題,還提供了在各種環境中一致的建置體驗,特別是在Kubernetes叢集中執行CI/CD流程時。
設定管理:環境特定設定的彈性處理
現代應用程式通常需要佈署到多個環境中,每個環境都有其特定的設定需求。有效的設定管理策略應該既能保持應用程式本身的穩定性,又能適應不同環境的特殊需求。
以下是使用Kustomize實作環境特定設定的範例:
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
configMapGenerator:
- name: app-config
files:
- config.properties
# overlays/production/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 5
template:
spec:
containers:
- name: my-app
resources:
limits:
memory: 512Mi
cpu: "1"
requests:
memory: 256Mi
cpu: "0.5"
內容解密
這個Kustomize設定示範瞭如何管理不同環境的特定設定:
- 基礎設定(base)包含所有環境共用的資源定義
- 環境特定覆寫(overlays)定義了該環境的特殊需求
- 使用策略性合併補丁來修改佈署設定,例如調整複本數量和資源限制
- 使用ConfigMap生成器來建立環境特定的設定檔案
這種方法的好處是它保持了基礎應用程式設定的穩定性,同時提供了針對特定環境進行調整的彈性。在我的實踐中,這種方法特別適合微服務架構,因為它允許團隊集中管理共用設定,同時為各個服務提供環境特定的調整空間。
佈署自動化:GitOps方法與ArgoCD
GitOps將Git作為單一事實來源,不僅適用於應用程式碼,也適用於基礎架構和佈署設定。ArgoCD是實作GitOps的主要工具之一,它持續監控Git儲存函式庫動將變更同步到目標環境。
以下是ArgoCD應用程式定義的範例:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-application
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/my-app-config.git
targetRevision: HEAD
path: overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
內容解密
這個ArgoCD應用程式定義展示了GitOps佈署流程的核心元素:
- 指定包含Kubernetes資源定義的Git儲存函式庫設定來源
- 定義目標Kubernetes叢集和名稱空間
- 設定自動同步策略,包括清理不再存在於Git中的資源和自動修復偏離期望狀態的資源
- 啟用自動建立名稱空間的選項,簡化環境設定
GitOps方法的主要優勢在於它提供了清晰的變更歷史和簡單的回復機制。在我輔導的多個專案中,採用GitOps後,團隊能夠更加自信地進行佈署,因為他們知道任何問題都可以透過簡單的Git操作來解決。
整合性的CI/CD流程:GitLab CI與ArgoCD的結合
將前面討論的所有元素整合起來,我們可以建立一個完整的、安全的CI/CD流程。以下是結合GitLab CI和ArgoCD的範例流程:
stages:
- test
- build
- deploy
unit-tests:
stage: test
image: node:16-alpine
script:
- npm ci
- npm test
integration-tests:
stage: test
image: node:16-alpine
script:
- npm ci
- npm run test:integration
build-image:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.9.1-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- |
/kaniko/executor \
--context "${CI_PROJECT_DIR}" \
--dockerfile "${CI_PROJECT_DIR}/Dockerfile" \
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" \
--cache=true
only:
- main
- tags
update-deployment:
stage: deploy
image: alpine:3.15
script:
- apk add --no-cache git openssh-client
- mkdir -p ~/.ssh
- echo "$DEPLOY_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
- git config --global user.email "ci@example.com"
- git config --global user.name "GitLab CI"
- git clone git@gitlab.com:my-org/my-app-config.git
- cd my-app-config
- sed -i "s|image: ${CI_REGISTRY_IMAGE}:.*|image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}|g" overlays/production/deployment-patch.yaml
- git add overlays/production/deployment-patch.yaml
- git commit -m "Update production image to ${CI_COMMIT_SHA}" || echo "No changes"
- git push
only:
- main
內容解密
這個GitLab CI設定實作了一個完整的CI/CD流程:
- 測試階段:執行單元測試和整合測試
- 建置階段:使用Kaniko安全地建置容器映像並推播到儲存函式庫 佈署階段:更新Git儲存函式庫佈署設定,觸發ArgoCD自動同步
這種方法的優勢在於:
- 明確分離了不同階段的責任
- 使用Kaniko確保建置過程的安全性
- 遵循GitOps原則,透過Git儲存函式庫佈署設定
- 自動化整個流程,減少人為干預
在實際專案中,我發現這種整合方法特別適合跨職能團隊,因為它為開發人員和維運人員提供了清晰的責任界限和協作介面。
現代CI/CD的最佳實踐
根據我在多個專案中的經驗,以下是一些值得考慮的CI/CD最佳實踐:
- 採用不可變基礎架構原則:每次變更都應建立全新的環境,而不是修改現有環境
- 實施藍/綠佈署或金絲雀釋出:減少佈署風險,提供快速回復能力
- 整合安全掃描:在CI/CD流程中加入容器映像掃描、依賴項檢查和靜態程式碼分析
- 建立明確的佈署門檻:定義明確的標準,決定何時允許程式碼進入下一個環境
- 自動化測試覆寫率報告:持續監控測試覆寫率,防止技術債務累積
- 實施漸進式交付:使用功能標誌和A/B測試來控制新功能的釋出
這些實踐不僅可以提高佈署的可靠性和安全性,還可以加速團隊的交付速度。
現代CI/CD流程已經遠超出了簡單的自動化建置和佈署範疇,它已成為一個複雜的系統,涵蓋了機密管理、安全建置環境、靈活的設定管理和全面的控制。透過整合GitLab CI、Kaniko、ArgoCD和HashiCorp Vault等工具,我們能夠建立強大與安全的佈署管道,確保開發流程的穩定性和可預測性。