Flux 是一套针对 Kubernetes 的持续交付和渐进式交付的解决方案,可以让我们以 GitOps 的方式轻松地交付应用。和另一个同类的 CNCF 孵化项目 Argo CD 不同,Flux CD 是许多工具集的集合,天然松耦合并且有良好的扩展性,用户可按需取用。最新版本的 Flux 引入了许多新功能,使其更加灵活多样。Flux 已经是 CNCF 毕业项目。
组件
Flux 是使用 GitOps Toolkit 组件构建的,它是一组:
- 专用工具和 Flux 控制器。
- 可组合的 API。
- 在 fluxcd GitHub 组织下,为构建基于 Kubernetes 的持续交付提供可重用的 Go 依赖包。
用于在 Kubernetes 之上构建持续交付。
GitOps Toolkit
这些 API 包括 Kubernetes 自定义资源,可以由集群用户或其他自动化工具进行创建和更新。我们可以使用这个工具包扩展 Flux,并构建自己的持续交付系统。
Flux 的核心工具包包括以下 5 个:
- Source Controller
- Kustomize Controller
- Helm Controller
- Notification Controller
- Image automation controllers
每个工具包都是一个控制器,都有自己的自定义资源定义 (CRD),用于定义其行为。
安装
Flux 项目由命令行工具(FLux CLI)和一系列 Kubernetes 控制器组成。要安装 Flux,首先需要下载 Flux CLI,然后使用 CLI,可以在集群上部署 Flux 控制器并配置 GitOps 交付流水线。
Flux CLI 是一个二进制可执行文件,可以从 GitHub 发布页面下载直接下载即可。
对于 Mac 用户可以直接使用 homebrew 进行一键安装:
$ brew install fluxcd/tap/flux
如果是 Linux 用户也可以使用下面的命令进行安装:
$ curl -s https://fluxcd.io/install.sh | sudo bash
安装完成后,可以使用 flux
命令来验证是否安装成功:
$ flux --version
flux version 2.1.1
接下来我们就可以使用 Flux CLI 来安装 Flux 控制器了。
Flux CLI 提供了一个 bootstrap 命令在 Kubernetes 集群上部署 Flux 控制器,并配置控制器以从 Git 存储库同步集群状态。除了安装控制器之外,bootstrap 命令还将 Flux 清单推送到 Git 存储库,并将 Flux 配置为从 Git 进行自我更新。
flux
如果集群上存在 Flux 控制器,则 bootstrap 命令将在需要时执行升级。Bootstrap 是幂等的,可以安全地运行该命令任意多次。
Flux 与主流的 Git 提供商进行集成,以简化部署密钥和其他身份验证机制的初始设置。比如我们这里选择和 GitLab 进行集成。那么我们可以使用 bootstrap gitlab 命令在 Kubernetes 集群上部署 Flux 控制器,并配置控制器从 GitLab 项目同步集群状态。除了安装控制器之外,bootstrap 命令还将 Flux 清单推送到 GitLab 项目,并将 Flux 配置为从 Git 进行自我更新。运行 bootstrap 命令后,对集群的任何操作都可以通过 Git 推送完成,无需连接到 Kubernetes 集群。
要启动 Flux,运行命令的人员必须拥有目标 Kubernetes 集群的集群管理员权限,还要求运行该命令的人是 GitLab 项目的所有者,或者具有 GitLab 组的管理员权限。
为了访问 GitLab API,boostrap 命令需要具有对 GitLab API 的完整读/写访问权限的 GitLab 个人访问令牌 (PAT)。GitLab PAT 可以导出为环境变量:
export GITLAB_TOKEN=<gh-token>
如果未设置 GITLAB_TOKEN 环境变量,boostrap 命令将提示你输入 token,当然可以使用管道提供,例如:echo "<gl-token>" | flux bootstrap gitlab。
比如我们这里可以前往 GitLab 个人访问令牌页面 页面创建一个 PAT:
Create PAT
然后我们可以使用下面的命令来安装 Flux:
export GITLAB_TOKEN=glpat-RzooW-ViSatx6zgzmb6d
flux bootstrap gitlab \
--deploy-token-auth \
--hostname=gitlab.k8s.local \
--owner=cnych \
--repository=flux \
--branch=main \
--path=clusters/my-cluster \
--personal
如果指定的项目不存在,Flux 将为你创建一个私有项目,如果希望创建公共项目,需要设置 --private=false 参数。使用 --deploy-token-auth 时,CLI 会生成一个 GitLab 项目部署令牌,并将其作为 Kubernetes Secret 存储在集群中 flux-system 命名空间内。
对多环境集群的支持并没有采用多仓库/多分支的策略,而是用的使用不同路径来管理不同的集群,这也是 Flux 推荐的策略,可以减少代码维护和合并的难度。
上面的命令执行后会出现如下所示的错误信息:
► connecting to https://gitlab.k8s.local
✗ failed to get Git repository "https://gitlab.k8s.local/cnych/flux": provider error: Get "https://gitlab.k8s.local/api/v4/projects/cnych%2Fflux": tls: failed to verify certificate: x509: certificate is valid for ingress.local, not gitlab.k8s.local
这是因为我们这里安装的 GitLab 使用的是 http 的方式,而且该命令下面并没有跳过对 https 证书校验的参数,所以这里我们需要换另外一种方式来安装,使用通用的 git 方式来安装,命令如下所示:
flux bootstrap git \
--url=http://gitlab.k8s.local/cnych/flux \
--username=cnych \
--password=<gh-token> \
--token-auth=true \
--path=clusters/my-cluster
--allow-insecure-http=true # 运行不安全的 http 方式
上面的命令会在 flux-system 命名空间中部署一系列 Kubernetes 控制器及其 CRD、RBAC 和网络策略,默认的组件包括:source-controller、kustomize-controller、helm-controller、notification-controller,可以通过 --components 参数来指定要安装的组件,但是需要注意最小安装需要 source-controller 和 kustomize-controller 两个组件。
上面的命令执行后会正常情况下会出现如下所示的输出信息:
► cloning branch "main" from Git repository "http://gitlab.k8s.local/cnych/flux"
✔ cloned repository
► generating component manifests
✔ generated component manifests
✔ component manifests are up to date
✔ reconciled components
► determining if source secret "flux-system/flux-system" exists
► generating source secret
► applying source secret "flux-system/flux-system"
✔ reconciled source secret
► generating sync manifests
✔ generated sync manifests
✔ sync manifests are up to date
► applying sync manifests
✔ reconciled sync configuration
◎ waiting for Kustomization "flux-system/flux-system" to be reconciled
✔ Kustomization reconciled successfully
► confirming components are healthy
✔ helm-controller: deployment ready
✔ kustomize-controller: deployment ready
✔ notification-controller: deployment ready
✔ source-controller: deployment ready
✔ all components are healthy
在 flux-system 命名空间中可以查看到部署的 Flux 控制器:
$ kubectl get pods -n flux-system
NAME READY STATUS RESTARTS AGE
helm-controller-7c8b698656-gftdr 1/1 Running 0 65m
kustomize-controller-858996fc8d-k2dlx 1/1 Running 0 65m
notification-controller-ddf44665d-49vtp 1/1 Running 0 65m
source-controller-594c848975-sq2pp 1/1 Running 0 29m
此时在对于的 GitLab 代码仓库 http://gitlab.k8s.local/cnych/flux 中可以看到 Flux 为我们创建了一个 clusters/my-cluster/flux-system 的目录,里面包含了一些 Flux 的配置文件。
flux git
到这里我们就完成了 Flux 的安装。
示例
这里我们还是以前面 Jenkins Pipeline 章节中的示例来进行说明,如何通过 Flux 来实现 GitOps 的持续交付。
示例中要用到的 Git 资源清单仓库为 http://gitlab.k8s.local/cnych/k8s-demo-config,该项目中包含一个 helm 目录,目录下面就是一个 helm chart 包:
demo config
当然在继续之前,为避免产生影响,我们可以将前面通过 Argo CD 部署的应用删除掉。
接下来我们就可以通过 Flux 来部署应用了,首先需要为 FluxCD 创建一个仓库连接信息,这就需要用到一个名为 GitRepository
的 CRD 对象,该对象可以定义一个 Source 代码源来为 Git 存储库的一个版本生成一个制品,如下所示:
# k8s-demo-git-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: k8s-demo
spec:
url: http://gitlab.k8s.local/cnych/k8s-demo-config
timeout: 60s
interval: 30s
ref:
branch: main
secretRef:
name: k8s-demo
---
apiVersion: v1
stringData:
password: <gl-token>
username: cnych
kind: Secret
metadata:
name: k8s-demo
type: Opaque
这里我们创建了一个名为 k8s-demo 的 GitRepository 对象,其中 spec 字段定义了如何从 Git 存储库提取数据,url 字段指定了 Git 存储库的 URL,ref 字段指定了要提取的代码分支,interval 字段指定了从 Git 存储库提取数据的频率,secretRef 字段指定了包含 GitRepository 身份验证凭据的 Secret。
对于 HTTPS 仓库,Secret 必须包含基本认证的 username 和 password 字段,或者令牌认证的 bearerToken 字段。对于 SSH 仓库,Secret 必须包含 identity 和 known_hosts 字段。
直接应用该资源对象即可:
$ kubectl apply -f k8s-demo-git-repo.yaml
gitrepository.source.toolkit.fluxcd.io/k8s-demo created
secret/k8s-demo created
$ kubectl get gitrepositories
NAME URL AGE READY STATUS
k8s-demo http://gitlab.k8s.local/cnych/k8s-demo-config 53s True stored artifact for revision 'main@sha1:cbb0226130da3ff5e1d4ccad9407e210ab65e551'
创建后我们可以通过 kubectl describe gitrepository k8s-demo 命令来查看 GitRepository 的各种状态:
$ kubectl describe gitrepositories k8s-demo
Name: k8s-demo
Namespace: default
Labels: <none>
Annotations: <none>
API Version: source.toolkit.fluxcd.io/v1
Kind: GitRepository
Metadata:
Creation Timestamp: 2023-09-23T09:29:35Z
Finalizers:
finalizers.fluxcd.io
Generation: 1
Resource Version: 485193
UID: fef6070d-56bf-452b-8aeb-c821a76ab8f2
Spec:
Interval: 30s
Ref:
Branch: main
Secret Ref:
Name: k8s-demo
Timeout: 60s
URL: http://gitlab.k8s.local/cnych/k8s-demo-config
Status:
Artifact:
Digest: sha256:b1944afa22fe6b0ce816100b7ac307fc142506287af9d8ac2cc693f7af73364b
Last Update Time: 2023-09-23T09:29:36Z
Path: gitrepository/default/k8s-demo/cbb0226130da3ff5e1d4ccad9407e210ab65e551.tar.gz
Revision: main@sha1:cbb0226130da3ff5e1d4ccad9407e210ab65e551
Size: 7240
URL: http://source-controller.flux-system.svc.cluster.local./gitrepository/default/k8s-demo/cbb0226130da3ff5e1d4ccad9407e210ab65e551.tar.gz
Conditions:
Last Transition Time: 2023-09-23T09:29:36Z
Message: stored artifact for revision 'main@sha1:cbb0226130da3ff5e1d4ccad9407e210ab65e551'
Observed Generation: 1
Reason: Succeeded
Status: True
Type: Ready
Last Transition Time: 2023-09-23T09:29:36Z
Message: stored artifact for revision 'main@sha1:cbb0226130da3ff5e1d4ccad9407e210ab65e551'
Observed Generation: 1
Reason: Succeeded
Status: True
Type: ArtifactInStorage
Observed Generation: 1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal NewArtifact 103s source-controller stored artifact for commit 'build: automatic update of devops-demo2'
Normal GitOperationSucceeded 14s (x3 over 72s) source-controller no changes since last reconcilation: observed revision 'main@sha1:cbb0226130da3ff5e1d4ccad9407e210ab65e551'
通过 .status.artifact.revision 字段可以查看到当前的 Git 版本,新的制品在 .status.artifact 字段中可以查看到。
接下来我们只需要为该应用创建一个部署策略即可,由于我们这里要发布的是 Helm Chart,所以我们需要创建一个 HelmRelease 对象,该对象可以定义一个包含 Chart 的源(可以是 HelmRepository、GitRepository 或 Bucket)告知 source-controller,以便 HelmRelease 能够引用它,很明显我们这里的源就是上面定义的 GitRepository 对象。
我们这里创建的 HelmRelease 对象如下所示:
# k8s-demo-helm-release.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: k8s-demo
namespace: default
spec:
interval: 30s
chart:
spec:
chart: helm # Chart 是 Helm chart 在 SourceRef 中可用的名称或路径
sourceRef:
kind: GitRepository
name: k8s-demo
namespace: default
valuesFiles:
- helm/values.yaml
- helm/my-values.yaml
interval: 30s
values:
replicaCount: 2
上面我们定义了一个 HelmRelease 对象,其中 chart 字段指定了 Helm Chart 的源,因为我们这里的 Helm Chart 是存储在 Git 代码仓库中的,所以我们通过 sourceRef 字段来指定 GitRepository 对象,interval 字段指定了从 Git 存储库提取数据的频率,values 字段指定了 Chart 的 values 值。
其中的 valuesFiles 字段是一个备选的值文件列表,用作 Chart 的 Values 值(默认情况下不包括 values.yaml),是相对于 SourceRef 的路径,Values 文件按照此列表的顺序合并,最后一个文件将覆盖第一个文件。
同样直接应用该资源对象即可:
$ kubectl apply -f k8s-demo-helm-release.yaml
helmrelease.helm.toolkit.fluxcd.io/k8s-demo created
$ kubectl get helmrelease
NAME AGE READY STATUS
k8s-demo 5m56s True Release reconciliation succeeded
我们可以看到已经成功部署了应用,如果出现了任何问题,可以通过 kubectl describe helmrelease k8s-demo
命令来查看 HelmRelease 的各种状态:
$ kubectl describe helmrelease k8s-demo
Name: k8s-demo
Namespace: default
Labels: <none>
Annotations: <none>
API Version: helm.toolkit.fluxcd.io/v2beta1
Kind: HelmRelease
Metadata:
Creation Timestamp: 2023-09-23T09:53:49Z
Finalizers:
finalizers.fluxcd.io
Generation: 2
Resource Version: 491438
UID: 7dc72409-57ee-4e4a-8950-ea5d09e43bc1
Spec:
Chart:
Spec:
Chart: helm
Interval: 30s
Reconcile Strategy: ChartVersion
Source Ref:
Kind: GitRepository
Name: k8s-demo
Namespace: default
Values Files:
helm/values.yaml
helm/my-values.yaml
Version: *
Interval: 30s
Values:
Replica Count: 2
Status:
Conditions:
Last Transition Time: 2023-09-23T09:59:44Z
Message: Release reconciliation succeeded
Reason: ReconciliationSucceeded
Status: True
Type: Ready
Last Transition Time: 2023-09-23T09:59:44Z
Message: Helm install succeeded
Reason: InstallSucceeded
Status: True
Type: Released
Helm Chart: default/default-k8s-demo
Last Applied Revision: 0.1.0+2
Last Attempted Revision: 0.1.0+2
Last Attempted Values Checksum: 1dd4966b30314fd329b48c5892b6a85412fd0236
Last Release Revision: 1
Observed Generation: 2
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal info 41s (x13 over 6m31s) helm-controller HelmChart 'default/default-k8s-demo' is not ready
Normal info 41s helm-controller Helm install has started
Normal info 36s helm-controller Helm install succeeded
事实上我们虽然是在 HelmRelease 中去为 chart 源关联的 GitRepository 对象,但是实际上 HelmRelease 会自动创建一个 HelmChart 对象,该对象可以定义一个包含 Chart 的源,以便 HelmRelease 能够引用它,如下所示:
$ kubectl get helmchart default-k8s-demo
NAME CHART VERSION SOURCE KIND SOURCE NAME AGE READY STATUS
default-k8s-demo helm * GitRepository k8s-demo 7m35s True packaged 'devops-demo' chart with version '0.1.0+2' and merged values files [helm/values.yaml helm/my-values.yaml]
$ kubectl get helmchart default-k8s-demo -o yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmChart
metadata:
name: default-k8s-demo
namespace: default
spec:
chart: helm
interval: 30s
reconcileStrategy: ChartVersion
sourceRef:
kind: GitRepository
name: k8s-demo
valuesFiles:
- helm/values.yaml
- helm/my-values.yaml
version: '*'
# ......
最后我们也可以通过 helm 命令来验证我们的应用是否已经部署成功:
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
k8s-demo default 1 2023-09-23 09:59:39.906949292 +0000 UTC deployed devops-demo-0.1.0+2 1.0
这样接下来我们只需要在 CI 流水线中去将镜像构建完成后,将镜像推送到镜像仓库,然后更新 Git 代码仓库中的 Values 文件的镜像版本即可,Flux 会自动检测到 Chart 版本的变化,然后自动更新应用。
但是这样的话,我们每次都需要在 CI 流水线去手动更新 Git 代码仓库中的 Values 文件的镜像版本,这样就会比较麻烦,和 Argo CD 类似,Flux 也提供了一个 Image Automation 控制器的功能。