flux2+kustomize+helm+github 多集群 GitOps 云原生漸進式交付
對于此示例,我們假設有兩個集群的場景:暫存(staging)和生產(chǎn)(production)。最終目標是利用 Flux 和 Kustomize 來管理兩個集群,同時最大限度地減少重復聲明。
我們將配置 Flux 以使用 HelmRepository 和 HelmRelease 自定義資源安裝、測試和升級演示應用程序。 Flux 將監(jiān)控 Helm 存儲庫,并根據(jù) semver 范圍自動將 Helm 版本升級到最新的 chart 版本。
準備工作
flux2-kustomize-helm-example
- https://github.com/fluxcd/flux2-kustomize-helm-example
您將需要 Kubernetes 集群版本 1.16 或更新版本以及 kubectl 版本 1.18 或更新。對于快速的本地測試,您可以使用 Kubernetes kind。不過,任何其他 Kubernetes 設置也可以正常工作。
為了遵循本指南,您需要一個 GitHub 帳戶和一個可以創(chuàng)建存儲庫的 personal access token(檢查 repo 下的所有權限)。
使用 Homebrew 在 MacOS 和 Linux 上安裝 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 發(fā)布定義(release definitions)
- apps/production/ 目錄包含生產(chǎn) Helm 發(fā)布值(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 版本,包括 alpha、beta 和預發(fā)布(pre-releases)。
在 apps/production/ 目錄中,我們有一個帶有生產(chǎn)特定值的 Kustomize 補?。?/p>
- 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 升級到 最新的穩(wěn)定 chart 版本(alpha、beta 和 pre-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 版本,F(xiàn)lux 將升級該版本。
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 在部署應用程序之前創(chuàng)建基礎設施項。
在您的個人 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 上創(chuàng)建一個具有只讀訪問權限的部署密鑰,因此它可以在集群內拉取更改(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"
- }
通過設置生產(chǎn)集群的上下文和路徑來引導生產(chǎn)上的 Flux:
- flux bootstrap github \
- --context=production \
- --owner=${GITHUB_USER} \
- --repository=${GITHUB_REPO} \
- --branch=main \
- --personal \
- --path=clusters/production
監(jiān)控 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 存儲庫中, 您可以使用 Mozilla 的 SOPS CLI 通過 OpenPGP 或 KMS 加密 Kubernetes secrets。
安裝 gnupg 和 sops:
- 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 在集群上創(chuàng)建 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 的數(shù)據(jù)字段:
- 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 命名空間中創(chuàng)建了 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 中創(chuàng)建一個目錄:
- mkdir -p clusters/dev
從 staging 復制同步清單:
- cp clusters/staging/infrastructure.yaml clusters/dev
- cp clusters/staging/apps.yaml clusters/dev
您可以在 apps 內創(chuàng)建一個 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
相同的環(huán)境
如果你想啟動一個相同的環(huán)境,你可以引導一個集群,例如 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 目錄中創(chuàng)建一個 kustomization.yaml:
- apiVersion: kustomize.config.k8s.io/v1beta1
- kind: Kustomization
- resources:
- - flux-system
- - ../production/infrastructure.yaml
- - ../production/apps.yaml
請注意,除了 flux-system kustomize overlay,我們還包括來自 production 目錄的 infrastructure 和 apps 清單。
將更改推送到主分支:
- git add -A && git commit -m "add production clone" && git push
告訴 Flux 在 production-clone 集群上部署生產(chǎn)工作負載(production workloads):
- flux reconcile kustomization flux-system \
- --context=production-clone \
- --with-source