使用 FluxCD 实现 Kubernetes GitOps

云计算 云原生
Flux 项目由命令行工具(FLux CLI)和一系列 Kubernetes 控制器组成。要安装 Flux,首先需要下载 Flux CLI,然后使用 CLI,可以在集群上部署 Flux 控制器并配置 GitOps 交付流水线。

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 控制器的功能。

责任编辑:姜华 来源: k8s技术圈
相关推荐

2023-04-26 12:46:43

DockerSpringKubernetes

2021-11-19 10:55:03

GitOps运维自动化

2021-07-09 06:40:59

TektonArgo CD GitOps

2022-07-26 10:00:14

KubernetesGitOps工具

2021-06-03 05:48:58

GitOps 云原生Kubernetes

2022-11-10 08:02:41

GitOpsDevOpsKubernetes

2023-09-27 08:24:49

2020-06-15 07:00:00

GitOpsKubernetesDevOps

2021-12-08 12:20:55

KubernetesGitOpsLinux

2023-04-18 08:00:35

DexKubernetes身份验证

2021-09-07 08:23:45

GitOpsCICD

2021-02-10 08:24:47

微服务CICD

2023-09-18 08:00:00

Kubernetes容器集群

2021-03-16 11:01:02

KubernetesCLI技术

2022-08-18 17:07:00

sopsGitOps

2023-10-27 07:36:36

2022-04-07 09:30:00

自动化LinodeKubernetes

2021-09-08 16:03:12

Kubernetes 安全开源

2021-03-16 07:56:32

KubernetesWebhook权限

2020-09-28 14:05:08

点赞
收藏

51CTO技术栈公众号