使用 flux2+kustomize+helm+github 進行多叢集 GitOps 雲原生漸進式交付

為少發表於2021-06-24

對於此示例,我們假設有兩個叢集的場景:暫存(staging)和生產(production)。
最終目標是利用 FluxKustomize 來管理兩個叢集,同時最大限度地減少重複宣告。

我們將配置 Flux 以使用 HelmRepositoryHelmRelease
自定義資源安裝、測試和升級演示應用程式。
Flux 將監控 Helm 儲存庫,並根據 semver 範圍自動將 Helm 版本升級到最新的 chart 版本。

準備工作

flux2-kustomize-helm-example

您將需要 Kubernetes 叢集版本 1.16 或更新版本以及 kubectl 版本 1.18 或更新。
對於快速的本地測試,您可以使用
Kubernetes kind。不過,任何其他 Kubernetes 設定也可以正常工作。

為了遵循本指南,您需要一個 GitHub 帳戶和一個可以建立儲存庫的
personal access token(檢查 repo 下的所有許可權)。

使用 HomebrewMacOSLinux 上安裝 Flux CLI

brew install fluxcd/tap/flux

或者通過使用 Bash 指令碼下載預編譯的二進位制檔案來安裝 CLI:

curl -s https://fluxcd.io/install.sh | sudo bash

專案結構

Git 儲存庫包含以下頂級目錄:

  • apps 目錄包含每個叢集具有自定義配置的 Helm 版本
  • infrastructure 目錄包含常見的基礎設施工具,例如 NGINX ingress controller 和 Helm 儲存庫定義
  • clusters 目錄包含每個叢集的 Flux 配置
├── apps
│   ├── base
│   ├── production 
│   └── staging
├── infrastructure
│   ├── nginx
│   ├── redis
│   └── sources
└── clusters
    ├── production
    └── staging

apps 配置結構為:

  • apps/base/ 目錄包含名稱空間和 Helm 釋出定義(release definitions)
  • apps/production/ 目錄包含生產 Helm 釋出值(release values)
  • apps/staging/ 目錄包含 staging values
./apps/
├── base
│   └── podinfo
│       ├── kustomization.yaml
│       ├── namespace.yaml
│       └── release.yaml
├── production
│   ├── kustomization.yaml
│   └── podinfo-patch.yaml
└── staging
    ├── kustomization.yaml
    └── podinfo-patch.yaml

apps/base/podinfo/ 目錄中,我們有一個 HelmRelease,兩個叢集都有共同的值:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: podinfo
  namespace: podinfo
spec:
  releaseName: podinfo
  chart:
    spec:
      chart: podinfo
      sourceRef:
        kind: HelmRepository
        name: podinfo
        namespace: flux-system
  interval: 5m
  values:
    cache: redis-master.redis:6379
    ingress:
      enabled: true
      annotations:
        kubernetes.io/ingress.class: nginx
      path: "/*"

apps/staging/ 目錄中,我們有一個帶有 staging 特定值的 Kustomize 補丁(patch):

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: podinfo
spec:
  chart:
    spec:
      version: ">=1.0.0-alpha"
  test:
    enable: true
  values:
    ingress:
      hosts:
        - podinfo.staging

請注意,使用 version: ">=1.0.0-alpha" 我們配置 Flux 以自動將 HelmRelease 升級到最新的 chart 版本,包括 alphabeta 和預釋出(pre-releases)。

apps/production/ 目錄中,我們有一個帶有生產特定值的 Kustomize 補丁:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: podinfo
  namespace: podinfo
spec:
  chart:
    spec:
      version: ">=1.0.0"
  values:
    ingress:
      hosts:
        - podinfo.production

請注意,使用 version: ">=1.0.0" 我們配置 Flux 以自動將 HelmRelease 升級到
最新的穩定 chart 版本(alphabetapre-releases 將被忽略)。

基礎設施:

./infrastructure/
├── nginx
│   ├── kustomization.yaml
│   ├── namespace.yaml
│   └── release.yaml
├── redis
│   ├── kustomization.yaml
│   ├── namespace.yaml
│   └── release.yaml
└── sources
    ├── bitnami.yaml
    ├── kustomization.yaml
    └── podinfo.yaml

infrastructure/sources/ 目錄中,我們有 Helm 儲存庫定義:

apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
  name: podinfo
spec:
  interval: 5m
  url: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
  name: bitnami
spec:
  interval: 30m
  url: https://charts.bitnami.com/bitnami

請注意,使用 interval: 5m 我們將 Flux 配置為每五分鐘拉一次 Helm 儲存庫索引。
如果索引包含與 HelmRelease semver 範圍匹配的新 chart 版本,Flux 將升級該版本。

Bootstrap staging 和 production

叢集目錄包含 Flux 配置:

./clusters/
├── production
│   ├── apps.yaml
│   └── infrastructure.yaml
└── staging
    ├── apps.yaml
    └── infrastructure.yaml

clusters/staging/ 目錄中,我們有 Kustomization 定義:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
  name: apps
  namespace: flux-system
spec:
  interval: 10m0s
  dependsOn:
    - name: infrastructure
  sourceRef:
    kind: GitRepository
    name: flux-sytem
  path: ./apps/staging
  prune: true
  validation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 10m0s
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./infrastructure

請注意,使用 path: ./apps/staging 我們配置 Flux 以同步暫存 Kustomize 覆蓋,並使用 dependsOn 我們告訴 Flux 在部署應用程式之前建立基礎設施項。

在您的個人 GitHub 帳戶上 Fork 此儲存庫並匯出您的 GitHub access token、使用者名稱和儲存庫名稱:

export GITHUB_TOKEN=<your-token>
export GITHUB_USER=<your-username>
export GITHUB_REPO=<repository-name>

驗證您的臨時叢集是否滿足先決條件:

flux check --pre

kubectl context 設定為您的 staging 叢集和 bootstrap Flux:

flux bootstrap github \
    --context=staging \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --personal \
    --path=clusters/staging

bootstrap 命令在 clusters/staging/flux-system 目錄中提交 Flux 元件的清單,並在 GitHub 上建立一個具有隻讀訪問許可權的部署金鑰,因此它可以在叢集內拉取更改(pull changes)。

注意在 staging 上安裝的 Helm releases:

$ watch flux get helmreleases --all-namespaces 
NAMESPACE	NAME   	REVISION	SUSPENDED	READY	MESSAGE                          
nginx    	nginx  	5.6.14  	False    	True 	release reconciliation succeeded	
podinfo  	podinfo	5.0.3   	False    	True 	release reconciliation succeeded	
redis    	redis  	11.3.4  	False    	True 	release reconciliation succeeded

驗證 demo app 是否可以通過 ingress 訪問:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &

$ curl -H "Host: podinfo.staging" http://localhost:8080
{
  "hostname": "podinfo-59489db7b5-lmwpn",
  "version": "5.0.3"
}

通過設定生產叢集的上下文和路徑來引導生產上的 Flux

flux bootstrap github \
    --context=production \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --personal \
    --path=clusters/production

監控 production reconciliation:

$ watch flux get kustomizations
NAME          	REVISION                                        READY
apps          	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True
flux-system   	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True
infrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

加密 Kubernetes secrets

為了將 secrets 安全地儲存在 Git 儲存庫中,
您可以使用 MozillaSOPS CLI 通過 OpenPGPKMS 加密 Kubernetes secrets

安裝 gnupgsops:

brew install gnupg sops

Flux 生成一個不指定密碼短語(passphrase)的 GPG key,並獲取GPG key ID

$ gpg --full-generate-key
Email address: fluxcdbot@users.noreply.github.com

$ gpg --list-secret-keys fluxcdbot@users.noreply.github.com
sec   rsa3072 2020-09-06 [SC]
      1F3D1CED2F865F5E59CA564553241F147E7C5FA4

使用 private key 在叢集上建立 Kubernetes secret:

gpg --export-secret-keys \
--armor 1F3D1CED2F865F5E59CA564553241F147E7C5FA4 |
kubectl create secret generic sops-gpg \
--namespace=flux-system \
--from-file=sops.asc=/dev/stdin

生成 Kubernetes secret manifest 並使用 sops 加密 secret 的資料欄位:

kubectl -n redis create secret generic redis-auth \
--from-literal=password=change-me \
--dry-run=client \
-o yaml > infrastructure/redis/redis-auth.yaml

sops --encrypt \
--pgp=1F3D1CED2F865F5E59CA564553241F147E7C5FA4 \
--encrypted-regex '^(data|stringData)$' \
--in-place infrastructure/redis/redis-auth.yaml

新增 secret 到 infrastructure/redis/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: redis
resources:
  - namespace.yaml
  - release.yaml
  - redis-auth.yaml

通過編輯 infrastructure.yaml 檔案在叢集上啟用解密:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  # content omitted for brevity
  decryption:
    provider: sops
    secretRef:
      name: sops-gpg

匯出公鑰(public key),以便任何有權訪問儲存庫的人都可以加密 secrets 但不能解密它們:

gpg --export -a fluxcdbot@users.noreply.github.com > public.key

將更改推送到主分支:

git add -A && git commit -m "add encrypted secret" && git push

驗證是否已在兩個叢集的 redis 名稱空間中建立了 secret

kubectl --context staging -n redis get secrets
kubectl --context production -n redis get secrets

您可以使用 Kubernetes secrets 為您的 Helm releases 提供值:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: redis
spec:
  # content omitted for brevity
  values:
    usePassword: true
  valuesFrom:
  - kind: Secret
    name: redis-auth
    valuesKey: password
    targetPath: password

docs 中瞭解有關 Helm releases values 覆蓋的更多資訊。

新增叢集

如果要將叢集新增到你的 fleet 中,請先在本地克隆儲存庫:

git clone https://github.com/${GITHUB_USER}/${GITHUB_REPO}.git
cd ${GITHUB_REPO}

使用您的叢集名稱在 clusters 中建立一個目錄:

mkdir -p clusters/dev

staging 複製同步清單:

cp clusters/staging/infrastructure.yaml clusters/dev
cp clusters/staging/apps.yaml clusters/dev

您可以在 apps 內建立一個 dev overlay,確保將 clusters/dev/apps.yaml 內的 spec.path 更改為 path: ./apps/dev

將更改推送到主分支:

git add -A && git commit -m "add dev cluster" && git push

將 kubectl 上下文和路徑設定為您的 dev cluster 並引導 Flux:

flux bootstrap github \
    --context=dev \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --personal \
    --path=clusters/dev

相同的環境

如果你想啟動一個相同的環境,你可以引導一個叢集,例如 production-clone 並重用 production 定義。

引導 production-clone 叢集:

flux bootstrap github \
    --context=production-clone \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --personal \
    --path=clusters/production-clone

在本地拉取更改:

git pull origin main

clusters/production-clone 目錄中建立一個 kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - flux-system
  - ../production/infrastructure.yaml
  - ../production/apps.yaml

請注意,除了 flux-system kustomize overlay,我們還包括來自 production 目錄的 infrastructureapps 清單。

將更改推送到主分支:

git add -A && git commit -m "add production clone" && git push

告訴 Flux 在 production-clone 叢集上部署生產工作負載(production workloads):

flux reconcile kustomization flux-system \
    --context=production-clone \
    --with-source 
我是為少
微信:uuhells123
公眾號:黑客下午茶

相關文章